update to ida 7.6, add builds
This commit is contained in:
284
idasdk76/module/6502/ana.cpp
Normal file
284
idasdk76/module/6502/ana.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65.hpp"
|
||||
|
||||
static const uchar nmos[256] =
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
/* 00 */ M65_brk, M65_ora, M65_null,M65_slo, M65_nop, M65_ora, M65_asl, M65_slo, M65_php, M65_ora, M65_asl, M65_anc, M65_nop, M65_ora, M65_asl, M65_slo, /* 00 */
|
||||
/* 10 */ M65_bpl, M65_ora, M65_null,M65_slo, M65_nop, M65_ora, M65_asl, M65_slo, M65_clc, M65_ora, M65_nop, M65_slo, M65_nop, M65_ora, M65_asl, M65_slo, /* 10 */
|
||||
/* 20 */ M65_jsr, M65_and, M65_null,M65_rla, M65_bit, M65_and, M65_rol, M65_rla, M65_plp, M65_and, M65_rol, M65_anc, M65_bit, M65_and, M65_rol, M65_rla, /* 20 */
|
||||
/* 30 */ M65_bmi, M65_and, M65_null,M65_rla, M65_nop, M65_and, M65_rol, M65_rla, M65_sec, M65_and, M65_nop, M65_rla, M65_nop, M65_and, M65_rol, M65_rla, /* 30 */
|
||||
/* 40 */ M65_rti, M65_eor, M65_null,M65_sre, M65_nop, M65_eor, M65_lsr, M65_sre, M65_pha, M65_eor, M65_lsr, M65_asr, M65_jmp, M65_eor, M65_lsr, M65_sre, /* 40 */
|
||||
/* 50 */ M65_bvc, M65_eor, M65_null,M65_sre, M65_nop, M65_eor, M65_lsr, M65_sre, M65_cli, M65_eor, M65_nop, M65_sre, M65_nop, M65_eor, M65_lsr, M65_sre, /* 50 */
|
||||
/* 60 */ M65_rts, M65_adc, M65_null,M65_rra, M65_nop, M65_adc, M65_ror, M65_rra, M65_pla, M65_adc, M65_ror, M65_arr, M65_jmpi,M65_adc, M65_ror, M65_rra, /* 60 */
|
||||
/* 70 */ M65_bvs, M65_adc, M65_null,M65_rra, M65_nop, M65_adc, M65_ror, M65_rra, M65_sei, M65_adc, M65_nop, M65_rra, M65_nop, M65_adc, M65_ror, M65_rra, /* 70 */
|
||||
/* 80 */ M65_nop, M65_sta, M65_nop, M65_sax, M65_sty, M65_sta, M65_stx, M65_sax, M65_dey, M65_nop, M65_txa, M65_ane, M65_sty, M65_sta, M65_stx, M65_sax, /* 80 */
|
||||
/* 90 */ M65_bcc, M65_sta, M65_null,M65_sha, M65_sty, M65_sta, M65_stx, M65_sax, M65_tya, M65_sta, M65_txs, M65_shs, M65_shy, M65_sta, M65_shx, M65_sha, /* 90 */
|
||||
/* A0 */ M65_ldy, M65_lda, M65_ldx, M65_lax, M65_ldy, M65_lda, M65_ldx, M65_lax, M65_tay, M65_lda, M65_tax, M65_lxa, M65_ldy, M65_lda, M65_ldx, M65_lax, /* A0 */
|
||||
/* B0 */ M65_bcs, M65_lda, M65_null,M65_lax, M65_ldy, M65_lda, M65_ldx, M65_lax, M65_clv, M65_lda, M65_tsx, M65_lae, M65_ldy, M65_lda, M65_ldx, M65_lax, /* B0 */
|
||||
/* C0 */ M65_cpy, M65_cmp, M65_nop, M65_dcp, M65_cpy, M65_cmp, M65_dec, M65_dcp, M65_iny, M65_cmp, M65_dex, M65_sbx, M65_cpy, M65_cmp, M65_dec, M65_dcp, /* C0 */
|
||||
/* D0 */ M65_bne, M65_cmp, M65_null,M65_dcp, M65_nop, M65_cmp, M65_dec, M65_dcp, M65_cld, M65_cmp, M65_nop, M65_dcp, M65_nop, M65_cmp, M65_dec, M65_dcp, /* D0 */
|
||||
/* E0 */ M65_cpx, M65_sbc, M65_nop, M65_isb, M65_cpx, M65_sbc, M65_inc, M65_isb, M65_inx, M65_sbc, M65_nop, M65_sbc, M65_cpx, M65_sbc, M65_inc, M65_isb, /* E0 */
|
||||
/* F0 */ M65_beq, M65_sbc, M65_null,M65_isb, M65_nop, M65_sbc, M65_inc, M65_isb, M65_sed, M65_sbc, M65_nop, M65_isb, M65_nop, M65_sbc, M65_inc, M65_isb /* F0 */
|
||||
};
|
||||
|
||||
static const uchar cmos[256] =
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
/* 00 */ M65_brk, M65_ora, M65_null,M65_null,M65_tsb, M65_ora, M65_asl, M65_rmb0,M65_php, M65_ora, M65_asl, M65_null,M65_tsb, M65_ora, M65_asl, M65_bbr0, /* 00 */
|
||||
/* 10 */ M65_bpl, M65_ora, M65_ora, M65_null,M65_trb, M65_ora, M65_asl, M65_rmb1,M65_clc, M65_ora, M65_inc, M65_null,M65_trb, M65_ora, M65_asl, M65_bbr1, /* 10 */
|
||||
/* 20 */ M65_jsr, M65_and, M65_null,M65_null,M65_bit, M65_and, M65_rol, M65_rmb2,M65_plp, M65_and, M65_rol, M65_null,M65_bit, M65_and, M65_rol, M65_bbr2, /* 20 */
|
||||
/* 30 */ M65_bmi, M65_and, M65_and, M65_null,M65_bit, M65_and, M65_rol, M65_rmb3,M65_sec, M65_and, M65_dec, M65_null,M65_bit, M65_and, M65_rol, M65_bbr3, /* 30 */
|
||||
/* 40 */ M65_rti, M65_eor, M65_null,M65_null,M65_null,M65_eor, M65_lsr, M65_rmb4,M65_pha, M65_eor, M65_lsr, M65_null,M65_jmp, M65_eor, M65_lsr, M65_bbr4, /* 40 */
|
||||
/* 50 */ M65_bvc, M65_eor, M65_eor, M65_null,M65_null,M65_eor, M65_lsr, M65_rmb5,M65_cli, M65_eor, M65_phy, M65_null,M65_null,M65_eor, M65_lsr, M65_bbr5, /* 50 */
|
||||
/* 60 */ M65_rts, M65_adc, M65_null,M65_null,M65_stz, M65_adc, M65_ror, M65_rmb6,M65_pla, M65_adc, M65_ror, M65_null,M65_jmpi,M65_adc, M65_ror, M65_bbr6, /* 60 */
|
||||
/* 70 */ M65_bvs, M65_adc, M65_adc, M65_null,M65_stz, M65_adc, M65_ror, M65_rmb7,M65_sei, M65_adc, M65_ply, M65_null,M65_jmpi,M65_adc, M65_ror, M65_bbr7, /* 70 */
|
||||
/* 80 */ M65_bra, M65_sta, M65_null,M65_null,M65_sty, M65_sta, M65_stx, M65_smb0,M65_dey, M65_bit, M65_txa, M65_null,M65_sty, M65_sta, M65_stx, M65_bbs0, /* 80 */
|
||||
/* 90 */ M65_bcc, M65_sta, M65_sta, M65_null,M65_sty, M65_sta, M65_stx, M65_smb1,M65_tya, M65_sta, M65_txs, M65_null,M65_stz, M65_sta, M65_stz, M65_bbs1, /* 90 */
|
||||
/* A0 */ M65_ldy, M65_lda, M65_ldx, M65_null,M65_ldy, M65_lda, M65_ldx, M65_smb2,M65_tay, M65_lda, M65_tax, M65_null,M65_ldy, M65_lda, M65_ldx, M65_bbs2, /* A0 */
|
||||
/* B0 */ M65_bcs, M65_lda, M65_lda, M65_null,M65_ldy, M65_lda, M65_ldx, M65_smb3,M65_clv, M65_lda, M65_tsx, M65_null,M65_ldy, M65_lda, M65_ldx, M65_bbs3, /* B0 */
|
||||
/* C0 */ M65_cpy, M65_cmp, M65_null,M65_null,M65_cpy, M65_cmp, M65_dec, M65_smb4,M65_iny, M65_cmp, M65_dex, M65_wai,M65_cpy, M65_cmp, M65_dec, M65_bbs4, /* C0 */
|
||||
/* D0 */ M65_bne, M65_cmp, M65_cmp, M65_null,M65_null,M65_cmp, M65_dec, M65_smb5,M65_cld, M65_cmp, M65_phx, M65_stp,M65_null,M65_cmp, M65_dec, M65_bbs5, /* D0 */
|
||||
/* E0 */ M65_cpx, M65_sbc, M65_null,M65_null,M65_cpx, M65_sbc, M65_inc, M65_smb6,M65_inx, M65_sbc, M65_nop, M65_null,M65_cpx, M65_sbc, M65_inc, M65_bbs6, /* E0 */
|
||||
/* F0 */ M65_beq, M65_sbc, M65_sbc, M65_null,M65_null,M65_sbc, M65_inc, M65_smb7,M65_sed, M65_sbc, M65_plx, M65_null,M65_null,M65_sbc, M65_inc, M65_bbs7 /* F0 */
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int m6502_t::ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
uchar code = insn.get_next_byte();
|
||||
insn.itype = (is_cmos ? cmos : nmos)[code];
|
||||
if ( insn.itype == M65_null )
|
||||
return 0;
|
||||
|
||||
switch ( code & 0x1F )
|
||||
{
|
||||
// +08 PHP PLP PHA PLA DEY TAY INY INX Implied
|
||||
// +18 CLC SEC CLI SEI TYA CLV CLD SED Implied
|
||||
// +1a NOP* NOP* NOP* NOP* TXS TSX NOP* NOP* Implied
|
||||
// +1a inc dec phy ply txs tsx phx ply
|
||||
case 0x1A:
|
||||
case 0x08:
|
||||
case 0x18:
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65_inc:
|
||||
case M65_dec:
|
||||
insn.Op1.type = o_reg;
|
||||
insn.Op1.reg = rA;
|
||||
}
|
||||
break;
|
||||
// +0a ASL ROL LSR ROR TXA TAX DEX NOP Accu/impl
|
||||
case 0x0A:
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65_asl:
|
||||
case M65_rol:
|
||||
case M65_lsr:
|
||||
case M65_ror:
|
||||
insn.Op1.type = o_reg;
|
||||
insn.Op1.reg = rA;
|
||||
}
|
||||
break;
|
||||
// +00 BRK JSR RTI RTS NOP*/bra LDY CPY CPX Impl/immed
|
||||
// +02 t t t t NOP*t LDX NOP*t NOP*t ? /immed
|
||||
// +09 ORA AND EOR ADC NOP* LDA CMP SBC Immediate
|
||||
// +0b ANC** ANC** ASR** ARR** ANE** LXA** SBX** SBC* Immediate
|
||||
case 0x00:
|
||||
case 0x02:
|
||||
case 0x09:
|
||||
case 0x0B:
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65_jsr:
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
break;
|
||||
case M65_brk:
|
||||
case M65_rti:
|
||||
case M65_rts:
|
||||
case M65_wai:
|
||||
|
||||
// no operands
|
||||
break;
|
||||
case M65_bra:
|
||||
goto M65_RELATIVE;
|
||||
default:
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// +0c NOP*/tsb BIT JMP JMP () STY LDY CPY CPX Absolute
|
||||
// +0d ORA AND EOR ADC STA LDA CMP SBC Absolute
|
||||
// +0e ASL ROL LSR ROR STX LDX DEC INC Absolute
|
||||
// +0f SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* Absolute
|
||||
// +0f bbr0 bbr2 bbr4 bbr6 bbs0 bbs2 bbs4 bbs6 Zero page relative
|
||||
case 0x0F:
|
||||
if ( is_cmos )
|
||||
goto ZP_RELATIVE;
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
case 0x0E:
|
||||
M65_ABSOLUTE:
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65_jmp:
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.type = o_near;
|
||||
break;
|
||||
case M65_jmpi:
|
||||
insn.Op1.dtype = dt_word;
|
||||
insn.indirect = 1;
|
||||
/* no break */
|
||||
default:
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
}
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
break;
|
||||
// +1c NOP*/trb NOP*/bit NOP* NOP*/jmp SHY**/stz LDY NOP* NOP* Absolute, x
|
||||
// +1d ORA AND EOR ADC STA LDA CMP SBC Absolute, x
|
||||
// +1e ASL ROL LSR ROR SHX**y) LDX y) DEC INC Absolute, x
|
||||
// +1f SLO* RLA* SRE* RRA* SHA**y) LAX* y) DCP ISB Absolute, x
|
||||
// +0f bbr1 bbr3 bbr5 bbr7 bbs1 bbs3 bbs5 bbs7 Zero page relative
|
||||
case 0x1F:
|
||||
if ( is_cmos )
|
||||
{
|
||||
ZP_RELATIVE:
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op2.dtype = dt_code;
|
||||
insn.Op2.type = o_near;
|
||||
char x = insn.get_next_byte();
|
||||
insn.Op2.addr = insn.ip + insn.size + x;
|
||||
break;
|
||||
}
|
||||
/* fall thru */
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rX;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65_stz:
|
||||
if ( code == 0x9E )
|
||||
break;
|
||||
// no break
|
||||
case M65_trb:
|
||||
goto M65_ABSOLUTE;
|
||||
case M65_shx:
|
||||
case M65_sha:
|
||||
case M65_ldx:
|
||||
case M65_lax:
|
||||
insn.Op1.phrase = rY;
|
||||
break;
|
||||
case M65_jmpi:
|
||||
insn.Op1.phrase = riX;
|
||||
break;
|
||||
}
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
break;
|
||||
// +19 ORA AND EOR ADC STA LDA CMP SBC Absolute, y
|
||||
// +1b SLO* RLA* SRE* RRA* SHS** LAS** DCP* ISB* Absolute, y
|
||||
case 0x19:
|
||||
case 0x1B:
|
||||
if ( insn.itype == M65_stp )
|
||||
// no operands
|
||||
break;
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rY;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
break;
|
||||
// +10 BPL BMI BVC BVS BCC BCS BNE BEQ Relative
|
||||
case 0x10:
|
||||
M65_RELATIVE:
|
||||
insn.Op1.dtype = dt_code;
|
||||
insn.Op1.type = o_near;
|
||||
{
|
||||
char x = insn.get_next_byte();
|
||||
insn.Op1.addr = insn.ip + insn.size + x;
|
||||
}
|
||||
break;
|
||||
// +01 ORA AND EOR ADC STA LDA CMP SBC (indir, x)
|
||||
// +03 SLO* RLA* SRE* RRA* SAX* LAX* y) DCP* ISB* (indir, x)
|
||||
case 0x01:
|
||||
case 0x03:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = uint16((insn.itype == M65_lax) ? riY : riX);
|
||||
insn.Op1.addr = insn.get_next_byte(); // what about LAX?
|
||||
break;
|
||||
// +11 ORA AND EOR ADC STA LDA CMP SBC (indir), y
|
||||
// +13 SLO* RLA* SRE* RRA* SHA** LAX* DCP* ISB* (indir), y
|
||||
case 0x11:
|
||||
case 0x13:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = riY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
break;
|
||||
// +04 NOP*/tsb BIT NOP* NOP*/stz STY LDY CPY CPX Zeropage
|
||||
// +05 ORA AND EOR ADC STA LDA CMP SBC Zeropage
|
||||
// +06 ASL ROL LSR ROR STX LDX DEC INC Zeropage
|
||||
// +07 SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* Zeropage
|
||||
// +07 rmb0 rmb2 rmb4 rmb6 smb0 smb2 smb4 smb6 Zeropage
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
ZEROPAGE:
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
break;
|
||||
// +14 NOP*/trb NOP*/bit NOP* NOP*/stz STY LDY NOP* NOP* Zeropage, x
|
||||
// +15 ORA AND EOR ADC STA LDA CMP SBC Zeropage, x
|
||||
// +16 ASL ROL LSR ROR STX y) LDX y) DEC INC Zeropage, x
|
||||
// +17 SLO* RLA* SRE* RRA* SAX* y) LAX* y) DCP ISB Zeropage, x
|
||||
// +17 rmb1 rmb3 rmb5 rmb7 smb1 smb3 smb5 smb7 Zeropage
|
||||
case 0x17:
|
||||
if ( is_cmos )
|
||||
goto ZEROPAGE;
|
||||
/* fall thru */
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = zX;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65_trb:
|
||||
goto ZEROPAGE;
|
||||
case M65_stx:
|
||||
case M65_sax:
|
||||
case M65_ldx:
|
||||
case M65_lax:
|
||||
insn.Op1.phrase = zY;
|
||||
break;
|
||||
}
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
break;
|
||||
// +12 ora and eor adc sta lda cmp sbc Zeropage, indirect
|
||||
case 0x12:
|
||||
insn.indirect = 1;
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
break;
|
||||
default:
|
||||
error("ana: bad code %x",code);
|
||||
}
|
||||
if ( insn.itype == M65_nop )
|
||||
insn.Op1.type = o_void;
|
||||
return insn.size;
|
||||
}
|
||||
94
idasdk76/module/6502/emu.cpp
Normal file
94
idasdk76/module/6502/emu.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void m6502_t::handle_operand(
|
||||
const op_t &x,
|
||||
bool isload,
|
||||
const insn_t &insn,
|
||||
bool *flow) const
|
||||
{
|
||||
ea_t ea;
|
||||
dref_t xreftype;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
break;
|
||||
case o_imm:
|
||||
if ( !isload )
|
||||
goto badTouch;
|
||||
xreftype = dr_O;
|
||||
goto MAKE_IMMD;
|
||||
case o_displ:
|
||||
xreftype = isload ? dr_R : dr_W;
|
||||
MAKE_IMMD:
|
||||
set_immd(insn.ea);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, xreftype, m65_opflags(x));
|
||||
break;
|
||||
case o_mem:
|
||||
ea = map_data_ea(insn, x);
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
// add xref to the target address
|
||||
if ( insn.itype == M65_jmpi && x.dtype == dt_word && is_loaded(ea) )
|
||||
{
|
||||
ea_t callee = get_word(ea);
|
||||
if ( callee > 32 && is_mapped(callee) ) // is good address?
|
||||
{
|
||||
add_cref(insn.ea, callee, fl_JN);
|
||||
if ( !is_defarg0(get_flags(ea)) )
|
||||
op_plain_offset(ea, 0, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case o_near:
|
||||
{
|
||||
ea = map_code_ea(insn, x);
|
||||
ea_t segbase = (ea - x.addr) >> 4;
|
||||
ea_t thisseg = insn.cs;
|
||||
bool iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
insn.add_cref(
|
||||
ea,
|
||||
x.offb,
|
||||
iscall ? (segbase == thisseg ? fl_CN : fl_CF)
|
||||
: (segbase == thisseg ? fl_JN : fl_JF));
|
||||
if ( iscall && *flow )
|
||||
*flow = func_does_return(ea);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
badTouch:
|
||||
const char *mnem = insn.get_canon_mnem(ph);
|
||||
warning("%a: %s,%d: bad optype %d", insn.ea, mnem, x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int m6502_t::emu(const insn_t &insn) const
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
bool flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn.Op1, 1, insn, &flow);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn.Op2, 1, insn, &flow);
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn.Op1, 0, insn, &flow);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn.Op2, 0, insn, &flow);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
140
idasdk76/module/6502/ins.cpp
Normal file
140
idasdk76/module/6502/ins.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 },
|
||||
{ "ADC", CF_USE1 }, // A <- (A) + M + C
|
||||
{ "ANC", CF_USE1 }, // A <- A /\ M, C <- ~A7
|
||||
{ "AND", CF_USE1 }, // A <- (A) /\ M
|
||||
{ "ANE", CF_USE1 }, // M <-[(A)\/$EE] /\ (X)/\(M)
|
||||
{ "ARR", CF_USE1 }, // A <- [(A /\ M) >> 1]
|
||||
{ "ASL", CF_CHG1 }, // C <- A7, A <- (A) << 1
|
||||
{ "ASR", CF_USE1 }, // A <- [(A /\ M) >> 1]
|
||||
{ "BCC", CF_USE1 }, // if C=0, PC = PC + offset
|
||||
{ "BCS", CF_USE1 }, // if C=1, PC = PC + offset
|
||||
{ "BEQ", CF_USE1 }, // if Z=1, PC = PC + offset
|
||||
{ "BIT", CF_USE1 }, // Z <- ~(A /\ M) N<-M7 V<-M6
|
||||
{ "BMI", CF_USE1 }, // if N=1, PC = PC + offset
|
||||
{ "BNE", CF_USE1 }, // if Z=0, PC = PC + offset
|
||||
{ "BPL", CF_USE1 }, // if N=0, PC = PC + offset
|
||||
{ "BRK", CF_STOP }, // Stack <- PC, PC <- ($fffe)
|
||||
{ "BVC", CF_USE1 }, // if V=0, PC = PC + offset
|
||||
{ "BVS", CF_USE1 }, // if V=1, PC = PC + offset
|
||||
{ "CLC", 0 }, // C <- 0
|
||||
{ "CLD", 0 }, // D <- 0
|
||||
{ "CLI", 0 }, // I <- 0
|
||||
{ "CLV", 0 }, // V <- 0
|
||||
{ "CMP", CF_USE1 }, // (A - M) -> NZC
|
||||
{ "CPX", CF_USE1 }, // (X - M) -> NZC
|
||||
{ "CPY", CF_USE1 }, // (Y - M) -> NZC
|
||||
{ "DCP", CF_USE1|CF_CHG1 }, // M <- (M)-1, (A-M) -> NZC
|
||||
{ "DEC", CF_USE1|CF_CHG1 }, // M <- (M) - 1
|
||||
{ "DEX", 0 }, // X <- (X) - 1
|
||||
{ "DEY", 0 }, // Y <- (Y) - 1
|
||||
{ "EOR", CF_USE1 }, // A <- (A) \-/ M
|
||||
{ "INC", CF_USE1|CF_CHG1 }, // M <- (M) + 1
|
||||
{ "INX", 0 }, // X <- (X) +1
|
||||
{ "INY", 0 }, // Y <- (Y) + 1
|
||||
{ "ISB", CF_USE1|CF_CHG1 }, // M <- (M) - 1,A <- (A)-M-~C
|
||||
{ "JMP", CF_USE1|CF_STOP }, // PC <- Address
|
||||
{ "JMP", CF_USE1|CF_JUMP|CF_STOP }, // PC <- (Address)
|
||||
{ "JSR", CF_USE1|CF_CALL }, // Stack <- PC, PC <- Address
|
||||
{ "LAE", CF_USE1 }, // X,S,A <- (S /\ M)
|
||||
{ "LAX", CF_USE1 }, // A <- M, X <- M
|
||||
{ "LDA", CF_USE1 }, // A <- M
|
||||
{ "LDX", CF_USE1 }, // X <- M
|
||||
{ "LDY", CF_USE1 }, // Y <- M
|
||||
{ "LSR", CF_CHG1 }, // C <- A0, A <- (A) >> 1
|
||||
{ "LXA", CF_USE1 }, // X04 <- (X04) /\ M04, A04 <- (A04) /\ M04
|
||||
{ "NOP", 0 }, // [no operation]
|
||||
{ "ORA", CF_USE1 }, // A <- (A) V M
|
||||
{ "PHA", 0 }, // Stack <- (A)
|
||||
{ "PHP", 0 }, // Stack <- (P)
|
||||
{ "PLA", 0 }, // A <- (Stack)
|
||||
{ "PLP", 0 }, // A <- (Stack)
|
||||
{ "RLA", CF_USE1|CF_CHG1 }, // M <- (M << 1) /\ (A)
|
||||
{ "ROL", CF_CHG1 }, // C <- A7 & A <- A << 1 + C
|
||||
{ "ROR", CF_CHG1 }, // C<-A0 & A<- (A7=C + A>>1)
|
||||
{ "RRA", CF_USE1|CF_CHG1 }, // M <- (M >> 1) + (A) + C
|
||||
{ "RTI", CF_STOP }, // P <- (Stack), PC <-(Stack)
|
||||
{ "RTS", CF_STOP }, // PC <- (Stack)
|
||||
{ "SAX", CF_CHG1 }, // M <- (A) /\ (X)
|
||||
{ "SBC", CF_USE1 }, // A <- (A) - M - ~C
|
||||
{ "SBX", CF_USE1 }, // X <- (X)/\(A) - M
|
||||
{ "SEC", 0 }, // C <- 1
|
||||
{ "SED", 0 }, // D <- 1
|
||||
{ "SEI", 0 }, // I <- 1
|
||||
{ "SHA", CF_CHG1 }, // M <- (A) /\ (X) /\ (PCH+1)
|
||||
{ "SHS", CF_CHG1 }, // X <- (A) /\ (X), S <- (X), M <- (X) /\ (PCH+1)
|
||||
{ "SHX", CF_CHG1 }, // M <- (X) /\ (PCH+1)
|
||||
{ "SHY", CF_CHG1 }, // M <- (Y) /\ (PCH+1)
|
||||
{ "SLO", CF_USE1|CF_CHG1 }, // M <- (M >> 1) + A + C
|
||||
{ "SRE", CF_USE1|CF_CHG1 }, // M <- (M >> 1) \-/ A
|
||||
{ "STA", CF_CHG1 }, // M <- (A)
|
||||
{ "STX", CF_CHG1 }, // M <- (X)
|
||||
{ "STY", CF_CHG1 }, // M <- (Y)
|
||||
{ "TAX", 0 }, // X <- (A)
|
||||
{ "TAY", 0 }, // Y <- (A)
|
||||
{ "TSX", 0 }, // X <- (S)
|
||||
{ "TXA", 0 }, // A <- (X)
|
||||
{ "TXS", 0 }, // S <- (X)
|
||||
{ "TYA", 0 }, // A <- (Y)
|
||||
|
||||
|
||||
// CMOS instructions
|
||||
|
||||
{ "BBR0", CF_USE1|CF_USE2 }, // Branch if bit 0 reset
|
||||
{ "BBR1", CF_USE1|CF_USE2 }, // Branch if bit 1 reset
|
||||
{ "BBR2", CF_USE1|CF_USE2 }, // Branch if bit 2 reset
|
||||
{ "BBR3", CF_USE1|CF_USE2 }, // Branch if bit 3 reset
|
||||
{ "BBR4", CF_USE1|CF_USE2 }, // Branch if bit 4 reset
|
||||
{ "BBR5", CF_USE1|CF_USE2 }, // Branch if bit 5 reset
|
||||
{ "BBR6", CF_USE1|CF_USE2 }, // Branch if bit 6 reset
|
||||
{ "BBR7", CF_USE1|CF_USE2 }, // Branch if bit 7 reset
|
||||
{ "BBS0", CF_USE1|CF_USE2 }, // Branch if bit 0 set
|
||||
{ "BBS1", CF_USE1|CF_USE2 }, // Branch if bit 1 set
|
||||
{ "BBS2", CF_USE1|CF_USE2 }, // Branch if bit 2 set
|
||||
{ "BBS3", CF_USE1|CF_USE2 }, // Branch if bit 3 set
|
||||
{ "BBS4", CF_USE1|CF_USE2 }, // Branch if bit 4 set
|
||||
{ "BBS5", CF_USE1|CF_USE2 }, // Branch if bit 5 set
|
||||
{ "BBS6", CF_USE1|CF_USE2 }, // Branch if bit 6 set
|
||||
{ "BBS7", CF_USE1|CF_USE2 }, // Branch if bit 7 set
|
||||
{ "RMB0", CF_CHG1 }, // Reset memory bit 0
|
||||
{ "RMB1", CF_CHG1 }, // Reset memory bit 1
|
||||
{ "RMB2", CF_CHG1 }, // Reset memory bit 2
|
||||
{ "RMB3", CF_CHG1 }, // Reset memory bit 3
|
||||
{ "RMB4", CF_CHG1 }, // Reset memory bit 4
|
||||
{ "RMB5", CF_CHG1 }, // Reset memory bit 5
|
||||
{ "RMB6", CF_CHG1 }, // Reset memory bit 6
|
||||
{ "RMB7", CF_CHG1 }, // Reset memory bit 7
|
||||
{ "SMB0", CF_CHG1 }, // Set memory bit 0
|
||||
{ "SMB1", CF_CHG1 }, // Set memory bit 1
|
||||
{ "SMB2", CF_CHG1 }, // Set memory bit 2
|
||||
{ "SMB3", CF_CHG1 }, // Set memory bit 3
|
||||
{ "SMB4", CF_CHG1 }, // Set memory bit 4
|
||||
{ "SMB5", CF_CHG1 }, // Set memory bit 5
|
||||
{ "SMB6", CF_CHG1 }, // Set memory bit 6
|
||||
{ "SMB7", CF_CHG1 }, // Set memory bit 7
|
||||
{ "STZ", CF_CHG1 }, // Store zero
|
||||
{ "TSB", CF_USE1|CF_CHG1 }, // Test and set bits
|
||||
{ "TRB", CF_USE1|CF_CHG1 }, // Test and reset bits
|
||||
{ "PHY", 0 }, // Push Y register
|
||||
{ "PLY", 0 }, // Pull Y register
|
||||
{ "PHX", 0 }, // Push X register
|
||||
{ "PLX", 0 }, // Pull X register
|
||||
{ "BRA", CF_USE1|CF_STOP }, // Branch always
|
||||
{ "WAI", 0 }, // Wait for interrupt
|
||||
{ "STP", CF_STOP }, // Stop processor
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == M65_last);
|
||||
144
idasdk76/module/6502/ins.hpp
Normal file
144
idasdk76/module/6502/ins.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
M65_null = 0, // Unknown Operation
|
||||
|
||||
// NMOS instructions
|
||||
|
||||
M65_adc, // A <- (A) + M + C
|
||||
M65_anc, // A <- A /\ M, C <- ~A7
|
||||
M65_and, // A <- (A) /\ M
|
||||
M65_ane, // M <-[(A)\/$EE] /\ (X)/\(M)
|
||||
M65_arr, // A <- [(A /\ M) >> 1]
|
||||
M65_asl, // C <- A7, A <- (A) << 1
|
||||
M65_asr, // A <- [(A /\ M) >> 1]
|
||||
M65_bcc, // if C=0, PC = PC + offset
|
||||
M65_bcs, // if C=1, PC = PC + offset
|
||||
M65_beq, // if Z=1, PC = PC + offset
|
||||
M65_bit, // Z <- ~(A /\ M) N<-M7 V<-M6
|
||||
M65_bmi, // if N=1, PC = PC + offset
|
||||
M65_bne, // if Z=0, PC = PC + offset
|
||||
M65_bpl, // if N=0, PC = PC + offset
|
||||
M65_brk, // Stack <- PC, PC <- ($fffe)
|
||||
M65_bvc, // if V=0, PC = PC + offset
|
||||
M65_bvs, // if V=1, PC = PC + offset
|
||||
M65_clc, // C <- 0
|
||||
M65_cld, // D <- 0
|
||||
M65_cli, // I <- 0
|
||||
M65_clv, // V <- 0
|
||||
M65_cmp, // (A - M) -> NZC
|
||||
M65_cpx, // (X - M) -> NZC
|
||||
M65_cpy, // (Y - M) -> NZC
|
||||
M65_dcp, // M <- (M)-1, (A-M) -> NZC
|
||||
M65_dec, // M <- (M) - 1
|
||||
M65_dex, // X <- (X) - 1
|
||||
M65_dey, // Y <- (Y) - 1
|
||||
M65_eor, // A <- (A) \-/ M
|
||||
M65_inc, // M <- (M) + 1
|
||||
M65_inx, // X <- (X) +1
|
||||
M65_iny, // Y <- (Y) + 1
|
||||
M65_isb, // M <- (M) - 1,A <- (A)-M-~C
|
||||
M65_jmp, // PC <- Address
|
||||
M65_jmpi, // (PC <- Address)
|
||||
M65_jsr, // Stack <- PC, PC <- Address
|
||||
M65_lae, // X,S,A <- (S /\ M)
|
||||
M65_lax, // A <- M, X <- M
|
||||
M65_lda, // A <- M
|
||||
M65_ldx, // X <- M
|
||||
M65_ldy, // Y <- M
|
||||
M65_lsr, // C <- A0, A <- (A) >> 1
|
||||
M65_lxa, // X04 <- (X04) /\ M04, A04 <- (A04) /\ M04
|
||||
M65_nop, // [no operation]
|
||||
M65_ora, // A <- (A) V M
|
||||
M65_pha, // Stack <- (A)
|
||||
M65_php, // Stack <- (P)
|
||||
M65_pla, // A <- (Stack)
|
||||
M65_plp, // A <- (Stack)
|
||||
M65_rla, // M <- (M << 1) /\ (A)
|
||||
M65_rol, // C <- A7 & A <- A << 1 + C
|
||||
M65_ror, // C<-A0 & A<- (A7=C + A>>1)
|
||||
M65_rra, // M <- (M >> 1) + (A) + C
|
||||
M65_rti, // P <- (Stack), PC <-(Stack)
|
||||
M65_rts, // PC <- (Stack)
|
||||
M65_sax, // M <- (A) /\ (X)
|
||||
M65_sbc, // A <- (A) - M - ~C
|
||||
M65_sbx, // X <- (X)/\(A) - M
|
||||
M65_sec, // C <- 1
|
||||
M65_sed, // D <- 1
|
||||
M65_sei, // I <- 1
|
||||
M65_sha, // M <- (A) /\ (X) /\ (PCH+1)
|
||||
M65_shs, // X <- (A) /\ (X), S <- (X), M <- (X) /\ (PCH+1)
|
||||
M65_shx, // M <- (X) /\ (PCH+1)
|
||||
M65_shy, // M <- (Y) /\ (PCH+1)
|
||||
M65_slo, // M <- (M >> 1) + A + C
|
||||
M65_sre, // M <- (M >> 1) \-/ A
|
||||
M65_sta, // M <- (A)
|
||||
M65_stx, // M <- (X)
|
||||
M65_sty, // M <- (Y)
|
||||
M65_tax, // X <- (A)
|
||||
M65_tay, // Y <- (A)
|
||||
M65_tsx, // X <- (S)
|
||||
M65_txa, // A <- (X)
|
||||
M65_txs, // S <- (X)
|
||||
M65_tya, // A <- (Y)
|
||||
|
||||
// CMOS instructions
|
||||
|
||||
M65_bbr0, // Branch if bit 0 reset
|
||||
M65_bbr1, // Branch if bit 1 reset
|
||||
M65_bbr2, // Branch if bit 2 reset
|
||||
M65_bbr3, // Branch if bit 3 reset
|
||||
M65_bbr4, // Branch if bit 4 reset
|
||||
M65_bbr5, // Branch if bit 5 reset
|
||||
M65_bbr6, // Branch if bit 6 reset
|
||||
M65_bbr7, // Branch if bit 7 reset
|
||||
M65_bbs0, // Branch if bit 0 set
|
||||
M65_bbs1, // Branch if bit 1 set
|
||||
M65_bbs2, // Branch if bit 2 set
|
||||
M65_bbs3, // Branch if bit 3 set
|
||||
M65_bbs4, // Branch if bit 4 set
|
||||
M65_bbs5, // Branch if bit 5 set
|
||||
M65_bbs6, // Branch if bit 6 set
|
||||
M65_bbs7, // Branch if bit 7 set
|
||||
M65_rmb0, // Reset memory bit 0
|
||||
M65_rmb1, // Reset memory bit 1
|
||||
M65_rmb2, // Reset memory bit 2
|
||||
M65_rmb3, // Reset memory bit 3
|
||||
M65_rmb4, // Reset memory bit 4
|
||||
M65_rmb5, // Reset memory bit 5
|
||||
M65_rmb6, // Reset memory bit 6
|
||||
M65_rmb7, // Reset memory bit 7
|
||||
M65_smb0, // Set memory bit 0
|
||||
M65_smb1, // Set memory bit 1
|
||||
M65_smb2, // Set memory bit 2
|
||||
M65_smb3, // Set memory bit 3
|
||||
M65_smb4, // Set memory bit 4
|
||||
M65_smb5, // Set memory bit 5
|
||||
M65_smb6, // Set memory bit 6
|
||||
M65_smb7, // Set memory bit 7
|
||||
M65_stz, // Store zero
|
||||
M65_tsb, // Test and set bits
|
||||
M65_trb, // Test and reset bits
|
||||
M65_phy, // Push Y register
|
||||
M65_ply, // Pull Y register
|
||||
M65_phx, // Push X register
|
||||
M65_plx, // Pull X register
|
||||
M65_bra, // Branch always
|
||||
M65_wai, // Wait for interrupt
|
||||
M65_stp, // Stop processor
|
||||
|
||||
M65_last,
|
||||
};
|
||||
|
||||
#endif
|
||||
51
idasdk76/module/6502/m65.hpp
Normal file
51
idasdk76/module/6502/m65.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _M65_HPP
|
||||
#define _M65_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
struct m6502_t : public procmod_t
|
||||
{
|
||||
bool is_cmos = false; // is CMOS (otherwise, NMOS)
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
int ana(insn_t *_insn);
|
||||
int emu(const insn_t &insn) const;
|
||||
void handle_operand(const op_t &x, bool isload, const insn_t &insn, bool *flow) const;
|
||||
|
||||
void header(outctx_t &ctx) const;
|
||||
void segstart(outctx_t &ctx, segment_t *seg) const;
|
||||
void footer(outctx_t &ctx) const;
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
// Is indirect memory reference?
|
||||
|
||||
#define indirect auxpref
|
||||
|
||||
#define UAS_SECT 0x0002 // Segments are named .SECTION
|
||||
#define UAS_NOSEG 0x0004 // No 'segment' directives
|
||||
#define UAS_SELSG 0x0010 // Segment should be selected by its name
|
||||
#define UAS_CDSEG 0x0080 // Only DSEG, CSEG, XSEG
|
||||
#define UAS_NOENS 0x0200 // don't specify start addr in the .end directive
|
||||
//------------------------------------------------------------------------
|
||||
enum M65_registers { rA, rX, rY, rVcs, rVds, riX, riY, zX, zY };
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi ana(insn_t *insn);
|
||||
int idaapi emu(const insn_t &insn);
|
||||
void idaapi assumes(outctx_t &ctx, ea_t ea);
|
||||
int m65_opflags(const op_t &x);
|
||||
|
||||
|
||||
#endif
|
||||
50
idasdk76/module/6502/makefile
Normal file
50
idasdk76/module/6502/makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
PROC=m65
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ana.cpp ins.hpp \
|
||||
m65.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 emu.cpp ins.hpp \
|
||||
m65.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ins.cpp ins.hpp \
|
||||
m65.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ins.hpp m65.hpp \
|
||||
out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ins.hpp m65.hpp \
|
||||
reg.cpp
|
||||
190
idasdk76/module/6502/out.cpp
Normal file
190
idasdk76/module/6502/out.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65.hpp"
|
||||
|
||||
int m65_opflags(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_displ:
|
||||
return OOF_ADDR|OOFS_NOSIGN|OOFW_16;
|
||||
case o_near:
|
||||
case o_mem:
|
||||
return OOF_ADDR|OOF_NUMBER|OOFS_NOSIGN|OOFW_16|OOF_ZSTROFF;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// simple wrapper class for syntactic sugar of member functions
|
||||
// this class may have only simple member functions.
|
||||
// virtual functions and data fields are forbidden, otherwise the class
|
||||
// layout may change
|
||||
class out_6502_t : public outctx_t
|
||||
{
|
||||
out_6502_t(void) = delete; // not used
|
||||
public:
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_6502_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_6502_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_6502_t::out_operand(const op_t &x)
|
||||
{
|
||||
int outf = m65_opflags(x);
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
out_register("A");
|
||||
break;
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, outf);
|
||||
break;
|
||||
case o_near:
|
||||
case o_mem:
|
||||
if ( insn.indirect )
|
||||
out_symbol('(');
|
||||
{
|
||||
ea_t v = map_ea(insn, x, x.type == o_near);
|
||||
if ( !out_name_expr(x, v, x.addr) )
|
||||
out_value(x, outf);
|
||||
}
|
||||
if ( insn.indirect )
|
||||
out_symbol(')');
|
||||
break;
|
||||
case o_displ:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case rX:
|
||||
case rY:
|
||||
case zX:
|
||||
case zY:
|
||||
out_value(x, outf);
|
||||
out_symbol(',');
|
||||
out_register((x.phrase == zX || x.phrase == rX) ? "X" : "Y");
|
||||
break;
|
||||
case riX:
|
||||
out_symbol('(');
|
||||
out_value(x, outf);
|
||||
out_symbol(',');
|
||||
out_register("X");
|
||||
out_symbol(')');
|
||||
break;
|
||||
case riY:
|
||||
out_symbol('(');
|
||||
out_value(x, outf);
|
||||
out_symbol(')');
|
||||
out_symbol(',');
|
||||
out_register("Y");
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case o_void:
|
||||
return 0;
|
||||
default:
|
||||
err:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_6502_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m6502_t::header(outctx_t &ctx) const
|
||||
{
|
||||
ctx.gen_cmt_line("%s Processor: %s", ash.cmnt, inf_get_procname().c_str());
|
||||
ctx.gen_cmt_line("%s Target assembler: %s", ash.cmnt, ash.name);
|
||||
if ( ash.header != NULL )
|
||||
for ( const char *const *ptr = ash.header; *ptr != NULL; ptr++ )
|
||||
ctx.flush_buf(*ptr, 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{1764} ctx could be const
|
||||
//lint -e{818} seg could be const
|
||||
void m6502_t::segstart(outctx_t &ctx, segment_t *seg) const
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, seg);
|
||||
if ( ash.uflag & UAS_SECT )
|
||||
{
|
||||
ctx.gen_printf(0, COLSTR("%s: .section", SCOLOR_ASMDIR), name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s.segment %s", SCOLOR_ASMDIR),
|
||||
(ash.uflag & UAS_NOSEG) ? ash.cmnt : "",
|
||||
name.c_str());
|
||||
if ( ash.uflag & UAS_SELSG )
|
||||
ctx.flush_buf(name.c_str(), DEFAULT_INDENT);
|
||||
if ( ash.uflag & UAS_CDSEG )
|
||||
ctx.flush_buf(COLSTR("CSEG", SCOLOR_ASMDIR), DEFAULT_INDENT); // XSEG - eXternal memory
|
||||
}
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
ea_t org = ea - get_segm_base(seg);
|
||||
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 m6502_t::footer(outctx_t &ctx) const
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
char *ptr = buf;
|
||||
char *end = buf + sizeof(buf);
|
||||
APPEND(ptr, end, ash.end);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
if ( ash.uflag & UAS_NOENS )
|
||||
APPEND(ptr, end, ash.cmnt);
|
||||
APPCHAR(ptr, end, ' ');
|
||||
APPEND(ptr, end, name.begin());
|
||||
}
|
||||
ctx.flush_buf(buf, DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
319
idasdk76/module/6502/reg.cpp
Normal file
319
idasdk76/module/6502/reg.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const regnames[] =
|
||||
{
|
||||
"A", "X", "Y", "cs", "ds"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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 m6502_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi m6502_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_ending_undo:
|
||||
is_cmos = static_cast<bool>(ph.get_proc_index());
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
is_cmos = va_arg(va, int) != 0;
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
{ // default DS is equal to CS
|
||||
segment_t *sptr = va_arg(va, segment_t *);
|
||||
sptr->defsr[rVds-ph.reg_first_sreg] = sptr->sel;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
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 *);
|
||||
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;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// PseudoSam
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const ps_headers[] =
|
||||
{
|
||||
".code",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t pseudosam =
|
||||
{
|
||||
AS_COLON | ASH_HEXF1 | AS_N2CHR | AS_NOXRF,
|
||||
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
|
||||
NULL, // 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
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// SVENSON ELECTRONICS 6502/65C02 ASSEMBLER - V.1.0 - MAY, 1988
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t svasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF4,
|
||||
UAS_NOSEG,
|
||||
"SVENSON ELECTRONICS 6502/65C02 ASSEMBLER - V.1.0 - MAY, 1988",
|
||||
0,
|
||||
NULL, // headers
|
||||
"* = ",
|
||||
".END",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\'", // special symbols in char and string constants
|
||||
|
||||
".BYTE", // ascii string directive
|
||||
".BYTE", // byte directive
|
||||
".WORD", // word directive
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// TASM assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t tasm =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_NOENS | UAS_NOSEG,
|
||||
"Table Driven Assembler (TASM) by Speech Technology Inc.",
|
||||
0,
|
||||
NULL, // 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
|
||||
NULL, // 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
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Avocet assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t avocet =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_NOENS | UAS_NOSEG,
|
||||
"Avocet Systems 2500AD 6502 Assembler",
|
||||
0,
|
||||
NULL, // headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".fcc", // 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
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &svasm, &tasm, &pseudosam, &avocet, NULL };
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "MOS Technology 65xx series:"
|
||||
static const char *const shnames[] = { "M6502", "M65C02", NULL };
|
||||
static const char *const lnames[] = { FAMILY"MOS Technology 6502", "MOS Technology 65C02", NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcode_1[] = { 0x60 };
|
||||
static const uchar retcode_2[] = { 0x40 };
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_6502, // id
|
||||
PR_SEGS // flag
|
||||
| PR_SEGTRANS,
|
||||
0, // flag2
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
regnames, // Register names
|
||||
qnumber(regnames), // Number of registers
|
||||
|
||||
rVcs, // first
|
||||
rVds, // last
|
||||
0, // size of a segment register
|
||||
rVcs,rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0, M65_last,
|
||||
Instructions, // instruc
|
||||
};
|
||||
581
idasdk76/module/65816/ana.cpp
Normal file
581
idasdk76/module/65816/ana.cpp
Normal file
@@ -0,0 +1,581 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
|
||||
#define DI(itype, len, addr_mode, cpus) { (itype), (addr_mode), (cpus) },
|
||||
#define DV(itype, len, addr_mode, cpus, flags) { (itype), (addr_mode), (cpus), (flags) },
|
||||
|
||||
static const struct opcode_info_t opinfos[] =
|
||||
{
|
||||
// 0x00
|
||||
DI(M65816_brk, 2, STACK_INT, M6X )
|
||||
DI(M65816_ora, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_cop, 2, STACK_INT, M65816 )
|
||||
DI(M65816_ora, 2, STACK_REL, M65816 )
|
||||
DI(M65816_tsb, 2, DP, M65C02 | M65816 )
|
||||
DI(M65816_ora, 2, DP, M6X)
|
||||
DI(M65816_asl, 2, DP, M6X)
|
||||
DI(M65816_ora, 2, DP_INDIR_LONG, M6X)
|
||||
|
||||
// 0x08
|
||||
DI(M65816_php, 1, STACK_PUSH, M6X )
|
||||
DV(M65816_ora, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_asl, 1, ACC, M6X )
|
||||
DI(M65816_phd, 1, STACK_PUSH, M65816 )
|
||||
DI(M65816_tsb, 3, ABS, M65C02 | M65816 )
|
||||
DI(M65816_ora, 3, ABS, M6X )
|
||||
DI(M65816_asl, 3, ABS, M6X )
|
||||
DI(M65816_ora, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x10
|
||||
DI(M65816_bpl, 2, PC_REL, M6X )
|
||||
DI(M65816_ora, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_ora, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_ora, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_trb, 2, DP, M65C02 | M65816 )
|
||||
DI(M65816_ora, 2, DP_IX, M6X )
|
||||
DI(M65816_asl, 2, DP_IX, M6X )
|
||||
DI(M65816_ora, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x18
|
||||
DI(M65816_clc, 1, IMPLIED, M6X )
|
||||
DI(M65816_ora, 3, ABS_IY, M6X )
|
||||
DI(M65816_inc, 1, ACC, M65C02 | M65816 )
|
||||
DI(M65816_tcs, 1, IMPLIED, M65816 )
|
||||
DI(M65816_trb, 3, ABS, M65C02 | M65816 )
|
||||
DI(M65816_ora, 3, ABS_IX, M6X )
|
||||
DI(M65816_asl, 3, ABS_IX, M6X )
|
||||
DI(M65816_ora, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0x20
|
||||
DI(M65816_jsr, 3, ABS, M6X )
|
||||
DI(M65816_and, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_jsl, 4, ABS_LONG, M65816 )
|
||||
DI(M65816_and, 2, STACK_REL, M65816 )
|
||||
DI(M65816_bit, 2, DP, M6X )
|
||||
DI(M65816_and, 2, DP, M6X )
|
||||
DI(M65816_rol, 2, DP, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x28
|
||||
DI(M65816_plp, 1, STACK_PULL, M6X )
|
||||
DV(M65816_and, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_rol, 1, ACC, M6X )
|
||||
DI(M65816_pld, 1, STACK_PULL, M65816 )
|
||||
DI(M65816_bit, 3, ABS, M6X )
|
||||
DI(M65816_and, 3, ABS, M6X )
|
||||
DI(M65816_rol, 3, ABS, M6X )
|
||||
DI(M65816_and, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x30
|
||||
DI(M65816_bmi, 2, PC_REL, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_and, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_bit, 2, DP_IX, M65C02 | M65816 )
|
||||
DI(M65816_and, 2, DP_IX, M6X )
|
||||
DI(M65816_rol, 2, DP_IX, M6X )
|
||||
DI(M65816_and, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x38
|
||||
DI(M65816_sec, 1, IMPLIED, M6X )
|
||||
DI(M65816_and, 3, ABS_IY, M6X )
|
||||
DI(M65816_dec, 1, ACC, M65C02 | M65816 )
|
||||
DI(M65816_tsc, 1, IMPLIED, M65816 )
|
||||
DI(M65816_bit, 3, ABS_IX, M65C02 | M65816 )
|
||||
DI(M65816_and, 3, ABS_IX, M6X )
|
||||
DI(M65816_rol, 3, ABS_IX, M6X )
|
||||
DI(M65816_and, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0x40
|
||||
DI(M65816_rti, 1, STACK_RTI, M6X )
|
||||
DI(M65816_eor, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_wdm, 2, IMPLIED, M65816 )
|
||||
DI(M65816_eor, 2, STACK_REL, M65816 )
|
||||
DI(M65816_mvp, 3, BLK_MOV, M65816 )
|
||||
DI(M65816_eor, 2, DP, M6X )
|
||||
DI(M65816_lsr, 2, DP, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x48
|
||||
DI(M65816_pha, 1, STACK_PUSH, M6X )
|
||||
DV(M65816_eor, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_lsr, 1, ACC, M6X )
|
||||
DI(M65816_phk, 1, STACK_PUSH, M65816 )
|
||||
DI(M65816_jmp, 3, ABS, M6X )
|
||||
DI(M65816_eor, 3, ABS, M6X )
|
||||
DI(M65816_lsr, 3, ABS, M6X )
|
||||
DI(M65816_eor, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x50
|
||||
DI(M65816_bvc, 2, PC_REL, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_eor, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_mvn, 3, BLK_MOV, M65816 )
|
||||
DI(M65816_eor, 2, DP_IX, M6X )
|
||||
DI(M65816_lsr, 2, DP_IX, M6X )
|
||||
DI(M65816_eor, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x58
|
||||
DI(M65816_cli, 1, IMPLIED, M6X )
|
||||
DI(M65816_eor, 3, ABS_IY, M6X )
|
||||
DI(M65816_phy, 1, STACK_PUSH, M65C02 | M65816 )
|
||||
DI(M65816_tcd, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jml, 4, ABS_LONG, M65816 )
|
||||
DI(M65816_eor, 3, ABS_IX, M6X )
|
||||
DI(M65816_lsr, 3, ABS_IX, M6X )
|
||||
DI(M65816_eor, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0x60
|
||||
DI(M65816_rts, 1, STACK_RTS, M6X )
|
||||
DI(M65816_adc, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_per, 3, STACK_PC_REL, M65816 )
|
||||
DI(M65816_adc, 2, STACK_REL, M65816 )
|
||||
DI(M65816_stz, 2, DP, M65C02 | M65816 )
|
||||
DI(M65816_adc, 2, DP, M6X )
|
||||
DI(M65816_ror, 2, DP, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x68
|
||||
DI(M65816_pla, 1, STACK_PULL, M6X )
|
||||
DV(M65816_adc, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_ror, 1, ACC, M6X )
|
||||
DI(M65816_rtl, 1, STACK_RTL, M65816 )
|
||||
DI(M65816_jmp, 3, ABS_INDIR, M6X )
|
||||
DI(M65816_adc, 3, ABS, M6X )
|
||||
DI(M65816_ror, 3, ABS, M6X )
|
||||
DI(M65816_adc, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x70
|
||||
DI(M65816_bvs, 2, PC_REL, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_adc, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_stz, 2, DP_IX, M65C02 | M65816 )
|
||||
DI(M65816_adc, 2, DP_IX, M6X )
|
||||
DI(M65816_ror, 2, DP_IX, M6X )
|
||||
DI(M65816_adc, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x78
|
||||
DI(M65816_sei, 1, IMPLIED, M6X )
|
||||
DI(M65816_adc, 3, ABS_IY, M6X )
|
||||
DI(M65816_ply, 1, STACK_PULL, M65C02 | M65816 )
|
||||
DI(M65816_tdc, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jmp, 3, ABS_IX_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_adc, 3, ABS_IX, M6X )
|
||||
DI(M65816_ror, 3, ABS_IX, M6X )
|
||||
DI(M65816_adc, 4, ABS_LONG_IX, M6X )
|
||||
|
||||
// 0x80
|
||||
DI(M65816_bra, 2, PC_REL, M65C02 | M65816 )
|
||||
DI(M65816_sta, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_brl, 3, PC_REL_LONG, M65816 )
|
||||
DI(M65816_sta, 2, STACK_REL, M65816 )
|
||||
DI(M65816_sty, 2, DP, M6X )
|
||||
DI(M65816_sta, 2, DP, M6X )
|
||||
DI(M65816_stx, 2, DP, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0x88
|
||||
DI(M65816_dey, 1, IMPLIED, M6X )
|
||||
DV(M65816_bit, 2, IMM, M65C02 | M65816, ACC16_INCBC)
|
||||
DI(M65816_txa, 1, IMPLIED, M6X )
|
||||
DI(M65816_phb, 1, STACK_PUSH, M65816 )
|
||||
DI(M65816_sty, 3, ABS, M6X )
|
||||
DI(M65816_sta, 3, ABS, M6X )
|
||||
DI(M65816_stx, 3, ABS, M6X )
|
||||
DI(M65816_sta, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0x90
|
||||
DI(M65816_bcc, 2, PC_REL, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_sta, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_sty, 2, DP_IX, M6X )
|
||||
DI(M65816_sta, 2, DP_IX, M6X )
|
||||
DI(M65816_stx, 2, DP_IY, M6X )
|
||||
DI(M65816_sta, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0x98
|
||||
DI(M65816_tya, 1, IMPLIED, M6X )
|
||||
DI(M65816_sta, 3, ABS_IY, M6X )
|
||||
DI(M65816_txs, 1, IMPLIED, M6X )
|
||||
DI(M65816_txy, 1, IMPLIED, M65816 )
|
||||
DI(M65816_stz, 3, ABS, M65C02 | M65816 )
|
||||
DI(M65816_sta, 3, ABS_IX, M6X )
|
||||
DI(M65816_stz, 3, ABS_IX, M65C02 | M65816 )
|
||||
DI(M65816_sta, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0xa0
|
||||
DV(M65816_ldy, 2, IMM, M6X, XY16_INCBC )
|
||||
DI(M65816_lda, 2, DP_IX_INDIR, M6X )
|
||||
DV(M65816_ldx, 2, IMM, M6X, XY16_INCBC )
|
||||
DI(M65816_lda, 2, STACK_REL, M65816 )
|
||||
DI(M65816_ldy, 2, DP, M6X )
|
||||
DI(M65816_lda, 2, DP, M6X )
|
||||
DI(M65816_ldx, 2, DP, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0xa8
|
||||
DI(M65816_tay, 1, IMPLIED, M6X )
|
||||
DV(M65816_lda, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_tax, 1, IMPLIED, M6X )
|
||||
DI(M65816_plb, 1, STACK_PULL, M65816 )
|
||||
DI(M65816_ldy, 3, ABS, M6X )
|
||||
DI(M65816_lda, 3, ABS, M6X )
|
||||
DI(M65816_ldx, 3, ABS, M6X )
|
||||
DI(M65816_lda, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0xb0
|
||||
DI(M65816_bcs, 2, PC_REL, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_lda, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_ldy, 2, DP_IX, M6X )
|
||||
DI(M65816_lda, 2, DP_IX, M6X )
|
||||
DI(M65816_ldx, 2, DP_IY, M6X )
|
||||
DI(M65816_lda, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0xb8
|
||||
DI(M65816_clv, 1, IMPLIED, M6X )
|
||||
DI(M65816_lda, 3, ABS_IY, M6X )
|
||||
DI(M65816_tsx, 1, IMPLIED, M6X )
|
||||
DI(M65816_tyx, 1, IMPLIED, M65816 )
|
||||
DI(M65816_ldy, 3, ABS_IX, M6X )
|
||||
DI(M65816_lda, 3, ABS_IX, M6X )
|
||||
DI(M65816_ldx, 3, ABS_IY, M6X )
|
||||
DI(M65816_lda, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0xc0
|
||||
DV(M65816_cpy, 2, IMM, M6X, XY16_INCBC)
|
||||
DI(M65816_cmp, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_rep, 2, IMM, M65816 )
|
||||
DI(M65816_cmp, 2, STACK_REL, M65816 )
|
||||
DI(M65816_cpy, 2, DP, M6X )
|
||||
DI(M65816_cmp, 2, DP, M6X )
|
||||
DI(M65816_dec, 2, DP, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0xc8
|
||||
DI(M65816_iny, 1, IMPLIED, M6X )
|
||||
DV(M65816_cmp, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_dex, 1, IMPLIED, M6X )
|
||||
DI(M65816_wai, 1, IMPLIED, M65816 )
|
||||
DI(M65816_cpy, 3, ABS, M6X )
|
||||
DI(M65816_cmp, 3, ABS, M6X )
|
||||
DI(M65816_dec, 3, ABS, M6X )
|
||||
DI(M65816_cmp, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0xd0
|
||||
DI(M65816_bne, 2, PC_REL, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_cmp, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_pei, 2, STACK_DP_INDIR, M65816 )
|
||||
DI(M65816_cmp, 2, DP_IX, M6X )
|
||||
DI(M65816_dec, 2, DP_IX, M6X )
|
||||
DI(M65816_cmp, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0xd8
|
||||
DI(M65816_cld, 1, IMPLIED, M6X )
|
||||
DI(M65816_cmp, 3, ABS_IY, M6X )
|
||||
DI(M65816_phx, 1, STACK_PUSH, M65C02 | M65816 )
|
||||
DI(M65816_stp, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jmp, 3, ABS_INDIR_LONG, M65816 )
|
||||
DI(M65816_cmp, 3, ABS_IX, M6X )
|
||||
DI(M65816_dec, 3, ABS_IX, M6X )
|
||||
DI(M65816_cmp, 4, ABS_LONG_IX, M65816 )
|
||||
|
||||
// 0xe0
|
||||
DV(M65816_cpx, 2, IMM, M6X, XY16_INCBC)
|
||||
DI(M65816_sbc, 2, DP_IX_INDIR, M6X )
|
||||
DI(M65816_sep, 2, IMM, M65816 )
|
||||
DI(M65816_sbc, 2, STACK_REL, M65816 )
|
||||
DI(M65816_cpx, 2, DP, M6X )
|
||||
DI(M65816_sbc, 2, DP, M6X )
|
||||
DI(M65816_inc, 2, DP, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR_LONG, M65816 )
|
||||
|
||||
// 0xe8
|
||||
DI(M65816_inx, 1, IMPLIED, M6X )
|
||||
DV(M65816_sbc, 2, IMM, M6X, ACC16_INCBC)
|
||||
DI(M65816_nop, 1, IMPLIED, M6X )
|
||||
DI(M65816_xba, 1, IMPLIED, M65816 )
|
||||
DI(M65816_cpx, 3, ABS, M6X )
|
||||
DI(M65816_sbc, 3, ABS, M6X )
|
||||
DI(M65816_inc, 3, ABS, M6X )
|
||||
DI(M65816_sbc, 4, ABS_LONG, M65816 )
|
||||
|
||||
// 0xf0
|
||||
DI(M65816_beq, 2, PC_REL, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR_IY, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR, M65C02 | M65816 )
|
||||
DI(M65816_sbc, 2, STACK_REL_INDIR_IY, M65816 )
|
||||
DI(M65816_pea, 3, STACK_ABS, M65816 )
|
||||
DI(M65816_sbc, 2, DP_IX, M6X )
|
||||
DI(M65816_inc, 2, DP_IX, M6X )
|
||||
DI(M65816_sbc, 2, DP_INDIR_LONG_IY, M65816 )
|
||||
|
||||
// 0xf8
|
||||
DI(M65816_sed, 1, IMPLIED, M6X )
|
||||
DI(M65816_sbc, 3, ABS_IY, M6X )
|
||||
DI(M65816_plx, 1, STACK_PULL, M65C02 | M65816 )
|
||||
DI(M65816_xce, 1, IMPLIED, M65816 )
|
||||
DI(M65816_jsr, 3, ABS_IX_INDIR, M65816 )
|
||||
DI(M65816_sbc, 3, ABS_IX, M6X )
|
||||
DI(M65816_inc, 3, ABS_IX, M6X )
|
||||
DI(M65816_sbc, 4, ABS_LONG_IX, M65816 )
|
||||
};
|
||||
|
||||
#undef DI
|
||||
#undef DV
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
const struct opcode_info_t &get_opcode_info(uint8 opcode)
|
||||
{
|
||||
return opinfos[opcode];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline bool is_acc_16_sensitive_op(const struct opcode_info_t &opinfo)
|
||||
{
|
||||
return (opinfo.flags & ACC16_INCBC) == ACC16_INCBC;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline bool is_xy_16_sensitive_op(const struct opcode_info_t &opinfo)
|
||||
{
|
||||
return (opinfo.flags & XY16_INCBC) == XY16_INCBC;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
int idaapi ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
insn.Op1.dtype = dt_byte;
|
||||
uint8 code = insn.get_next_byte();
|
||||
|
||||
// Fetch instruction info
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(code);
|
||||
insn.itype = opinfo.itype;
|
||||
|
||||
switch ( opinfo.addr )
|
||||
{
|
||||
case ACC:
|
||||
case STACK_PUSH:
|
||||
case STACK_PULL:
|
||||
case STACK_RTS:
|
||||
case STACK_RTI:
|
||||
case STACK_RTL:
|
||||
case IMPLIED:
|
||||
break;
|
||||
case STACK_INT:
|
||||
// COP & BRK; they are 1-byte, but have
|
||||
// another, signature byte.
|
||||
insn.get_next_byte();
|
||||
break;
|
||||
case STACK_ABS:
|
||||
// Always 16 bits
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case STACK_REL:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rS;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
break;
|
||||
case STACK_REL_INDIR_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rSiY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
break;
|
||||
case STACK_PC_REL:
|
||||
{
|
||||
int16 disp = insn.get_next_word();
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.addr = uint16(insn.ip + insn.size + disp);
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
break;
|
||||
case STACK_DP_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rSDi;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case IMM:
|
||||
insn.Op1.type = o_imm;
|
||||
if ( (is_acc_16_sensitive_op (opinfo) && is_acc_16_bits(insn))
|
||||
|| (is_xy_16_sensitive_op (opinfo) && is_xy_16_bits(insn)) ) //
|
||||
{
|
||||
insn.Op1.value = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
}
|
||||
break;
|
||||
case ABS:
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
if ( insn.itype == M65816_jsr || insn.itype == M65816_jmp )
|
||||
{
|
||||
insn.Op1.type = o_near;
|
||||
}
|
||||
else if ( insn.itype == M65816_stx || insn.itype == M65816_sty
|
||||
|| insn.itype == M65816_ldx || insn.itype == M65816_ldy
|
||||
|| insn.itype == M65816_cpx || insn.itype == M65816_cpy )
|
||||
{
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
break;
|
||||
case ABS_LONG:
|
||||
insn.Op1.type = o_mem_far;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.addr|= insn.get_next_byte() << 16;
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
if ( insn.itype == M65816_jsl || insn.itype == M65816_jml )
|
||||
insn.Op1.type = o_far;
|
||||
else
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case ABS_IX:
|
||||
case ABS_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = opinfo.addr == ABS_IX ? rAbsX : rAbsY;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
if ( insn.itype == M65816_ldx || insn.itype == M65816_ldy )
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
else
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case ABS_LONG_IX:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsLX;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.addr |= insn.get_next_byte() << 16;
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case ABS_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsi;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case ABS_INDIR_LONG:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsiL;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case ABS_IX_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rAbsXi;
|
||||
insn.Op1.addr = insn.get_next_word();
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
case DP:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rD;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
if ( insn.itype == M65816_stx || insn.itype == M65816_sty
|
||||
|| insn.itype == M65816_ldx || insn.itype == M65816_ldy
|
||||
|| insn.itype == M65816_cpx || insn.itype == M65816_cpy )
|
||||
{
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
break;
|
||||
case DP_IY:
|
||||
case DP_IX:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = opinfo.addr == DP_IX ? rDX : rDY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
if ( insn.itype == M65816_stx || insn.itype == M65816_sty
|
||||
|| insn.itype == M65816_ldx || insn.itype == M65816_ldy )
|
||||
{
|
||||
insn.Op1.dtype = is_xy_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
}
|
||||
break;
|
||||
case DP_IX_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = riDX;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDi;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR_LONG:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDiL;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDiY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case DP_INDIR_LONG_IY:
|
||||
insn.Op1.type = o_displ;
|
||||
insn.Op1.phrase = rDiLY;
|
||||
insn.Op1.addr = insn.get_next_byte();
|
||||
insn.Op1.dtype = is_acc_16_bits(insn) ? dt_word : dt_byte;
|
||||
break;
|
||||
case PC_REL:
|
||||
insn.Op1.type = o_near;
|
||||
{
|
||||
char x = insn.get_next_byte();
|
||||
insn.Op1.addr = uint16(insn.ip + insn.size + x);
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
break;
|
||||
case PC_REL_LONG:
|
||||
insn.Op1.type = o_far;
|
||||
{
|
||||
int16 x = insn.get_next_word();
|
||||
insn.Op1.addr = uint16(insn.ip + insn.size + x) | (insn.ea & 0xff0000);
|
||||
insn.Op1.full_target_ea = insn.Op1.addr;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
break;
|
||||
case BLK_MOV:
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op2.type = o_imm;
|
||||
insn.Op2.value = insn.get_next_byte();
|
||||
insn.Op2.dtype = dt_byte;
|
||||
break;
|
||||
default:
|
||||
warning("ana: bad code 0x%x, @: 0x%a (IP=%a)", code, insn.ea, insn.ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return insn.size;
|
||||
}
|
||||
323
idasdk76/module/65816/bt.cpp
Normal file
323
idasdk76/module/65816/bt.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "bt.hpp"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
//lint -estring(823,BTWALK_PREAMBLE) definition of macro ends in semi-colon
|
||||
#define BTWALK_PREAMBLE(walker_ea, opcode_var, itype_var) \
|
||||
(walker_ea) = prev_head((walker_ea), (walker_ea) - 4); \
|
||||
if ( (walker_ea) == BADADDR ) \
|
||||
break; \
|
||||
flags_t F = get_flags(walker_ea); \
|
||||
if ( is_func(F) || !is_code(F) ) \
|
||||
break; \
|
||||
opcode_var = get_byte(walker_ea); \
|
||||
itype_var = get_opcode_info(opcode_var).itype;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FIXME: The following are lacks in implementation:
|
||||
// * If the value we asked for is 16bits, and
|
||||
// at some point we are reduced to an 8-bits one, we should
|
||||
// fail.
|
||||
int32 backtrack_value(ea_t from_ea, uint8 size, btsource_t source)
|
||||
{
|
||||
// Note: At some point, we were using:
|
||||
// ---
|
||||
// const func_t * const func = get_fchunk(from_ea);
|
||||
// if (func == NULL)
|
||||
// return -1;
|
||||
// ea_t chunk_start_ea = func->start_ea;
|
||||
// ---
|
||||
// in order to determine where we had to stop backtracking
|
||||
// values.
|
||||
// Unfortunately, that doesn't work because, during the initial
|
||||
// analysis, where functions & chunks aren't properly formed yet,
|
||||
// the 'func' ptr would always be NULL. Therefore, we wouldn't
|
||||
// be capable of backtracking a value properly; which also
|
||||
// means that wrong values were propagated to other
|
||||
// functions.
|
||||
//
|
||||
// A particularily interesting example is this: In a certain
|
||||
// rom, we had the following seq. of instructions:
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// .C0:0019 SEI
|
||||
// .C0:001A CLC
|
||||
// .C0:001B XCE
|
||||
// .C0:001C SEP #$20 ; ' ' ; .a8, .i16
|
||||
// .C0:001E REP #$10 ; .a8, .i16
|
||||
// .C0:0020 LDX #$15FF
|
||||
// .C0:0023 TXS
|
||||
// .C0:0024 LDX #0
|
||||
// .C0:0027 PHX
|
||||
// .C0:0028 PLD
|
||||
// .C0:0029 TDC
|
||||
// .C0:002A PHA
|
||||
// .C0:002B PLB
|
||||
// .C0:002C LDA #1
|
||||
// .C0:002E STA CYCLE_SPEED_DESIGNATION ; 0000000a a: 0 = 2.68 MHz, 1 = 3.58 MHz
|
||||
// .C0:0031 STZ REGULAR_DMA_CHANNEL_ENABLE ; abcdefgh a = Channel 7...h = Channel 0: 1 = Enable 0 = Disable
|
||||
// .C0:0034 STZ H_DMA_CHANNEL_ENABLE ; abcdefgh a = Channel 7 .. h = Channel 0: 1 = Enable 0 = Disable
|
||||
// .C0:0037 LDA #$8F ; ''
|
||||
// .C0:0039 STA SCREEN_DISPLAY_REGISTER ; a000bbbb a: 0=screen on 1=screen off, b = brightness
|
||||
// .C0:003C STZ NMI_V_H_COUNT_AND_JOYPAD_ENABLE ; a0bc000d a = NMI b = V-Count c = H-Count d = Joypad
|
||||
// .C0:003F JSR sub_C00525
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// And, at 0xc00525:
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// .C0:0525 sub_C00525: ; CODE XREF: sub_C00019+26p
|
||||
// .C0:0525 TDC
|
||||
// .C0:0526 TAX
|
||||
// .C0:0527 STX WRAM_ADDRESS_LOW_BYTE
|
||||
// .C0:052A STA WRAM_ADDRESS_HIGH_BYTE
|
||||
// .C0:052D LDX #$120
|
||||
// .C0:0530
|
||||
// .C0:0530 loc_C00530: ; CODE XREF: sub_C00525+3Cj
|
||||
// .C0:0530 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0533 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0536 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0539 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:053C STA WRAM_DATA_READ_WRITE
|
||||
// .C0:053F STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0542 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0545 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0548 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:054B STA WRAM_DATA_READ_WRITE
|
||||
// .C0:054E STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0551 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0554 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0557 STA WRAM_DATA_READ_WRITE
|
||||
// .C0:055A STA WRAM_DATA_READ_WRITE
|
||||
// .C0:055D STA WRAM_DATA_READ_WRITE
|
||||
// .C0:0560 DEX
|
||||
// .C0:0561 BNE loc_C00530
|
||||
// .C0:0563 RTS
|
||||
// --------------------------------------------------------------------------
|
||||
//
|
||||
// What would happen is that the 'STA's starting at
|
||||
// C0:0530 would not reference the proper register:
|
||||
// The B was 0xffffffff (from a previous
|
||||
// propagation), and when a later propagation tried to set
|
||||
// the B value to 0x00, starting at C0:0525, that
|
||||
// propagation stopped at the next segment start.
|
||||
// That is, C0:0530,
|
||||
// which was established because of the BNE that
|
||||
// appears below.
|
||||
// Which also makes me think.. should we propagate from a BNE?
|
||||
|
||||
uint8 opcode;
|
||||
ea_t cur_ea = from_ea;
|
||||
uint8 itype;
|
||||
switch ( source )
|
||||
{
|
||||
case BT_STACK:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
if ( M65_ITYPE_PUSH(itype) )
|
||||
{
|
||||
switch ( itype )
|
||||
{
|
||||
case M65816_pea: // Push effective absolute address
|
||||
{
|
||||
uint16 val = get_word(cur_ea + 1);
|
||||
if ( size == 1 )
|
||||
val &= 0xff;
|
||||
return val;
|
||||
}
|
||||
case M65816_pei: // Push effective indirect address
|
||||
return -1;
|
||||
case M65816_per: // Push effective PC-relative indirect address
|
||||
{
|
||||
uint16 val = cur_ea + 3;
|
||||
val += get_word(cur_ea + 1);
|
||||
val &= (size == 1 ? 0xff : 0xffff);
|
||||
return val;
|
||||
}
|
||||
case M65816_pha: // Push A
|
||||
return backtrack_value(cur_ea, size, BT_A);
|
||||
case M65816_phb: // Push B (data bank register)
|
||||
return get_sreg(cur_ea, rB);
|
||||
case M65816_phd: // Push D (direct page register)
|
||||
return get_sreg(cur_ea, rD);
|
||||
case M65816_phk: // Push K (program bank register)
|
||||
return get_sreg(cur_ea, rPB);
|
||||
case M65816_php: // Push processor status
|
||||
return -1;
|
||||
case M65816_phx: // Push X
|
||||
return backtrack_value(cur_ea, size, BT_X);
|
||||
case M65816_phy: // Push Y
|
||||
return backtrack_value(cur_ea, size, BT_Y);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if ( M65_ITYPE_PULL(itype) )
|
||||
{
|
||||
// TODO: keep track of additional displacements in the stack
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_A:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
uint8 opsize = from_ea - cur_ea;
|
||||
uint8 cur_ea_acc_is_16 = is_acc_16_bits(cur_ea);
|
||||
uint8 new_size = cur_ea_acc_is_16 ? 2 : 1;
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify A in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_adc: // Add with carry
|
||||
case M65816_and: // AND A with memory
|
||||
case M65816_asl: // Shift memory or A left
|
||||
case M65816_dec: // Decrement
|
||||
case M65816_eor: // XOR A with M
|
||||
case M65816_inc: // Increment
|
||||
case M65816_mvn: // Block move next
|
||||
case M65816_mvp: // Block move prev
|
||||
case M65816_ora: // Or A with memory
|
||||
case M65816_sbc: // Subtract with borrow from A
|
||||
case M65816_xba: // Exchange bytes in A
|
||||
return -1;
|
||||
// For these next ones, there's hope.
|
||||
case M65816_lsr: // Logical shift memory or A right
|
||||
if ( opcode == 0x4a ) // LSR A
|
||||
return -1;
|
||||
break;
|
||||
case M65816_rol: // Rotate memory or A left
|
||||
case M65816_ror: // Rotate memory or A right
|
||||
if ( opcode == 0x30 || opcode == 0x70 )
|
||||
return -1;
|
||||
break;
|
||||
case M65816_lda: // Load A from memory
|
||||
if ( opcode == 0xa9 ) // LDA imm
|
||||
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
|
||||
else
|
||||
return -1;
|
||||
case M65816_pla: // Pull A
|
||||
return backtrack_value(cur_ea, new_size, BT_STACK);
|
||||
case M65816_tdc: // Transfer 16-bit D to A
|
||||
return get_sreg(cur_ea, rD);
|
||||
case M65816_tsc: // Transfer S to A
|
||||
return get_sreg(cur_ea, rS);
|
||||
case M65816_txa: // Transfer X to A
|
||||
return backtrack_value(cur_ea, new_size, BT_X);
|
||||
case M65816_tya: // Transfer Y to A
|
||||
return backtrack_value(cur_ea, new_size, BT_Y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_X:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
uint8 opsize = from_ea - cur_ea;
|
||||
uint8 cur_ea_xy_is_16 = is_xy_16_bits(cur_ea);
|
||||
uint8 new_size = cur_ea_xy_is_16 ? 2 : 1;
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify X in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_dex: // Decrement X
|
||||
case M65816_inx: // Increment X
|
||||
case M65816_mvn: // Block move next
|
||||
case M65816_mvp: // Block move prev
|
||||
return -1;
|
||||
case M65816_ldx: // Load X from memory
|
||||
if ( opcode == 0xa2 ) // LDX imm
|
||||
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
|
||||
else
|
||||
return -1;
|
||||
case M65816_plx: // Pull X
|
||||
return backtrack_value(cur_ea, new_size, BT_STACK);
|
||||
case M65816_tax: // Transfer A to X
|
||||
return backtrack_value(cur_ea, new_size, BT_A);
|
||||
case M65816_tsx: // Transfer S to X
|
||||
return get_sreg(cur_ea, rS);
|
||||
case M65816_tyx: // Transfer Y to X
|
||||
return backtrack_value(cur_ea, new_size, BT_Y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_Y:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
uint8 opsize = from_ea - cur_ea;
|
||||
uint8 cur_ea_xy_is_16 = is_xy_16_bits(cur_ea);
|
||||
uint8 new_size = cur_ea_xy_is_16 ? 2 : 1;
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify X in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_dey: // Decrement Y
|
||||
case M65816_iny: // Increment Y
|
||||
case M65816_mvn: // Block move next
|
||||
case M65816_mvp: // Block move prev
|
||||
return -1;
|
||||
case M65816_ldy: // Load Y from memory
|
||||
if ( opcode == 0xa0 ) // LDY imm
|
||||
return opsize == 3 ? get_word(cur_ea + 1) : get_byte(cur_ea + 1);
|
||||
else
|
||||
return -1;
|
||||
case M65816_ply: // Pull Y
|
||||
return backtrack_value(cur_ea, new_size, BT_STACK);
|
||||
case M65816_tay: // Transfer A to Y
|
||||
return backtrack_value(cur_ea, new_size, BT_A);
|
||||
case M65816_txy: // Transfer X to Y
|
||||
return backtrack_value(cur_ea, new_size, BT_X);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BT_DP:
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, itype);
|
||||
switch ( itype )
|
||||
{
|
||||
// All these modify D in a way we cannot
|
||||
// easily determine its value anymore.
|
||||
// We'll thus stop.
|
||||
case M65816_pld: // Pull D
|
||||
return backtrack_value(cur_ea, size, BT_STACK);
|
||||
case M65816_tcd: // Transfer 16-bit Accumulator to Direct Page Register
|
||||
return backtrack_value(cur_ea, size, BT_A);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg("WARNING: backtrack_value() of unsupported BT-type: %d\n", source);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
ea_t backtrack_prev_ins(ea_t from_ea, m65_itype_t itype)
|
||||
{
|
||||
uint8 opcode;
|
||||
ea_t cur_ea = from_ea;
|
||||
uint8 candidate_itype;
|
||||
while ( true )
|
||||
{
|
||||
BTWALK_PREAMBLE(cur_ea, opcode, candidate_itype);
|
||||
if ( candidate_itype == itype )
|
||||
return cur_ea;
|
||||
}
|
||||
|
||||
return BADADDR;
|
||||
}
|
||||
|
||||
#undef BTWALK_LOOP
|
||||
#undef BTWALK_PREAMBLE
|
||||
|
||||
|
||||
74
idasdk76/module/65816/bt.hpp
Normal file
74
idasdk76/module/65816/bt.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef __BACKTRACK_HPP__
|
||||
#define __BACKTRACK_HPP__
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
|
||||
enum btsource_t
|
||||
{
|
||||
BT_NONE = 0,
|
||||
BT_STACK,
|
||||
BT_A,
|
||||
BT_X,
|
||||
BT_Y,
|
||||
BT_DP
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Walk instructions up, and try and determine what's the
|
||||
* (size * 8)-bits value we're looking for.
|
||||
*
|
||||
* For example, let's assume we have the following sequence
|
||||
* of instructions:
|
||||
* .05:8001 PHK
|
||||
* .05:8002 PLB
|
||||
* We'll call:
|
||||
* backtrack_value(0x58002, 1, BT_STACK).
|
||||
*
|
||||
* A more complex example is this:
|
||||
* .C0:0024 A2 00 00 LDX #0
|
||||
* .C0:0027 DA PHX
|
||||
* .C0:0028 2B PLD
|
||||
* .C0:0029 7B TDC
|
||||
* .C0:002A 48 PHA
|
||||
* .C0:002B AB PLB
|
||||
* We'll call:
|
||||
* backtrack_value(0xc0002b, 1, BT_STACK), which will call
|
||||
* backtrack_value(0xc0002a, 1, BT_A), which will call
|
||||
* backtrack_value(0xc00029, 1, BT_D), which will call
|
||||
* backtrack_value(0xc00028, 2, BT_STACK), which will call
|
||||
* backtrack_value(0xc00027, 2, BT_X), which has an immediate value that we can use. Bingo.
|
||||
*
|
||||
* Backtracking will, of course, stop if we hit the top
|
||||
* of a function, as it doesn't make much sense to keep
|
||||
* moving up.
|
||||
*
|
||||
* from_ea : The address from which we'll be analyzing up.
|
||||
* size : The size, in bytes, of the data we're looking for.
|
||||
* source : The register/stack that holds the value.
|
||||
*
|
||||
* returns : The value.
|
||||
*/
|
||||
int32 backtrack_value(ea_t from_ea, uint8 size, btsource_t source);
|
||||
|
||||
|
||||
/**
|
||||
* Walk instructions up, until an instruction with the given type
|
||||
* is found.
|
||||
*
|
||||
* Backtracking will, of course, stop if we hit the top
|
||||
* of a function, as it doesn't make much sense to keep
|
||||
* moving up.
|
||||
*
|
||||
* from_ea : The address from which we'll be analyzing up.
|
||||
* itype : The instruction type.
|
||||
*
|
||||
* returns : The address of the found instruction, or BADADDR
|
||||
* if not found.
|
||||
*/
|
||||
ea_t backtrack_prev_ins(ea_t from_ea, m65_itype_t itype);
|
||||
|
||||
|
||||
#endif
|
||||
294
idasdk76/module/65816/emu.cpp
Normal file
294
idasdk76/module/65816/emu.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "bt.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void m65816_t::handle_operand(const op_t &x, bool read_access, const insn_t &insn)
|
||||
{
|
||||
ea_t ea;
|
||||
dref_t dreftype;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
QASSERT(557, read_access);
|
||||
dreftype = dr_O;
|
||||
MAKE_IMMD:
|
||||
set_immd(insn.ea);
|
||||
if ( is_off(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dreftype, x.type == o_imm ? 0 : OOF_ADDR);
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
dreftype = read_access ? dr_R : dr_W;
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case rD: // "dp"
|
||||
case rDX: // "dp, X"
|
||||
case rDY: // "dp, Y"
|
||||
case riDX: // "(dp, X)"
|
||||
case rDi: // "(dp,n)"
|
||||
case rDiL: // "long(dp,n)"
|
||||
case rDiY: // "(dp,n), Y"
|
||||
case rDiLY: // "long(dp,n), Y"
|
||||
{
|
||||
sel_t dp = get_sreg(insn.ea, rD);
|
||||
if ( dp != BADSEL )
|
||||
{
|
||||
ea_t orig_ea = dp + x.addr;
|
||||
ea = xlat(orig_ea);
|
||||
goto MAKE_DREF;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto MAKE_IMMD;
|
||||
}
|
||||
}
|
||||
|
||||
case rAbsi: // "(abs)"
|
||||
case rAbsX: // "abs, X"
|
||||
case rAbsY: // "abs, Y"
|
||||
case rAbsiL: // "long(abs)"
|
||||
ea = xlat(map_data_ea(insn, x));
|
||||
goto MAKE_DREF;
|
||||
|
||||
case rAbsXi: // "(abs,X)"
|
||||
ea = xlat(map_code_ea(insn, x)); // jmp, jsr
|
||||
goto MAKE_DREF;
|
||||
|
||||
case rAbsLX: // "long abs, X"
|
||||
ea = x.addr;
|
||||
goto MAKE_DREF;
|
||||
|
||||
default:
|
||||
goto MAKE_IMMD;
|
||||
}
|
||||
|
||||
case o_mem:
|
||||
case o_mem_far:
|
||||
ea = calc_addr(x, NULL, insn);
|
||||
MAKE_DREF:
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, read_access ? dr_R : dr_W);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
case o_far:
|
||||
{
|
||||
ea_t orig_ea;
|
||||
ea = calc_addr(x, &orig_ea, insn);
|
||||
if ( insn.itype == M65816_per )
|
||||
{
|
||||
insn.add_dref(ea, x.offb, dr_O);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
cref_t creftype = x.type == o_near
|
||||
? iscall ? fl_CN : fl_JN
|
||||
: iscall ? fl_CF : fl_JF;
|
||||
insn.add_cref(ea, x.offb, creftype);
|
||||
if ( flow && iscall )
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(558);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/**
|
||||
* Get what is known of the status flags register,
|
||||
* at address 'ea'.
|
||||
*
|
||||
* ea : The effective address.
|
||||
*
|
||||
* returns : A 9-bit value, composed with what is known of the
|
||||
* status register at the 'ea' effective address. Its
|
||||
* layout is the following:
|
||||
* +----------------------------------------------------------------+
|
||||
* | 0 | 0 | 0 | 0 | 0 | 0 | 0 | e || n | v | m | x | d | i | z | c |
|
||||
* +----------------------------------------------------------------+
|
||||
* 15 7 0
|
||||
* Note that a 16-bit value is returned, in order to
|
||||
* take the emulation-mode flag into consideration.
|
||||
*/
|
||||
static uint16 get_cpu_status(ea_t ea)
|
||||
{
|
||||
return (get_sreg(ea, rFe) << 8) | (get_sreg(ea, rFm) << 5) | (get_sreg(ea, rFx) << 4);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int m65816_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn.Op1, 1, insn);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn.Op2, 1, insn);
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn.Op1, 0, insn);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn.Op2, 0, insn);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
uint8 code = get_byte(insn.ea);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(code);
|
||||
|
||||
if ( opinfo.itype == M65816_jmp || opinfo.itype == M65816_jsr )
|
||||
{
|
||||
if ( opinfo.addr == ABS_INDIR
|
||||
|| opinfo.addr == ABS_INDIR_LONG
|
||||
|| opinfo.addr == ABS_IX_INDIR )
|
||||
{
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
switch ( opinfo.addr )
|
||||
{
|
||||
case ABS_LONG_IX:
|
||||
{
|
||||
ea_t orig_ea = insn.Op1.addr;
|
||||
ea_t ea = xlat(orig_ea);
|
||||
|
||||
bool read_access;
|
||||
if ( insn.itype == M65816_sta )
|
||||
read_access = false;
|
||||
else
|
||||
read_access = true;
|
||||
|
||||
insn.add_dref(ea, insn.Op1.offb, read_access ? dr_R : dr_W);
|
||||
break;
|
||||
}
|
||||
|
||||
case DP:
|
||||
{
|
||||
bool read_access;
|
||||
if ( insn.itype == M65816_tsb || insn.itype == M65816_asl || insn.itype == M65816_trb
|
||||
|| insn.itype == M65816_rol || insn.itype == M65816_lsr || insn.itype == M65816_ror
|
||||
|| insn.itype == M65816_dec || insn.itype == M65816_inc )
|
||||
read_access = false;
|
||||
else
|
||||
read_access = true;
|
||||
|
||||
int32 val = backtrack_value(insn.ea, 2, BT_DP);
|
||||
if ( val != -1 )
|
||||
{
|
||||
ea_t orig_ea = val + insn.Op1.addr;
|
||||
ea_t ea = xlat(orig_ea);
|
||||
|
||||
insn.create_op_data(ea, insn.Op1);
|
||||
insn.add_dref(ea, insn.Op1.offb, read_access ? dr_R : dr_W);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case M65816_sep:
|
||||
case M65816_rep:
|
||||
{
|
||||
// Switching 8 -> 16 bits modes.
|
||||
uint8 flag_data = get_byte(insn.ea + 1);
|
||||
uint8 m_flag = flag_data & 0x20;
|
||||
uint8 x_flag = flag_data & 0x10;
|
||||
uint8 val = (insn.itype == M65816_rep) ? 0 : 1;
|
||||
|
||||
if ( m_flag )
|
||||
split_sreg_range(insn.ea + 2, rFm, val, SR_auto);
|
||||
if ( x_flag )
|
||||
split_sreg_range(insn.ea + 2, rFx, val, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_xce:
|
||||
{
|
||||
// Switching to native mode?
|
||||
uint8 prev = get_byte(insn.ea - 1);
|
||||
const struct opcode_info_t &opinf = get_opcode_info(prev);
|
||||
if ( opinf.itype == M65816_clc )
|
||||
split_sreg_range(insn.ea + 1, rFe, 0, SR_auto);
|
||||
else if ( opinf.itype == M65816_sec )
|
||||
split_sreg_range(insn.ea + 1, rFe, 1, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_jmp:
|
||||
case M65816_jml:
|
||||
case M65816_jsl:
|
||||
case M65816_jsr:
|
||||
{
|
||||
if ( insn.Op1.full_target_ea )
|
||||
{
|
||||
ea_t ftea = insn.Op1.full_target_ea;
|
||||
if ( insn.itype != M65816_jsl && insn.itype != M65816_jml )
|
||||
ftea = map_code_ea(insn, ftea, 0);
|
||||
else
|
||||
ftea = xlat(ftea);
|
||||
|
||||
split_sreg_range(ftea, rFm, get_sreg(insn.ea, rFm), SR_auto);
|
||||
split_sreg_range(ftea, rFx, get_sreg(insn.ea, rFx), SR_auto);
|
||||
split_sreg_range(ftea, rFe, get_sreg(insn.ea, rFe), SR_auto);
|
||||
split_sreg_range(ftea, rPB, ftea >> 16, SR_auto);
|
||||
split_sreg_range(ftea, rB, get_sreg(insn.ea, rB), SR_auto);
|
||||
split_sreg_range(ftea, rDs, get_sreg(insn.ea, rDs), SR_auto);
|
||||
split_sreg_range(ftea, rD, get_sreg(insn.ea, rD), SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_plb:
|
||||
{
|
||||
int32 val = backtrack_value(insn.ea, 1, BT_STACK);
|
||||
if ( val != -1 )
|
||||
{
|
||||
split_sreg_range(insn.ea + insn.size, rB, val, SR_auto);
|
||||
split_sreg_range(insn.ea + insn.size, rDs, val << 12, SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_pld:
|
||||
{
|
||||
int32 val = backtrack_value(insn.ea, 2, BT_STACK);
|
||||
if ( val != -1 )
|
||||
split_sreg_range(insn.ea + insn.size, rD, val, SR_auto);
|
||||
}
|
||||
break;
|
||||
|
||||
case M65816_plp:
|
||||
{
|
||||
// Ideally, should pass another parameter, specifying when to stop
|
||||
// backtracking.
|
||||
// For example, in order to avoid this:
|
||||
// PHP
|
||||
// PLP <-- this one is causing interference
|
||||
// (dunno if that even happens, though)
|
||||
// PLP
|
||||
ea_t ea = backtrack_prev_ins(insn.ea, M65816_php);
|
||||
if ( ea != BADADDR )
|
||||
{
|
||||
uint16 p = get_cpu_status(ea);
|
||||
split_sreg_range(insn.ea + insn.size, rFm, (p >> 5) & 0x1, SR_auto);
|
||||
split_sreg_range(insn.ea + insn.size, rFx, (p >> 4) & 0x1, SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
143
idasdk76/module/65816/ins.cpp
Normal file
143
idasdk76/module/65816/ins.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 },
|
||||
{ "ADC", CF_USE1 }, // A <- (A) + M + C
|
||||
{ "AND", CF_USE1 }, // A <- A /\ M, C <- ~A7
|
||||
{ "ASL", CF_CHG1|CF_SHFT }, // C <- A7, A <- (A) << 1
|
||||
{ "BCC", CF_USE1 }, // if C=0, PC = PC + offset
|
||||
{ "BCS", CF_USE1 }, // if C=1, PC = PC + offset
|
||||
{ "BEQ", CF_USE1 }, // if Z=1, PC = PC + offset
|
||||
{ "BIT", CF_USE1 }, // Z <- ~(A /\ M) N<-M7 V<-M6
|
||||
{ "BMI", CF_USE1 }, // if N=1, PC = PC + offset
|
||||
{ "BNE", CF_USE1 }, // if Z=0, PC = PC + offset
|
||||
{ "BPL", CF_USE1 }, // if N=0, PC = PC + offset
|
||||
{ "BRA", CF_USE1|CF_STOP }, // Branch always
|
||||
{ "BRK", 0 }, // Stack <- PC, PC <- ($fffe) NOTE: Usually it stops the processor. However, some games (e.g. Dragon Quest VI) use BRK as a customized opcode, by overriding the behavior through the interrupt vector.
|
||||
{ "BRL", CF_USE1|CF_STOP }, // Branch always long
|
||||
{ "BVC", CF_USE1 }, // if V=0, PC = PC + offset
|
||||
{ "BVS", CF_USE1 }, // if V=1, PC = PC + offset
|
||||
{ "CLC", 0 }, // C <- 0
|
||||
{ "CLD", 0 }, // D <- 0
|
||||
{ "CLI", 0 }, // I <- 0
|
||||
{ "CLV", 0 }, // V <- 0
|
||||
{ "CMP", CF_USE1 }, // (A - M) -> NZC
|
||||
{ "COP", 0 }, // Coprocessor enable
|
||||
{ "CPX", CF_USE1 }, // (X - M) -> NZC
|
||||
{ "CPY", CF_USE1 }, // (Y - M) -> NZC
|
||||
{ "DEC", CF_USE1|CF_CHG1 }, // M <- (M) - 1
|
||||
{ "DEX", 0 }, // X <- (X) - 1
|
||||
{ "DEY", 0 }, // Y <- (Y) - 1
|
||||
{ "EOR", CF_USE1 }, // A <- (A) \-/ M
|
||||
{ "INC", CF_USE1|CF_CHG1 }, // M <- (M) + 1
|
||||
{ "INX", 0 }, // X <- (X) +1
|
||||
{ "INY", 0 }, // Y <- (Y) + 1
|
||||
{ "JML", CF_USE1|CF_STOP }, // K,PC <- Long Address
|
||||
{ "JMP", CF_USE1|CF_STOP }, // PC <- Address
|
||||
{ "JSL", CF_USE1|CF_CALL }, // Stack <- PC, PC <- Long Address
|
||||
{ "JSR", CF_USE1|CF_CALL }, // Stack <- PC, PC <- Address
|
||||
{ "LDA", CF_USE1 }, // A <- M
|
||||
{ "LDX", CF_USE1 }, // X <- M
|
||||
{ "LDY", CF_USE1 }, // Y <- M
|
||||
{ "LSR", CF_CHG1|CF_SHFT }, // C <- A0, A <- (A) >> 1
|
||||
{ "MVN", CF_USE1|CF_USE2 }, // Block move next
|
||||
{ "MVP", CF_USE1|CF_USE2 }, // Block move previous
|
||||
{ "NOP", 0 }, // [no operation]
|
||||
{ "ORA", CF_USE1 }, // A <- (A) V M
|
||||
{ "PEA", CF_USE1 }, // Stack <- Address
|
||||
{ "PEI", CF_USE1 }, // Stack <- [DP + M]
|
||||
{ "PER", CF_USE1 }, // Stack <- PC + offset
|
||||
{ "PHA", 0 }, // Stack <- (A)
|
||||
{ "PHB", 0 }, // Stack <- (B)
|
||||
{ "PHD", 0 }, // Stack <- (D)
|
||||
{ "PHK", 0 }, // Stack <- (K)
|
||||
{ "PHP", 0 }, // Stack <- (P)
|
||||
{ "PHX", 0 }, // Push X register
|
||||
{ "PHY", 0 }, // Push Y register
|
||||
{ "PLA", 0 }, // A <- (Stack)
|
||||
{ "PLB", 0 }, // B <- (Stack)
|
||||
{ "PLD", 0 }, // D <- (Stack)
|
||||
{ "PLP", 0 }, // P <- (Stack)
|
||||
{ "PLX", 0 }, // Pull X register
|
||||
{ "PLY", 0 }, // Pull Y register
|
||||
{ "REP", CF_USE1 }, // Reset bits
|
||||
{ "ROL", CF_CHG1|CF_SHFT }, // C <- A7 & A <- A << 1 + C
|
||||
{ "ROR", CF_CHG1|CF_SHFT }, // C<-A0 & A<- (A7=C + A>>1)
|
||||
{ "RTI", CF_STOP }, // P <- (Stack), PC <-(Stack)
|
||||
{ "RTL", CF_STOP }, // K,PC <- (Stack)
|
||||
{ "RTS", CF_STOP }, // PC <- (Stack)
|
||||
{ "SBC", CF_USE1 }, // A <- (A) - M - ~C
|
||||
{ "SEC", 0 }, // C <- 1
|
||||
{ "SED", 0 }, // D <- 1
|
||||
{ "SEI", 0 }, // I <- 1
|
||||
{ "SEP", CF_USE1 }, // P <- Values
|
||||
{ "STA", CF_CHG1 }, // M <- (A)
|
||||
{ "STP", 0 }, // Stop processor
|
||||
{ "STX", CF_CHG1 }, // M <- (X)
|
||||
{ "STY", CF_CHG1 }, // M <- (Y)
|
||||
{ "STZ", CF_CHG1 }, // Store zero
|
||||
{ "TAX", 0 }, // X <- (A)
|
||||
{ "TAY", 0 }, // Y <- (A)
|
||||
{ "TCD", 0 }, // D <- (A)
|
||||
{ "TCS", 0 }, // S <- (A)
|
||||
{ "TDC", 0 }, // A <- (D)
|
||||
{ "TRB", CF_USE1|CF_CHG1 }, // Test and reset bits
|
||||
{ "TSB", CF_USE1|CF_CHG1 }, // Test and set bits
|
||||
{ "TSC", 0 }, // A <- (S)
|
||||
{ "TSX", 0 }, // X <- (S)
|
||||
{ "TXA", 0 }, // A <- (X)
|
||||
{ "TXS", 0 }, // S <- (X)
|
||||
{ "TXY", 0 }, // Y <- (X)
|
||||
{ "TYA", 0 }, // A <- (Y)
|
||||
{ "TYX", 0 }, // X <- (Y)
|
||||
{ "WAI", 0 }, // Wait for interrupt
|
||||
{ "WDM", 0 }, // Reserved
|
||||
{ "XBA", 0 }, // Exchange A's bytes
|
||||
{ "XCE", 0 } // Exchange carry & emu bits
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == M65816_last);
|
||||
|
||||
|
||||
const struct addrmode_info_t AddressingModes[] =
|
||||
{
|
||||
{ "Absolute" }, // ABS
|
||||
{ "Absolute Indexed X" }, // ABS_IX,
|
||||
{ "Absolute Indexed Y" }, // ABS_IY,
|
||||
{ "Absolute Indexed Indirect" }, // ABS_IX_INDIR,
|
||||
{ "Absolute Indirect" }, // ABS_INDIR,
|
||||
{ "Absolute Indirect Long" }, // ABS_INDIR_LONG,
|
||||
{ "Absolute Long" }, // ABS_LONG,
|
||||
{ "Absolute Long Indexed X" }, // ABS_LONG_IX,
|
||||
{ "Accumulator" }, // ACC,
|
||||
{ "Block Move" }, // BLK_MOV,
|
||||
{ "Direct Page" }, // DP,
|
||||
{ "Direct Page Indexed X" }, // DP_IX,
|
||||
{ "Direct Page Indexed Y" }, // DP_IY,
|
||||
{ "Direct Page Indexed X Indirect" }, // DP_IX_INDIR,
|
||||
{ "Direct Page Indirect" }, // DP_INDIR,
|
||||
{ "Direct Page Indirect Long" }, // DP_INDIR_LONG,
|
||||
{ "Direct Page Indirect Indexed Y" }, // DP_INDIR_IY,
|
||||
{ "Direct Page Indirect Long Indexed Y" }, // DP_INDIR_LONG_IY,
|
||||
{ "Immediate" }, // IMM,
|
||||
{ "Implied" }, // IMPLIED,
|
||||
{ "Program Counter Relative" }, // PC_REL,
|
||||
{ "Program Counter Relative Long" }, // PC_REL_LONG,
|
||||
{ "Stack Absolute" }, // STACK_ABS,
|
||||
{ "Stack Direct Page Indirect" }, // STACK_DP_INDIR,
|
||||
{ "Stack Interrupt" }, // STACK_INT,
|
||||
{ "Stack Program Counter Relative" }, // STACK_PC_REL,
|
||||
{ "Stack Pull" }, // STACK_PULL,
|
||||
{ "Stack Push" }, // STACK_PUSH,
|
||||
{ "Stack RTI" }, // STACK_RTI,
|
||||
{ "Stack RTL" }, // STACK_RTL,
|
||||
{ "Stack RTS" }, // STACK_RTS,
|
||||
{ "Stack REL" }, // STACK_REL,
|
||||
{ "Stack Relative Indirect Indexed Y" } // STACK_REL_INDIR_IY,
|
||||
};
|
||||
|
||||
CASSERT(qnumber(AddressingModes) == ADDRMODE_last);
|
||||
109
idasdk76/module/65816/ins.hpp
Normal file
109
idasdk76/module/65816/ins.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
#ifndef __INSTRS_HPP__
|
||||
#define __INSTRS_HPP__
|
||||
|
||||
extern const struct instruc_t Instructions[];
|
||||
|
||||
// The instruction types (``itype''s)
|
||||
// m65* CPUs implements.
|
||||
|
||||
enum m65_itype_t
|
||||
{
|
||||
// http://www.westerndesigncenter.com/wdc/datasheets/Programmanual.pdf
|
||||
M65816_null=0, // Unknown Operation
|
||||
M65816_adc, // Add with carry
|
||||
M65816_and, // AND A with memory
|
||||
M65816_asl, // Shift memory or A left
|
||||
M65816_bcc, // Branch if carry clear
|
||||
M65816_bcs, // Branch if carry set
|
||||
M65816_beq, // Branch if equal
|
||||
M65816_bit, // Test memory bits against A
|
||||
M65816_bmi, // Branch if minus
|
||||
M65816_bne, // Branch if not equal
|
||||
M65816_bpl, // Branch if plus
|
||||
M65816_bra, // Branch always
|
||||
M65816_brk, // Software break
|
||||
M65816_brl, // Branch always long
|
||||
M65816_bvc, // Branch if overflow clear
|
||||
M65816_bvs, // Branch if overflow set
|
||||
M65816_clc, // Clear carry flag
|
||||
M65816_cld, // Clear decimal mode flag
|
||||
M65816_cli, // Clear interrupt disable flag
|
||||
M65816_clv, // Clear overflow flag
|
||||
M65816_cmp, // Compare A with memory
|
||||
M65816_cop, // Co-processor enable
|
||||
M65816_cpx, // Compare X with memory
|
||||
M65816_cpy, // Compare Y with memory
|
||||
M65816_dec, // Decrement
|
||||
M65816_dex, // Decrement X
|
||||
M65816_dey, // Decrement Y
|
||||
M65816_eor, // XOR A with M
|
||||
M65816_inc, // Increment
|
||||
M65816_inx, // Increment X
|
||||
M65816_iny, // Increment Y
|
||||
M65816_jml, // Jump long (inter-bank)
|
||||
M65816_jmp, // Jump
|
||||
M65816_jsl, // Jump to subroutine long (inter-bank)
|
||||
M65816_jsr, // Jump to subroutine
|
||||
M65816_lda, // Load A from memory
|
||||
M65816_ldx, // Load X from memory
|
||||
M65816_ldy, // Load Y from memory
|
||||
M65816_lsr, // Logical shift memory or A right
|
||||
M65816_mvn, // Block move next
|
||||
M65816_mvp, // Block move prev
|
||||
M65816_nop, // Nop
|
||||
M65816_ora, // Or A with memory
|
||||
M65816_pea, // Push effective absolute address
|
||||
M65816_pei, // Push effective indirect address
|
||||
M65816_per, // Push effective PC-relative indirect address
|
||||
M65816_pha, // Push A
|
||||
M65816_phb, // Push B (data bank register)
|
||||
M65816_phd, // Push D (direct page register)
|
||||
M65816_phk, // Push K (program bank register)
|
||||
M65816_php, // Push processor status
|
||||
M65816_phx, // Push X
|
||||
M65816_phy, // Push Y
|
||||
M65816_pla, // Pull A
|
||||
M65816_plb, // Pull B
|
||||
M65816_pld, // Pull D
|
||||
M65816_plp, // Pull processor status
|
||||
M65816_plx, // Pull X
|
||||
M65816_ply, // Pull Y
|
||||
M65816_rep, // Reset status bits
|
||||
M65816_rol, // Rotate memory or A left
|
||||
M65816_ror, // Rotate memory or A right
|
||||
M65816_rti, // Return from interrupt
|
||||
M65816_rtl, // Return from subroutine long
|
||||
M65816_rts, // Return from subroutine
|
||||
M65816_sbc, // Subtract with borrow from A
|
||||
M65816_sec, // Set carry flag
|
||||
M65816_sed, // Set decimal mode flag
|
||||
M65816_sei, // Set interrupt disable flag
|
||||
M65816_sep, // Set status bits
|
||||
M65816_sta, // Store A to memory
|
||||
M65816_stp, // Stop processor
|
||||
M65816_stx, // Store X to memory
|
||||
M65816_sty, // Store Y to memory
|
||||
M65816_stz, // Store zero to memory
|
||||
M65816_tax, // Transfer A to X
|
||||
M65816_tay, // Transfer A to Y
|
||||
M65816_tcd, // Transfer 16-bit A to D (direct page register)
|
||||
M65816_tcs, // Transfer A to S
|
||||
M65816_tdc, // Transfer 16-bit D to A
|
||||
M65816_trb, // Test and reset memory bits against A
|
||||
M65816_tsb, // Test and set memory bits against A
|
||||
M65816_tsc, // Transfer S to A
|
||||
M65816_tsx, // Transfer S to X
|
||||
M65816_txa, // Transfer X to A
|
||||
M65816_txs, // Transfer X to S
|
||||
M65816_txy, // Transfer X to Y
|
||||
M65816_tya, // Transfer Y to A
|
||||
M65816_tyx, // Transfer Y to X
|
||||
M65816_wai, // Wait for interrupt
|
||||
M65816_wdm, // Reserved
|
||||
M65816_xba, // Exchange bytes in A
|
||||
M65816_xce, // Exchange carry and emulation bits
|
||||
M65816_last
|
||||
};
|
||||
|
||||
#endif
|
||||
422
idasdk76/module/65816/m65816.cfg
Normal file
422
idasdk76/module/65816/m65816.cfg
Normal file
@@ -0,0 +1,422 @@
|
||||
;; Copied from m7900.cfg
|
||||
; The format of the input file:
|
||||
; each device definition begins with a line like this:
|
||||
;
|
||||
; .devicename
|
||||
;
|
||||
; after it go the port definitions in this format:
|
||||
;
|
||||
; portname address
|
||||
;
|
||||
; the bit definitions (optional) are represented like this:
|
||||
;
|
||||
; portname.bitname bitnumber
|
||||
;
|
||||
; lines beginning with a space are ignored.
|
||||
; comment lines should be started with ';' character.
|
||||
;
|
||||
; the default device is specified at the start of the file
|
||||
;
|
||||
; .default device_name
|
||||
;
|
||||
; all lines non conforming to the format are passed to the callback function
|
||||
;
|
||||
; MITSUBISHI 7900 SPECIFIC LINES
|
||||
;------------------------
|
||||
;
|
||||
; the processor definition may include the memory configuration.
|
||||
; the line format is:
|
||||
|
||||
; area CLASS AREA-NAME START:END
|
||||
;
|
||||
; where CLASS is anything, but please use one of CODE, DATA, BSS
|
||||
; START and END are addresses, the end address is not included
|
||||
|
||||
; Interrupt vectors are declared in the following way:
|
||||
|
||||
; entry NAME ADDRESS COMMENT
|
||||
|
||||
.default snes
|
||||
|
||||
.snes
|
||||
|
||||
; --------------------- PPU Picture Processing Unit (Write-Only Ports)
|
||||
|
||||
INIDISP 0x2100 Display Control 1 (a000bbbb a: 0=screen on 1=screen off, b = brightness)
|
||||
OBSEL 0x2101 Object Size and Object Base (aaabbccc a = Size, b = Name Selection, c = Base Selection)
|
||||
OAMADDL 0x2102 OAM Address (lower 8bit)
|
||||
OAMADDH 0x2103 OAM Address (upper 1bit) and Priority Rotation
|
||||
OAMDATA 0x2104 OAM Data Write (write-twice)
|
||||
BGMODE 0x2105 BG Mode and BG Character Size (abcdefff abcd = BG tile size (4321): 0 = 8x8 1 = 16x16, e = BG 3 High Priority, f = BG Mode)
|
||||
MOSAIC 0x2106 Mosaic Size and Mosaic Enable (aaaabbbb a = Mosaic Size b = Mosaic BG Enable)
|
||||
BG1SC 0x2107 BG1 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG2SC 0x2108 BG2 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG3SC 0x2109 BG3 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG4SC 0x210a BG4 Screen Base and Screen Size (aaaaaabb a = Screen Base Address (Upper 6-bit), b = Screen Size)
|
||||
BG12NBA 0x210b BG Character Data Area Designation (aaaabbbb a = BG 2 Tile Base Address, b = BG 1 Tile Base Address)
|
||||
BG34NBA 0x210c BG Character Data Area Designation (aaaabbbb a = BG 4 Tile Base Address, b = BG 3 Tile Base Address)
|
||||
BG1HOFS 0x210d BG1 Horizontal Scroll (X) (write-twice) / M7HOFS
|
||||
BG1VOFS 0x210e BG1 Vertical Scroll (Y) (write-twice) / M7VOFS
|
||||
BG2HOFS 0x210f BG2 Horizontal Scroll (X) (write-twice)
|
||||
BG2VOFS 0x2110 BG2 Vertical Scroll (Y) (write-twice)
|
||||
BG3HOFS 0x2111 BG3 Horizontal Scroll (X) (write-twice)
|
||||
BG3VOFS 0x2112 BG3 Vertical Scroll (Y) (write-twice)
|
||||
BG4HOFS 0x2113 BG4 Horizontal Scroll (X) (write-twice)
|
||||
BG4VOFS 0x2114 BG4 Vertical Scroll (Y) (write-twice)
|
||||
VMAIN 0x2115 VRAM Address Increment Mode
|
||||
VMADDL 0x2116 VRAM Address (lower 8bit)
|
||||
VMADDH 0x2117 VRAM Address (upper 8bit)
|
||||
VMDATAL 0x2118 VRAM Data Write (lower 8bit)
|
||||
VMDATAH 0x2119 VRAM Data Write (upper 8bit)
|
||||
M7SEL 0x211a Rotation/Scaling Mode Settings (aa0000bc a = Screen Over b = Vertical Flip c = Horizontal Flip)
|
||||
M7A 0x211b Rotation/Scaling Parameter A & Maths 16bit operand
|
||||
M7B 0x211c Rotation/Scaling Parameter B & Maths 8bit operand
|
||||
M7C 0x211d Rotation/Scaling Parameter C (write-twice)
|
||||
M7D 0x211e Rotation/Scaling Parameter D (write-twice)
|
||||
M7X 0x211f Rotation/Scaling Center Coordinate X (write-twice)
|
||||
M7Y 0x2120 Rotation/Scaling Center Coordinate Y (write-twice)
|
||||
CGADD 0x2121 Palette CGRAM Address
|
||||
CGDATA 0x2122 Palette CGRAM Data Write (write-twice)
|
||||
W12SEL 0x2123 Window BG1/BG2 Mask Settings (aaaabbbb a = BG 2 Window Settings b = BG 1 Window Settings)
|
||||
W34SEL 0x2124 Window BG3/BG4 Mask Settings (aaaabbbb a = BG 4 Window Settings b = BG 3 Window Settings)
|
||||
WOBJSEL 0x2125 Window OBJ/MATH Mask Settings (aaaabbbb a = Color Window Settings b = OBJ Window Settings)
|
||||
WH0 0x2126 Window 1 Left Position (X1)
|
||||
WH1 0x2127 Window 1 Right Position (X2)
|
||||
WH2 0x2128 Window 2 Left Position (X1)
|
||||
WH3 0x2129 Window 2 Right Position (X2)
|
||||
WBGLOG 0x212a Window 1/2 Mask Logic (BG1-BG4) (aabbccdd a = Bg4, b = Bg3, c = Bg2, d = Bg1)
|
||||
WOBJLOG 0x212b Window 1/2 Mask Logic (OBJ/MATH) (0000aabb a = Color Window b = OBJ Window)
|
||||
TM 0x212c Main Screen Designation (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
TS 0x212d Sub Screen Designation (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
TMW 0x212e Window Area Main Screen Disable (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
TSW 0x212f Window Area Sub Screen Disable (000abcde a = Object b = Bg4 c = Bg3 d = Bg2 e = Bg1)
|
||||
CGWSEL 0x2130 Color Math Control Register A (aabb00cd a = Main Color Window On/Off, b = Sub Color Window On/Off, c = Fixed Color Add/Subtract Enable, d = Direct Select)
|
||||
CGADSUB 0x2131 Color Math Control Register B (abcdefgh a = 0 for Addition, 1 for Subtraction, b = 1/2 Enable c = Back Enable, d = Object Enable, efgh = Enable Bg 4, 3, 2, 1)
|
||||
COLDATA 0x2132 Color Math Sub Screen Backdrop Color (abcddddd a = Blue b = Green c = Red ddddd = Color Data)
|
||||
SETINI 0x2133 Display Control 2 (ab00cdef a = External Sync, b = ExtBG Mode, c = Pseudo 512 Mode, d = Vertical Size, e = Object-V Select, f = Interlace)
|
||||
|
||||
; --------------------- PPU Picture Processing Unit (Read-Only Ports)
|
||||
|
||||
MPYL 0x2134 PPU1 Signed Multiply Result (lower 8bit)
|
||||
MPYM 0x2135 PPU1 Signed Multiply Result (middle 8bit)
|
||||
MPYH 0x2136 PPU1 Signed Multiply Result (upper 8bit)
|
||||
SLHV 0x2137 PPU1 Latch H/V-Counter by Software (Read=Strobe)
|
||||
RDOAM 0x2138 PPU1 OAM Data Read (read-twice)
|
||||
RDVRAML 0x2139 PPU1 VRAM Data Read (lower 8bits)
|
||||
RDVRAMH 0x213a PPU1 VRAM Data Read (upper 8bits)
|
||||
RDCGRAM 0x213b PPU2 CGRAM Data Read (Palette) (read-twice)
|
||||
OPHCT 0x213c PPU2 Horizontal Counter Latch (read-twice)
|
||||
OPVCT 0x213d PPU2 Vertical Counter Latch (read-twice)
|
||||
STAT77 0x213e PPU1 Status and PPU1 Version Number
|
||||
STAT78 0x213f PPU2 Status and PPU2 Version Number
|
||||
|
||||
; --------------------- APU Audio Processing Unit (R/W)
|
||||
|
||||
APUI00 0x2140 Main CPU to Sound CPU Communication Port 0
|
||||
APUI01 0x2141 Main CPU to Sound CPU Communication Port 1
|
||||
APUI02 0x2142 Main CPU to Sound CPU Communication Port 2
|
||||
APUI03 0x2143 Main CPU to Sound CPU Communication Port 3
|
||||
|
||||
; --------------------- WRAM Access
|
||||
|
||||
WMDATA 0x2180 WRAM Data Read/Write (R/W)
|
||||
WMADDL 0x2181 WRAM Address (lower 8bit) (W)
|
||||
WMADDM 0x2182 WRAM Address (middle 8bit) (W)
|
||||
WMADDH 0x2183 WRAM Address (upper 1bit) (W)
|
||||
|
||||
; --------------------- CPU On-Chip I/O Ports
|
||||
|
||||
JOYA 0x4016 Joypad Input Register A (R) / Joypad Output (W)
|
||||
JOYB 0x4017 Joypad Input Register B (R)
|
||||
|
||||
; --------------------- CPU On-Chip I/O Ports (Write-only) (Read=open bus)
|
||||
|
||||
NMITIMEN 0x4200 Interrupt Enable and Joypad Request (a0bc000d a = NMI b = V-Count c = H-Count d = Joypad)
|
||||
WRIO 0x4201 Joypad Programmable I/O Port (Open-Collector Output)
|
||||
WRMPYA 0x4202 Set unsigned 8bit Multiplicand
|
||||
WRMPYB 0x4203 Set unsigned 8bit Multiplier and Start Multiplication
|
||||
WRDIVL 0x4204 Set unsigned 16bit Dividend (lower 8bit)
|
||||
WRDIVH 0x4205 Set unsigned 16bit Dividend (upper 8bit)
|
||||
WRDIVB 0x4206 Set unsigned 8bit Divisor and Start Division
|
||||
HTIMEL 0x4207 H-Count Timer Setting (lower 8bits)
|
||||
HTIMEH 0x4208 H-Count Timer Setting (upper 1bit)
|
||||
VTIMEL 0x4209 V-Count Timer Setting (lower 8bits)
|
||||
VTIMEH 0x420a V-Count Timer Setting (upper 1bit)
|
||||
MDMAEN 0x420b Select General Purpose DMA Channel(s) and Start Transfer (abcdefgh a = Channel 7...h = Channel 0: 1 = Enable 0 = Disable
|
||||
HDMAEN 0x420c Select H-Blank DMA (H-DMA) Channel(s) (abcdefgh a = Channel 7 .. h = Channel 0: 1 = Enable 0 = Disable
|
||||
MEMSEL 0x420d Memory-2 Waitstate Control (0000000a a: 0 = 2.68 MHz, 1 = 3.58 MHz
|
||||
|
||||
; --------------------- CPU On-Chip I/O Ports (Read-only)
|
||||
|
||||
RDNMI 0x4210 V-Blank NMI Flag and CPU Version Number (Read/Ack)
|
||||
TIMEUP 0x4211 H/V-Timer IRQ Flag (Read/Ack)
|
||||
HVBJOY 0x4212 H/V-Blank flag and Joypad Busy flag (R)
|
||||
RDIO 0x4213 Joypad Programmable I/O Port (Input)
|
||||
RDDIVL 0x4214 Unsigned Division Result (Quotient) (lower 8bit)
|
||||
RDDIVH 0x4215 Unsigned Division Result (Quotient) (upper 8bit)
|
||||
RDMPYL 0x4216 Unsigned Division Remainder / Multiply Product (lower 8bit)
|
||||
RDMPYH 0x4217 Unsigned Division Remainder / Multiply Product (upper 8bit)
|
||||
JOY1L 0x4218 Joypad 1 (gameport 1, pin 4) (lower 8bit) (abcd0000 a = Button A b = X c = L d = R)
|
||||
JOY1H 0x4219 Joypad 1 (gameport 1, pin 4) (upper 8bit) (abcdefgh a = B b = Y c = Select d = Start efgh = Up/Dn/Lt/Rt)
|
||||
JOY2L 0x421a Joypad 2 (gameport 2, pin 4) (lower 8bit)
|
||||
JOY2H 0x421b Joypad 2 (gameport 2, pin 4) (upper 8bit)
|
||||
JOY3L 0x421c Joypad 3 (gameport 1, pin 5) (lower 8bit)
|
||||
JOY3H 0x421d Joypad 3 (gameport 1, pin 5) (upper 8bit)
|
||||
JOY4L 0x421e Joypad 4 (gameport 2, pin 5) (lower 8bit)
|
||||
JOY4H 0x421f Joypad 4 (gameport 2, pin 5) (upper 8bit)
|
||||
|
||||
; --------------------- DMA
|
||||
|
||||
DMAP0 0x4300 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD0 0x4301 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T0L 0x4302 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T0H 0x4303 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B0 0x4304 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS0L 0x4305 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS0H 0x4306 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS00 0x4307 Indirect HDMA Address (bank)
|
||||
A2A0L 0x4308 HDMA Table Current Address (low)
|
||||
A2A0H 0x4309 HDMA Table Current Address (high)
|
||||
NTRL0 0x430a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED0 0x430b Unused byte (read/write-able)
|
||||
MIRR0 0x430f Mirror of 430Bh (R/W)
|
||||
DMAP1 0x4310 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD1 0x4311 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T1L 0x4312 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T1H 0x4313 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B1 0x4314 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS1L 0x4315 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS1H 0x4316 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS10 0x4317 Indirect HDMA Address (bank)
|
||||
A2A1L 0x4318 HDMA Table Current Address (low)
|
||||
A2A1H 0x4319 HDMA Table Current Address (high)
|
||||
NTRL1 0x431a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED1 0x431b Unused byte (read/write-able)
|
||||
MIRR1 0x431f Mirror of 431Bh (R/W)
|
||||
DMAP2 0x4320 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD2 0x4321 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T2L 0x4322 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T2H 0x4323 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B2 0x4324 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS2L 0x4325 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS2H 0x4326 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS20 0x4327 Indirect HDMA Address (bank)
|
||||
A2A2L 0x4328 HDMA Table Current Address (low)
|
||||
A2A2H 0x4329 HDMA Table Current Address (high)
|
||||
NTRL2 0x432a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED2 0x432b Unused byte (read/write-able)
|
||||
MIRR2 0x432f Mirror of 432Bh (R/W)
|
||||
DMAP3 0x4330 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD3 0x4331 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T3L 0x4332 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T3H 0x4333 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B3 0x4334 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS3L 0x4335 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS3H 0x4336 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS30 0x4337 Indirect HDMA Address (bank)
|
||||
A2A3L 0x4338 HDMA Table Current Address (low)
|
||||
A2A3H 0x4339 HDMA Table Current Address (high)
|
||||
NTRL3 0x433a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED3 0x433b Unused byte (read/write-able)
|
||||
MIRR3 0x433f Mirror of 433Bh (R/W)
|
||||
DMAP4 0x4340 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD4 0x4341 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T4L 0x4342 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T4H 0x4343 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B4 0x4344 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS4L 0x4345 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS4H 0x4346 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS40 0x4347 Indirect HDMA Address (bank)
|
||||
A2A4L 0x4348 HDMA Table Current Address (low)
|
||||
A2A4H 0x4349 HDMA Table Current Address (high)
|
||||
NTRL4 0x434a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED4 0x434b Unused byte (read/write-able)
|
||||
MIRR4 0x434f Mirror of 434Bh (R/W)
|
||||
DMAP5 0x4350 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD5 0x4351 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T5L 0x4352 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T5H 0x4353 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B5 0x4354 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS5L 0x4355 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS5H 0x4356 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS50 0x4357 Indirect HDMA Address (bank)
|
||||
A2A5L 0x4358 HDMA Table Current Address (low)
|
||||
A2A5H 0x4359 HDMA Table Current Address (high)
|
||||
NTRL5 0x435a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED5 0x435b Unused byte (read/write-able)
|
||||
MIRR5 0x435f Mirror of 435Bh (R/W)
|
||||
DMAP6 0x4360 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD6 0x4361 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T6L 0x4362 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T6H 0x4363 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B6 0x4364 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS6L 0x4365 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS6H 0x4366 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS60 0x4367 Indirect HDMA Address (bank)
|
||||
A2A6L 0x4368 HDMA Table Current Address (low)
|
||||
A2A6H 0x4369 HDMA Table Current Address (high)
|
||||
NTRL6 0x436a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED6 0x436b Unused byte (read/write-able)
|
||||
MIRR6 0x436f Mirror of 436Bh (R/W)
|
||||
DMAP7 0x4370 DMA/HDMA Parameters (ab0cdeee a = Direction b = Type c = Inc/Dec d = Auto/Fixed e = Word Size Select)
|
||||
BBAD7 0x4371 DMA/HDMA I/O-Bus Address (PPU-Bus aka B-Bus)
|
||||
A1T7L 0x4372 HDMA Table Start Address (low) / DMA Curr Addr (low)
|
||||
A1T7H 0x4373 HDMA Table Start Address (high) / DMA Curr Addr (high)
|
||||
A1B7 0x4374 HDMA Table Start Address (bank) / DMA Curr Addr (bank)
|
||||
DAS7L 0x4375 Indirect HDMA Address (low) / DMA Byte-Counter (low)
|
||||
DAS7H 0x4376 Indirect HDMA Address (high) / DMA Byte-Counter (high)
|
||||
DAS70 0x4377 Indirect HDMA Address (bank)
|
||||
A2A7L 0x4378 HDMA Table Current Address (low)
|
||||
A2A7H 0x4379 HDMA Table Current Address (high)
|
||||
NTRL7 0x437a HDMA Line-Counter (from current Table entry)
|
||||
UNUSED7 0x437b Unused byte (read/write-able)
|
||||
MIRR7 0x437f Mirror of 437Bh (R/W)
|
||||
|
||||
.superfx
|
||||
|
||||
; --------------------- GSU I/O Map
|
||||
|
||||
R0 0x3000 Default source/destination register (Sreg/Dreg) (R/W)
|
||||
R1 0x3002 PLOT opcode: X coordinate (0000h on reset) (R/W)
|
||||
R2 0x3004 PLOT opcode: Y coordinate (0000h on reset) (R/W)
|
||||
R3 0x3006 General purpose (R/W)
|
||||
R4 0x3008 LMULT opcode: lower 16bits of result (R/W)
|
||||
R5 0x300a General purpose (R/W)
|
||||
R6 0x300c LMULT and FMULT opcodes: multiplier (R/W)
|
||||
R7 0x300e MERGE opcode (R/W)
|
||||
R8 0x3010 MERGE opcode (R/W)
|
||||
R9 0x3012 General purpose (R/W)
|
||||
R10 0x3014 General purpose (conventionally stack pointer) (R/W)
|
||||
R11 0x3016 LINK opcode: destination (R/W)
|
||||
R12 0x3018 LOOP opcode: counter (R/W)
|
||||
R13 0x301a LOOP opcode: address (R/W)
|
||||
R14 0x301c GETxx opcodes: Game Pak ROM Address Pointer (R/W)
|
||||
R15 0x301e Program Counter, writing MSB starts GSU operation (R/W)
|
||||
SFR 0x3030 Status/Flag Register (R) (Bit1-5: R/W)
|
||||
BRAMR 0x3033 Back-up RAM Register (W)
|
||||
PBR 0x3034 Program Bank Register (8bit, bank 00h..FFh) (R/W)
|
||||
ROMBR 0x3036 Game Pak ROM Bank Register (8bit, bank 00h..FFh) (R)
|
||||
CFGR 0x3037 Config Register (W)
|
||||
SCBR 0x3038 Screen Base Register (8bit, in 1Kbyte units) (W)
|
||||
CLSR 0x3039 Clock Select Register (W)
|
||||
SCMR 0x303a Screen Mode Register (W)
|
||||
VCR 0x303b Version Code Register (R)
|
||||
RAMBR 0x303c Game Pak RAM Bank Register (1bit, bank 70h/71h) (R)
|
||||
CBR 0x303e Cache Base Register (in upper 12bit; lower 4bit=unused) (R)
|
||||
|
||||
.sa1
|
||||
|
||||
; --------------------- SA-1 I/O Map (Write Only Registers)
|
||||
|
||||
CCNT 0x2200 SA-1 CPU Control (W)
|
||||
SIE 0x2201 SNES CPU Int Enable (W)
|
||||
SIC 0x2202 SNES CPU Int Clear (W)
|
||||
CRV 0x2203 SA-1 CPU Reset Vector Lsb (W)
|
||||
CNVL 0x2205 SA-1 CPU NMI Vector Lsb (W)
|
||||
CNVH 0x2206 SA-1 CPU NMI Vector Msb (W)
|
||||
CIVL 0x2207 SA-1 CPU IRQ Vector Lsb (W)
|
||||
CIVH 0x2208 SA-1 CPU IRQ Vector Msb (W)
|
||||
SCNT 0x2209 SNES CPU Control (W)
|
||||
CIE 0x220a SA-1 CPU Int Enable (W)
|
||||
CIC 0x220b SA-1 CPU Int Clear (W)
|
||||
SNVL 0x220c SNES CPU NMI Vector Lsb (W)
|
||||
SNVH 0x220d SNES CPU NMI Vector Msb (W)
|
||||
SIVL 0x220e SNES CPU IRQ Vector Lsb (W)
|
||||
SIVH 0x220f SNES CPU IRQ Vector Msb (W)
|
||||
TMC 0x2210 H/V Timer Control (W)
|
||||
CTR 0x2211 SA-1 CPU Timer Restart (W)
|
||||
HCNTL 0x2212 Set H-Count Lsb (W)
|
||||
HCNTH 0x2213 Set H-Count Msb (W)
|
||||
VCNTL 0x2214 Set V-Count Lsb (W)
|
||||
VCNTH 0x2215 Set V-Count Msb (W)
|
||||
CXB 0x2220 MMC Bank C - Hirom C0h-CFh / LoRom 00h-1Fh (W)
|
||||
DXB 0x2221 MMC Bank D - Hirom D0h-DFh / LoRom 20h-3Fh (W)
|
||||
EXB 0x2222 MMC Bank E - Hirom E0h-EFh / LoRom 80h-9Fh (W)
|
||||
FXB 0x2223 MMC Bank F - Hirom F0h-FFh / LoRom A0h-BFh (W)
|
||||
BMAPS 0x2224 SNES CPU BW-RAM Mapping to 6000h-7FFFh (W)
|
||||
BMAP 0x2225 SA-1 CPU BW-RAM Mapping to 6000h-7FFFh (W)
|
||||
SBWE 0x2226 SNES CPU BW-RAM Write Enable (W)
|
||||
CBWE 0x2227 SA-1 CPU BW-RAM Write Enable (W)
|
||||
BWPA 0x2228 BW-RAM Write-Protected Area (W)
|
||||
SIWP 0x2229 SNES I-RAM Write-Protection (W)
|
||||
CIWP 0x222a SA-1 I-RAM Write-Protection (W)
|
||||
DCNT 0x2230 DMA Control (W)
|
||||
CDMA 0x2231 Character Conversion DMA Parameters (W)
|
||||
SDAL 0x2232 DMA Source Device Start Address Lsb (W)
|
||||
SDAM 0x2233 DMA Source Device Start Address Mid (W)
|
||||
SDAH 0x2234 DMA Source Device Start Address Msb (W)
|
||||
DDAL 0x2235 DMA Dest Device Start Address Lsb (W)
|
||||
DDAM 0x2236 DMA Dest Device Start Address Mid (Start/I-RAM) (W)
|
||||
DDAH 0x2237 DMA Dest Device Start Address Msb (Start/BW-RAM)(W)
|
||||
DTCL 0x2238 DMA Terminal Counter Lsb (W)
|
||||
DTCH 0x2239 DMA Terminal Counter Msb (W)
|
||||
BBF 0x223f BW-RAM Bit Map Format for 600000h-6FFFFFh (W)
|
||||
BRF0 0x2240 Bit Map Register File (W)
|
||||
BRF1 0x2241 Bit Map Register File (W)
|
||||
BRF2 0x2242 Bit Map Register File (W)
|
||||
BRF3 0x2243 Bit Map Register File (W)
|
||||
BRF4 0x2244 Bit Map Register File (W)
|
||||
BRF5 0x2245 Bit Map Register File (W)
|
||||
BRF6 0x2246 Bit Map Register File (W)
|
||||
BRF7 0x2247 Bit Map Register File (W)
|
||||
BRF8 0x2248 Bit Map Register File (W)
|
||||
BRF9 0x2249 Bit Map Register File (W)
|
||||
BRFA 0x224a Bit Map Register File (W)
|
||||
BRFB 0x224b Bit Map Register File (W)
|
||||
BRFC 0x224c Bit Map Register File (W)
|
||||
BRFD 0x224d Bit Map Register File (W)
|
||||
BRFE 0x224e Bit Map Register File (W)
|
||||
BRFF 0x224f Bit Map Register File (W)
|
||||
MCNT 0x2250 Arithmetic Control (W)
|
||||
MAL 0x2251 Arithmetic Param A Lsb (Multiplicand/Dividend) (W)
|
||||
MAH 0x2252 Arithmetic Param A Msb (Multiplicand/Dividend) (W)
|
||||
MBL 0x2253 Arithmetic Param B Lsb (Multiplier/Divisor) (W)
|
||||
MBH 0x2254 Arithmetic Param B Msb (Multiplier/Divisor)/Start (W)
|
||||
VBD 0x2258 Variable-Length Bit Processing (W)
|
||||
VDAL 0x2259 Var-Length Bit Game Pak ROM Start Address Lsb (W)
|
||||
VDAM 0x225a Var-Length Bit Game Pak ROM Start Address Mid (W)
|
||||
VDAH 0x225b Var-Length Bit Game Pak ROM Start Address Msb & Kick
|
||||
|
||||
; --------------------- SA-1 I/O Map (Read Only Registers)
|
||||
|
||||
SFR 0x2300 SNES CPU Flag Read (R)
|
||||
CFR 0x2301 SA-1 CPU Flag Read (R)
|
||||
HCRL 0x2302 H-Count Read Lsb / Do Latching (R)
|
||||
HCRH 0x2303 H-Count Read Msb (R)
|
||||
VCRL 0x2304 V-Count Read Lsb (R)
|
||||
VCRH 0x2305 V-Count Read Msb (R)
|
||||
MRAL 0x2306 Arithmetic Result, bit0-7 (Sum/Product/Quotient) (R)
|
||||
MRAH 0x2307 Arithmetic Result, bit8-15 (Sum/Product/Quotient) (R)
|
||||
MRBL 0x2308 Arithmetic Result, bit16-23 (Sum/Product/Remainder) (R)
|
||||
MRBH 0x2309 Arithmetic Result, bit24-31 (Sum/Product/Remainder) (R)
|
||||
MRC 0x230a Arithmetic Result, bit32-39 (Sum) (R)
|
||||
OF 0x230b Arithmetic Overflow Flag (R)
|
||||
VDPL 0x230c Variable-Length Data Read Port Lsb (R)
|
||||
VDPH 0x230d Variable-Length Data Read Port Msb (R)
|
||||
VC 0x230e Version Code Register (R)
|
||||
|
||||
.cx4
|
||||
|
||||
.spc7110
|
||||
|
||||
.sdd1
|
||||
|
||||
.sharprtc
|
||||
|
||||
.epsonrtc
|
||||
|
||||
.obc1
|
||||
|
||||
.dsp1
|
||||
|
||||
.dsp2
|
||||
|
||||
.dsp3
|
||||
|
||||
.dsp4
|
||||
|
||||
.st010
|
||||
|
||||
.st011
|
||||
|
||||
.st018
|
||||
263
idasdk76/module/65816/m65816.hpp
Normal file
263
idasdk76/module/65816/m65816.hpp
Normal file
@@ -0,0 +1,263 @@
|
||||
|
||||
#ifndef __M65816_HPP__
|
||||
#define __M65816_HPP__
|
||||
|
||||
#include "../../module/idaidp.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
#define PROCMOD_NAME m65816
|
||||
#define PROCMOD_NODE_NAME "$ " QSTRINGIZE(PROCMOD_NAME)
|
||||
|
||||
// Direct Memory Reference with full-length address
|
||||
#define o_mem_far o_idpspec0
|
||||
|
||||
// If there is an address in 'Op[N].full_target_ea',
|
||||
// it means the target address of a branch/jump
|
||||
// is already known. That's there to help the 'emu'
|
||||
// module propagate M&X flags & status.
|
||||
#define full_target_ea specval
|
||||
|
||||
|
||||
// Is indirect memory reference?
|
||||
#define indirect segpref
|
||||
|
||||
// These defines are used by some 6502 asm_t descriptors.
|
||||
// Although this is primarily a 65816 module, they'll
|
||||
// remain here since at some point, this CPU module /might/
|
||||
// supersede the 6502 one.
|
||||
// Should that happen, we wouldn't want to waste the
|
||||
// set of asm_t's that are defined for 6502.
|
||||
#define UAS_SECT 0x0002 // Segments are named .SECTION
|
||||
#define UAS_NOSEG 0x0004 // No 'segment' directives
|
||||
#define UAS_SELSG 0x0010 // Segment should be selected by its name
|
||||
#define UAS_CDSEG 0x0080 // Only DSEG,CSEG,XSEG
|
||||
#define UAS_NOENS 0x0200 // don't specify start addr in the .end directive
|
||||
|
||||
|
||||
enum M65816_registers
|
||||
{
|
||||
rA, // Accumulator
|
||||
rX, // X index
|
||||
rY, // Y index
|
||||
rS, // Stack
|
||||
rCs, // code segment
|
||||
rDs, // data segment
|
||||
|
||||
// This will hold the value of B, the
|
||||
// data bank register. We won't make use of Ds
|
||||
// directly, as it is typically used, in computation,
|
||||
// as a 16-byte paragraph register, while B is a
|
||||
// 64KB pages register. Also, by having a dedicated
|
||||
// B, the user will be able to modify it more
|
||||
// easily (without having to manually shift the value by
|
||||
// 12 bits).
|
||||
// Note: Also, we won't have this register ``mapped'' to a sel_t.
|
||||
// We'll stuff the B value in there directly, which allows
|
||||
// it to be more versatile, and access banks where there's
|
||||
// no ROM loaded (such as [S|W]RAM bank(s)).
|
||||
rB,
|
||||
|
||||
// Direct page register. Same note as that of rB applies.
|
||||
rD,
|
||||
|
||||
// These will be considered segment
|
||||
// registers by IDA (just as rCs, rDs, rB and rD),
|
||||
// but we'll actually use them to keep information
|
||||
// about the 'm', 'x' and 'e' flags, determining
|
||||
// what's the accumulator & indices mode, and whether
|
||||
// we run in 6502 emulation or 65816 native mode.
|
||||
rFm,
|
||||
rFx,
|
||||
rFe,
|
||||
|
||||
// program bank register
|
||||
rPB
|
||||
};
|
||||
|
||||
|
||||
// Addressing modes
|
||||
enum m65_addrmode_t
|
||||
{
|
||||
ABS = 0,
|
||||
ABS_IX,
|
||||
ABS_IY,
|
||||
ABS_IX_INDIR,
|
||||
ABS_INDIR,
|
||||
ABS_INDIR_LONG,
|
||||
ABS_LONG,
|
||||
ABS_LONG_IX,
|
||||
ACC,
|
||||
BLK_MOV,
|
||||
DP,
|
||||
DP_IX,
|
||||
DP_IY,
|
||||
DP_IX_INDIR,
|
||||
DP_INDIR,
|
||||
DP_INDIR_LONG,
|
||||
DP_INDIR_IY,
|
||||
DP_INDIR_LONG_IY,
|
||||
IMM,
|
||||
IMPLIED,
|
||||
PC_REL,
|
||||
PC_REL_LONG,
|
||||
STACK_ABS,
|
||||
STACK_DP_INDIR,
|
||||
STACK_INT,
|
||||
STACK_PC_REL,
|
||||
STACK_PULL,
|
||||
STACK_PUSH,
|
||||
STACK_RTI,
|
||||
STACK_RTL,
|
||||
STACK_RTS,
|
||||
STACK_REL,
|
||||
STACK_REL_INDIR_IY,
|
||||
ADDRMODE_last
|
||||
};
|
||||
|
||||
// The various phrases that can be used in case
|
||||
// an operand is of type 'o_displ'.
|
||||
enum odispl_phrases_t
|
||||
{
|
||||
rDX = 100, // "dp, X" DP_IX
|
||||
rDY, // "dp, Y" DP_IY
|
||||
riDX, // "(dp, X)" DP_IX_INDIR
|
||||
rAbsi, // "(abs)" ABS_INDIR
|
||||
rAbsiL, // "long(abs)" ABS_INDIR_LONG
|
||||
rAbsX, // "abs, X" ABS_IX
|
||||
rAbsY, // "abs, Y" ABS_IY
|
||||
rAbsLX, // "long abs, X" ABS_LONG_IX
|
||||
rAbsXi, // "(abs,X)" ABS_IX_INDIR
|
||||
rDi, // "(dp,n)" DP_INDIR
|
||||
rDiL, // "long(dp,n)" DP_INDIR_LONG
|
||||
rDiY, // "(dp,n), Y" DP_INDIR_IY
|
||||
rDiLY, // "long(dp,n), Y" DP_INDIR_LONG_IY
|
||||
rSiY, // (s,n),Y STACK_REL_INDIR_IY
|
||||
rSDi // "(dp,n)" STACK_DP_INDIR
|
||||
};
|
||||
|
||||
|
||||
// Information about addressing modes.
|
||||
struct addrmode_info_t
|
||||
{
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern const struct addrmode_info_t AddressingModes[];
|
||||
|
||||
|
||||
// The type of m65* processors. Used
|
||||
// to declare availability of certain opcodes depending
|
||||
// on the processor.
|
||||
enum m65_variant_t
|
||||
{
|
||||
M6502 = 1,
|
||||
M65C02 = 2,
|
||||
M65802 = 4,
|
||||
M65816 = 8,
|
||||
M6X = 1 | 2 | 4 | 8
|
||||
};
|
||||
|
||||
|
||||
// Special flags, for certain opcodes
|
||||
enum opcode_flags_t
|
||||
{
|
||||
// Increment instruction's byte count
|
||||
// if accumulator is in 16-bits mode.
|
||||
ACC16_INCBC = 1,
|
||||
|
||||
// Increment instruction's byte count
|
||||
// if X/Y registers are in 16-bits mode.
|
||||
XY16_INCBC = 2
|
||||
};
|
||||
|
||||
// Information about an opcode
|
||||
struct opcode_info_t
|
||||
{
|
||||
m65_itype_t itype;
|
||||
m65_addrmode_t addr;
|
||||
uint8 cpu_variants; // OR'd m65_variant_t
|
||||
uint16 flags; // OR'd opcode_flags_t
|
||||
};
|
||||
|
||||
inline bool is_acc_16_bits(ea_t ea) { return (get_sreg(ea, rFm) == 0); }
|
||||
inline bool is_xy_16_bits(ea_t ea) { return (get_sreg(ea, rFx) == 0); }
|
||||
inline bool is_acc_16_bits(const insn_t &insn) { return is_acc_16_bits(insn.ea); }
|
||||
inline bool is_xy_16_bits(const insn_t &insn) { return is_xy_16_bits(insn.ea); }
|
||||
|
||||
const struct opcode_info_t &get_opcode_info(uint8 opcode);
|
||||
|
||||
// Determines whether an m65_itype_t is of type 'push'
|
||||
#define M65_ITYPE_PUSH(op) \
|
||||
(((op) == M65816_pea) \
|
||||
|| ((op) == M65816_pei) \
|
||||
|| ((op) == M65816_per) \
|
||||
|| ((op) == M65816_pha) \
|
||||
|| ((op) == M65816_phb) \
|
||||
|| ((op) == M65816_phd) \
|
||||
|| ((op) == M65816_phk) \
|
||||
|| ((op) == M65816_php) \
|
||||
|| ((op) == M65816_phx) \
|
||||
|| ((op) == M65816_phy))
|
||||
|
||||
// Determines whether an m65_itype_t is of type 'pull'
|
||||
#define M65_ITYPE_PULL(op) \
|
||||
(((op) == M65816_pla) \
|
||||
|| ((op) == M65816_plb) \
|
||||
|| ((op) == M65816_pld) \
|
||||
|| ((op) == M65816_plp) \
|
||||
|| ((op) == M65816_plx) \
|
||||
|| ((op) == M65816_ply))
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi ana(insn_t *_insn);
|
||||
int idaapi emu(const insn_t &insn);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class snes_addr_t;
|
||||
|
||||
struct m65816_iohandler_t : public iohandler_t
|
||||
{
|
||||
m65816_iohandler_t(netnode &nn) : iohandler_t(nn) {}
|
||||
|
||||
virtual bool check_ioresp() const override
|
||||
{
|
||||
if ( inf_like_binary() )
|
||||
return true;
|
||||
else
|
||||
return get_segm_by_name("ppu") != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(idb_listener_t, struct m65816_t);
|
||||
|
||||
struct m65816_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
m65816_iohandler_t ioh = m65816_iohandler_t(helper);
|
||||
idb_listener_t idb_listener = idb_listener_t(*this);
|
||||
struct SuperFamicomCartridge *cartridge = nullptr;
|
||||
snes_addr_t *sa = nullptr;
|
||||
bool flow = false;
|
||||
|
||||
m65816_t();
|
||||
~m65816_t();
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
ea_t xlat(ea_t address);
|
||||
|
||||
void handle_operand(const op_t &x, bool read_access, const insn_t &insn);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void m65816_assumes(outctx_t &ctx);
|
||||
ea_t calc_addr(const op_t &x, ea_t *orig_ea, const insn_t &insn);
|
||||
void m65816_header(outctx_t &ctx) const;
|
||||
void m65816_segstart(outctx_t &ctx, segment_t *Srange) const;
|
||||
void m65816_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
#endif
|
||||
75
idasdk76/module/65816/makefile
Normal file
75
idasdk76/module/65816/makefile
Normal file
@@ -0,0 +1,75 @@
|
||||
PROC=m65816
|
||||
CONFIGS=m65816.cfg
|
||||
O1=bt
|
||||
|
||||
|
||||
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)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp ana.cpp ins.hpp \
|
||||
m65816.hpp
|
||||
$(F)bt$(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)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp bt.cpp bt.hpp \
|
||||
ins.hpp m65816.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp bt.hpp emu.cpp \
|
||||
ins.hpp m65816.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)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp ins.cpp ins.hpp \
|
||||
m65816.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)ieee.h $(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 \
|
||||
../../module/idaidp.hpp ../iohandler.hpp bt.hpp ins.hpp \
|
||||
m65816.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)ieee.h $(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 \
|
||||
../../ldr/snes/addr.cpp ../../ldr/snes/super-famicom.hpp \
|
||||
../../module/idaidp.hpp ../iohandler.hpp ins.hpp \
|
||||
m65816.hpp reg.cpp
|
||||
473
idasdk76/module/65816/out.cpp
Normal file
473
idasdk76/module/65816/out.cpp
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Version 3.05
|
||||
* Copyright (c) 1990-95 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* FIDO: 2:5020/209
|
||||
* E-mail: ig@estar.msk.su
|
||||
*
|
||||
*/
|
||||
|
||||
#include "m65816.hpp"
|
||||
#include "bt.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_m65816_t : public outctx_t
|
||||
{
|
||||
out_m65816_t(void) = delete; // not used
|
||||
m65816_t &pm() { return *static_cast<m65816_t *>(procmod); }
|
||||
public:
|
||||
void out_dp(const op_t &x);
|
||||
void out_addr_near_b(const op_t &x);
|
||||
void out_addr_near(const op_t &x);
|
||||
void out_addr_far(const op_t &x);
|
||||
void print_orig_ea(const op_t &x);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_m65816_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_m65816_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_dp(const op_t &x)
|
||||
{
|
||||
sel_t dp = get_sreg(insn.ea, rD);
|
||||
if ( dp != BADSEL )
|
||||
{
|
||||
ea_t orig_ea = dp + x.addr;
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_addr_near_b(const op_t &x)
|
||||
{
|
||||
sel_t db = get_sreg(insn.ea, rB);
|
||||
if ( db != BADSEL )
|
||||
{
|
||||
ea_t orig_ea = (db << 16) + x.addr;
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_16);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void out_m65816_t::out_addr_near(const op_t &x)
|
||||
{
|
||||
ea_t orig_ea = map_code_ea(insn, x);
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_addr_far(const op_t &x)
|
||||
{
|
||||
ea_t orig_ea = x.addr;
|
||||
ea_t ea = pm().xlat(orig_ea);
|
||||
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_24);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::print_orig_ea(const op_t &x)
|
||||
{
|
||||
if ( !has_cmt(F) )
|
||||
{
|
||||
char buf[64];
|
||||
qsnprintf(buf, sizeof(buf),
|
||||
COLSTR(" %s orig=0x%0*a", SCOLOR_AUTOCMT),
|
||||
ash.cmnt,
|
||||
(x.type == o_far || x.type == o_mem_far) ? 6 : 4,
|
||||
x.addr);
|
||||
out_line(buf);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t m65816_t::calc_addr(const op_t &x, ea_t *orig_ea, const insn_t &insn)
|
||||
{
|
||||
ea_t ea;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_near:
|
||||
ea = map_code_ea(insn, x);
|
||||
goto XLAT_ADDR;
|
||||
case o_far:
|
||||
case o_mem_far:
|
||||
ea = x.addr;
|
||||
goto XLAT_ADDR;
|
||||
case o_mem:
|
||||
ea = map_data_ea(insn, x);
|
||||
XLAT_ADDR:
|
||||
if ( orig_ea != NULL )
|
||||
*orig_ea = ea;
|
||||
return xlat(ea);
|
||||
default:
|
||||
INTERR(559);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_m65816_t::out_operand(const op_t &x)
|
||||
{
|
||||
ea_t ea, orig_ea;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
break;
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, 0);
|
||||
break;
|
||||
case o_near:
|
||||
case o_far:
|
||||
if ( insn.indirect )
|
||||
out_symbol('(');
|
||||
ea = pm().calc_addr(x, &orig_ea, insn);
|
||||
if ( !out_name_expr(x, ea, BADADDR) )
|
||||
{
|
||||
uint32 v = x.addr;
|
||||
if ( x.type == o_far )
|
||||
v &= 0xFFFFFF;
|
||||
else
|
||||
v &= 0xFFFF;
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(v, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
if ( insn.indirect )
|
||||
out_symbol(')');
|
||||
if ( orig_ea != ea )
|
||||
print_orig_ea(x);
|
||||
break;
|
||||
case o_mem:
|
||||
case o_mem_far:
|
||||
{
|
||||
if ( insn.indirect )
|
||||
out_symbol('(');
|
||||
|
||||
if ( x.type == o_mem_far )
|
||||
{
|
||||
ea = pm().calc_addr(x, &orig_ea, insn);
|
||||
out_addr_far(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
sel_t db = get_sreg(insn.ea, rB);
|
||||
if ( db == BADSEL )
|
||||
ea = orig_ea = x.addr;
|
||||
else
|
||||
ea = pm().calc_addr(x, &orig_ea, insn);
|
||||
out_addr_near_b(x);
|
||||
}
|
||||
|
||||
if ( insn.indirect )
|
||||
out_symbol(')');
|
||||
|
||||
if ( orig_ea != ea )
|
||||
print_orig_ea(x);
|
||||
}
|
||||
break;
|
||||
case o_displ:
|
||||
switch ( x.phrase )
|
||||
{
|
||||
case rS:
|
||||
out_register(ph.reg_names[x.phrase]);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
break;
|
||||
case rD:
|
||||
out_register(ph.reg_names[x.phrase]);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
break;
|
||||
case rSiY:
|
||||
out_symbol('(');
|
||||
out_register("S");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_value(x, OOF_ADDR|OOFS_NOSIGN|OOFW_8);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("Y");
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rDi:
|
||||
case rSDi:
|
||||
out_symbol('(');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rDiL:
|
||||
out_symbol('[');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(']');
|
||||
break;
|
||||
case rDX:
|
||||
case rDY:
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register((x.phrase == rDX) ? "X" : "Y");
|
||||
break;
|
||||
case riDX:
|
||||
out_symbol('(');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("X");
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rDiY:
|
||||
case rDiLY:
|
||||
out_symbol(x.phrase == rDiLY ? '[' : '(');
|
||||
out_register("D");
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_dp(x);
|
||||
out_symbol(x.phrase == rDiLY ? ']' : ')');
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("Y");
|
||||
break;
|
||||
case rAbsi:
|
||||
out_symbol('(');
|
||||
out_addr_near_b(x);
|
||||
out_symbol(')');
|
||||
break;
|
||||
case rAbsiL:
|
||||
out_symbol('[');
|
||||
out_addr_near_b(x);
|
||||
out_symbol(']');
|
||||
break;
|
||||
case rAbsX:
|
||||
case rAbsY:
|
||||
out_addr_near_b(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register(x.phrase == rAbsY ? "Y" : "X");
|
||||
break;
|
||||
case rAbsLX:
|
||||
{
|
||||
ea_t lorig_ea = x.addr;
|
||||
ea_t lea = pm().xlat(lorig_ea);
|
||||
|
||||
out_addr_far(x);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("X");
|
||||
|
||||
if ( lorig_ea != lea )
|
||||
print_orig_ea(x);
|
||||
}
|
||||
break;
|
||||
case rAbsXi:
|
||||
out_symbol('(');
|
||||
out_addr_near(x); // jmp, jsr
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_register("X");
|
||||
out_symbol(')');
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case o_void:
|
||||
return 0;
|
||||
default:
|
||||
err:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool forced_print(flags_t F, int reg)
|
||||
{
|
||||
return (reg == rFm || reg == rFx) && is_func(F);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
void m65816_t::m65816_assumes(outctx_t &ctx)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
char buf[MAXSTR];
|
||||
char *ptr = buf;
|
||||
char *end = buf + sizeof(buf);
|
||||
segment_t *seg = getseg(ea);
|
||||
bool seg_started = (ea == seg->start_ea);
|
||||
for ( int reg=ph.reg_first_sreg; reg <= ph.reg_last_sreg; reg++ )
|
||||
{
|
||||
if ( reg == rCs )
|
||||
continue;
|
||||
sreg_range_t srrange;
|
||||
if ( !get_sreg_range(&srrange, ea, reg) )
|
||||
continue;
|
||||
sel_t curval = srrange.val;
|
||||
if ( seg_started || srrange.start_ea == ea )
|
||||
{
|
||||
sreg_range_t prev;
|
||||
bool prev_exists = get_sreg_range(&prev, ea - 1, reg);
|
||||
if ( seg_started
|
||||
|| (prev_exists && prev.val != curval)
|
||||
|| forced_print(ctx.F, reg) )
|
||||
{
|
||||
if ( reg == rFm || reg == rFx )
|
||||
{
|
||||
ctx.gen_printf(0, ".%c%d", reg == rFm ? 'A' : 'I', curval > 0 ? 8 : 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ptr != buf )
|
||||
APPCHAR(ptr, end, ' ');
|
||||
ptr += qsnprintf(ptr, end-ptr, "%s=%a", ph.reg_names[reg], curval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ptr != buf )
|
||||
ctx.gen_cmt_line("%s", buf);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_m65816_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void m65816_t::m65816_header(outctx_t &ctx) const
|
||||
{
|
||||
ctx.gen_cmt_line("%s Processor: %s", ash.cmnt, inf_get_procname().c_str());
|
||||
ctx.gen_cmt_line("%s Target assembler: %s", ash.cmnt, ash.name);
|
||||
if ( ash.header != NULL )
|
||||
for ( const char *const *ptr=ash.header; *ptr != NULL; ptr++ )
|
||||
ctx.flush_buf(*ptr,0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Srange) could be made const
|
||||
void m65816_t::m65816_segstart(outctx_t &ctx, segment_t *Srange) const
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, Srange);
|
||||
if ( ash.uflag & UAS_SECT )
|
||||
{
|
||||
ctx.gen_printf(0, COLSTR("%s: .section",SCOLOR_ASMDIR), name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s.segment %s",SCOLOR_ASMDIR),
|
||||
(ash.uflag & UAS_NOSEG) ? ash.cmnt : "",
|
||||
name.c_str());
|
||||
if ( ash.uflag & UAS_SELSG )
|
||||
ctx.flush_buf(name.c_str(), DEFAULT_INDENT);
|
||||
if ( ash.uflag & UAS_CDSEG )
|
||||
ctx.flush_buf(COLSTR("CSEG",SCOLOR_ASMDIR), DEFAULT_INDENT); // XSEG - eXternal memory
|
||||
}
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Srange);
|
||||
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 m65816_t::m65816_footer(outctx_t &ctx) const
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
char *ptr = buf;
|
||||
char *end = buf + sizeof(buf);
|
||||
APPEND(ptr, end, ash.end);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
if ( ash.uflag & UAS_NOENS )
|
||||
APPEND(ptr, end, ash.cmnt);
|
||||
APPCHAR(ptr, end, ' ');
|
||||
APPEND(ptr, end, name.begin());
|
||||
}
|
||||
ctx.flush_buf(buf, DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
705
idasdk76/module/65816/reg.cpp
Normal file
705
idasdk76/module/65816/reg.cpp
Normal file
@@ -0,0 +1,705 @@
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
|
||||
#include "m65816.hpp"
|
||||
int data_id;
|
||||
|
||||
#include "../../ldr/snes/addr.cpp"
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"A", // Accumulator
|
||||
"X", // Index
|
||||
"Y", // Index
|
||||
"S", // Stack register (used?)
|
||||
"cs",
|
||||
"ds",
|
||||
|
||||
"B", // Data bank
|
||||
"D", // Direct page register (used?)
|
||||
|
||||
"m", // Holds accumulator-is-8-bits flag
|
||||
"x", // Holds indices-are-8-bits flag
|
||||
"e", // Holds emulation mode flag
|
||||
|
||||
"PB" // Program bank
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
ea_t m65816_t::xlat(ea_t address)
|
||||
{
|
||||
return sa->xlat(address);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
m65816_t::m65816_t()
|
||||
{
|
||||
cartridge = new SuperFamicomCartridge;
|
||||
sa = new snes_addr_t;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
m65816_t::~m65816_t()
|
||||
{
|
||||
delete cartridge;
|
||||
cartridge = nullptr;
|
||||
delete sa;
|
||||
sa = nullptr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handler for: get_autocmt.
|
||||
// Will possibly store a comment in 'buf',
|
||||
// depending on whether an autocmt is deemed necessary
|
||||
// for the current line.
|
||||
//
|
||||
// For the moment this will just print, in a user-friendly
|
||||
// way, information about the addressing mode, if needed.
|
||||
static bool make_insn_cmt(qstring *buf, const insn_t &insn)
|
||||
{
|
||||
uint8 opcode = get_byte(insn.ea);
|
||||
const struct opcode_info_t &opcode_info = get_opcode_info(opcode);
|
||||
static const bool addressing_info_required[] =
|
||||
{
|
||||
false, // ABS
|
||||
false, // ABS_IX,
|
||||
false, // ABS_IY,
|
||||
false, // ABS_IX_INDIR,
|
||||
false, // ABS_INDIR,
|
||||
false, // ABS_INDIR_LONG,
|
||||
false, // ABS_LONG,
|
||||
false, // ABS_LONG_IX,
|
||||
false, // ACC,
|
||||
true, // BLK_MOV,
|
||||
false, // DP,
|
||||
false, // DP_IX,
|
||||
false, // DP_IY,
|
||||
false, // DP_IX_INDIR,
|
||||
false, // DP_INDIR,
|
||||
false, // DP_INDIR_LONG,
|
||||
false, // DP_INDIR_IY,
|
||||
false, // DP_INDIR_LONG_IY,
|
||||
false, // IMM,
|
||||
false, // IMPLIED,
|
||||
true, // PC_REL,
|
||||
true, // PC_REL_LONG,
|
||||
false, // STACK_ABS,
|
||||
false, // STACK_DP_INDIR,
|
||||
false, // STACK_INT,
|
||||
false, // STACK_PC_REL,
|
||||
false, // STACK_PULL,
|
||||
false, // STACK_PUSH,
|
||||
false, // STACK_RTI,
|
||||
false, // STACK_RTL,
|
||||
false, // STACK_RTS,
|
||||
false, // STACK_REL,
|
||||
false // STACK_REL_INDIR_IY,
|
||||
};
|
||||
|
||||
if ( !addressing_info_required[opcode_info.addr] )
|
||||
return false;
|
||||
|
||||
const struct addrmode_info_t &addrmode_info = AddressingModes[opcode_info.addr];
|
||||
*buf = addrmode_info.name;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case idb_event::sgr_changed:
|
||||
{
|
||||
ea_t start_ea = va_arg(va, ea_t);
|
||||
ea_t dummy = va_arg(va, ea_t); qnotused(dummy);
|
||||
int regnum = va_arg(va, int);
|
||||
sel_t value = va_arg(va, sel_t);
|
||||
if ( regnum == rB )
|
||||
{
|
||||
// sel_t d2 = va_arg(va, sel_t); qnotused(d2);
|
||||
if ( value == BADSEL )
|
||||
split_sreg_range(start_ea, rDs, BADSEL, SR_auto);
|
||||
else
|
||||
split_sreg_range(start_ea, rDs, value << 12, SR_auto);
|
||||
}
|
||||
else if ( regnum == rPB )
|
||||
{
|
||||
uint16 offset = start_ea & 0xffff;
|
||||
ea_t newEA = pm.xlat((value << 16) + offset);
|
||||
if ( start_ea != newEA )
|
||||
warning("Inconsistent program bank number ($%02X:%04X != $%02X:%04X)",
|
||||
uint32(start_ea >> 16),
|
||||
offset,
|
||||
uint8(value),
|
||||
offset);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void m65816_t::load_from_idb()
|
||||
{
|
||||
cartridge->read_hash(helper);
|
||||
//cartridge.print();
|
||||
if ( !sa->addr_init(*cartridge) )
|
||||
warning("Unsupported mapper: %s", cartridge->mapper_string());
|
||||
ioh.restore_device(IORESP_NONE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(m65816_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi m65816_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int retcode = 1;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
case processor_t::ev_term:
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
case processor_t::ev_newprc:
|
||||
break;
|
||||
case processor_t::ev_creating_segm:
|
||||
{
|
||||
segment_t *sptr = va_arg(va, segment_t *);
|
||||
|
||||
// default DS is equal to CS
|
||||
sptr->defsr[rDs - ph.reg_first_sreg] = sptr->sel;
|
||||
|
||||
// detect SNES bank 0
|
||||
if ( xlat(0) == (sptr->start_ea & 0xff0000) )
|
||||
{
|
||||
// initial bank must be $00 (especially important on HiROM)
|
||||
// Example: Donkey Kong Country 2 - Emulation_mode_RESET
|
||||
sptr->defsr[rB - ph.reg_first_sreg] = 0;
|
||||
sptr->defsr[rPB - ph.reg_first_sreg] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, set the default bank number from EA
|
||||
uint8 pb = sptr->start_ea >> 16;
|
||||
sptr->defsr[rB - ph.reg_first_sreg] = pb;
|
||||
sptr->defsr[rPB - ph.reg_first_sreg] = pb;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
cartridge->read_hash(helper);
|
||||
//cartridge.print();
|
||||
if ( !sa->addr_init(*cartridge) )
|
||||
warning("Unsupported mapper: %s", cartridge->mapper_string());
|
||||
|
||||
const char *device_ptr = nullptr;
|
||||
if ( cartridge->has_superfx )
|
||||
device_ptr = "superfx";
|
||||
else if ( cartridge->has_sa1 )
|
||||
device_ptr = "sa1";
|
||||
else if ( cartridge->has_cx4 )
|
||||
device_ptr = "cx4";
|
||||
else if ( cartridge->has_spc7110 )
|
||||
device_ptr = "spc7110";
|
||||
else if ( cartridge->has_sdd1 )
|
||||
device_ptr = "sdd1";
|
||||
else if ( cartridge->has_sharprtc )
|
||||
device_ptr = "sharprtc";
|
||||
else if ( cartridge->has_epsonrtc )
|
||||
device_ptr = "epsonrtc";
|
||||
else if ( cartridge->has_obc1 )
|
||||
device_ptr = "obc1";
|
||||
else if ( cartridge->has_dsp1 )
|
||||
device_ptr = "dsp1";
|
||||
else if ( cartridge->has_dsp2 )
|
||||
device_ptr = "dsp2";
|
||||
else if ( cartridge->has_dsp3 )
|
||||
device_ptr = "dsp3";
|
||||
else if ( cartridge->has_dsp4 )
|
||||
device_ptr = "dsp4";
|
||||
else if ( cartridge->has_st010 )
|
||||
device_ptr = "st010";
|
||||
else if ( cartridge->has_st011 )
|
||||
device_ptr = "st011";
|
||||
else if ( cartridge->has_st018 )
|
||||
device_ptr = "st018";
|
||||
qstring loader_device;
|
||||
if ( device_ptr == nullptr )
|
||||
{
|
||||
ssize_t len = helper.hashstr(&loader_device, "device");
|
||||
if ( len <= 0 )
|
||||
device_ptr = "65816";
|
||||
else
|
||||
device_ptr = loader_device.c_str();
|
||||
}
|
||||
ioh.set_device_name(device_ptr, IORESP_ALL);
|
||||
|
||||
set_default_sreg_value(NULL, rFm, 1);
|
||||
set_default_sreg_value(NULL, rFx, 1);
|
||||
set_default_sreg_value(NULL, rFe, 1);
|
||||
set_default_sreg_value(NULL, rD, 0);
|
||||
|
||||
// see processor_t::ev_creating_segm for the following registers
|
||||
//set_default_sreg_value(NULL, rPB, 0);
|
||||
//set_default_sreg_value(NULL, rB, 0);
|
||||
//set_default_sreg_value(NULL, rDs, 0);
|
||||
|
||||
if ( inf_get_start_ip() != BADADDR )
|
||||
{
|
||||
ea_t reset_ea = xlat(inf_get_start_ip());
|
||||
ea_t sea = getseg(reset_ea)->start_ea;
|
||||
split_sreg_range(reset_ea, rFm, get_sreg(sea, rFm), SR_auto);
|
||||
split_sreg_range(reset_ea, rFx, get_sreg(sea, rFx), SR_auto);
|
||||
split_sreg_range(reset_ea, rFe, get_sreg(sea, rFe), SR_auto);
|
||||
split_sreg_range(reset_ea, rPB, 0, SR_auto);
|
||||
split_sreg_range(reset_ea, rB, 0, SR_auto);
|
||||
split_sreg_range(reset_ea, rD, get_sreg(sea, rD), SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
{
|
||||
load_from_idb();
|
||||
if ( msgid == processor_t::ev_oldfile )
|
||||
{ // read rommode_t for backward compatibility
|
||||
nodeidx_t mode = helper.hashval_long("rommode_t");
|
||||
if ( mode != 0 )
|
||||
{
|
||||
switch ( mode )
|
||||
{
|
||||
case 0x20:
|
||||
cartridge->mapper = SuperFamicomCartridge::LoROM;
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
cartridge->mapper = SuperFamicomCartridge::HiROM;
|
||||
break;
|
||||
}
|
||||
helper.hashdel("rommode_t");
|
||||
cartridge->write_hash(helper);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_get_autocmt:
|
||||
{
|
||||
qstring *buf = va_arg(va, qstring *);
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
if ( make_insn_cmt(buf, *insn) )
|
||||
retcode = 1;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_may_be_func:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
retcode = 0;
|
||||
ea_t cref_addr;
|
||||
for ( cref_addr = get_first_cref_to(insn->ea);
|
||||
cref_addr != BADADDR;
|
||||
cref_addr = get_next_cref_to(insn->ea, cref_addr) )
|
||||
{
|
||||
uint8 opcode = get_byte(cref_addr);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(opcode);
|
||||
if ( opinfo.itype == M65816_jsl
|
||||
|| opinfo.itype == M65816_jsr
|
||||
|| opinfo.itype == M65816_jml )
|
||||
{
|
||||
retcode = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_is_call_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(get_byte(insn->ea));
|
||||
if ( opinfo.itype == M65816_jsr
|
||||
|| opinfo.itype == M65816_jsl )
|
||||
retcode = 1;
|
||||
else
|
||||
retcode = -1;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_is_ret_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(get_byte(insn->ea));
|
||||
if ( opinfo.itype == M65816_rti
|
||||
|| opinfo.itype == M65816_rtl
|
||||
|| opinfo.itype == M65816_rts )
|
||||
retcode = 1;
|
||||
else
|
||||
retcode = -1;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_is_indirect_jump:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
const struct opcode_info_t &opinfo = get_opcode_info(get_byte(insn->ea));
|
||||
if ( opinfo.itype == M65816_jmp
|
||||
|| opinfo.itype == M65816_jml )
|
||||
{
|
||||
if ( opinfo.addr == ABS_INDIR
|
||||
|| opinfo.addr == ABS_IX_INDIR
|
||||
|| opinfo.addr == ABS_INDIR_LONG )
|
||||
retcode = 2;
|
||||
else
|
||||
retcode = 1;
|
||||
}
|
||||
else
|
||||
retcode = 0;
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m65816_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m65816_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 *);
|
||||
m65816_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_assumes:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m65816_assumes(*ctx);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
retcode = 0;
|
||||
break;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// CA65 ASSEMBLER
|
||||
//
|
||||
// http://www.cc65.org/doc/ca65-4.html#ss4.1
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t ca65asm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF4, // Assembler features
|
||||
0, // User-defined flags
|
||||
"CA65 ASSEMBLER", // Name
|
||||
0,
|
||||
NULL, // headers
|
||||
".ORG", // origin directive
|
||||
".END", // end directive
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\'", // special symbols in char and string constants
|
||||
|
||||
".BYTE", // ascii string directive
|
||||
".BYTE", // byte directive
|
||||
".WORD", // word directive
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// PseudoSam
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const ps_headers[] =
|
||||
{
|
||||
".code",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t pseudosam =
|
||||
{
|
||||
AS_COLON | ASH_HEXF1 | AS_N2CHR | AS_NOXRF,
|
||||
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
|
||||
NULL, // 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
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// SVENSON ELECTRONICS 6502/65C02 ASSEMBLER - V.1.0 - MAY, 1988
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t svasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF4,
|
||||
UAS_NOSEG,
|
||||
"SVENSON ELECTRONICS 6502/65C02 ASSEMBLER - V.1.0 - MAY, 1988",
|
||||
0,
|
||||
NULL, // headers
|
||||
"* = ",
|
||||
".END",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\'", // special symbols in char and string constants
|
||||
|
||||
".BYTE", // ascii string directive
|
||||
".BYTE", // byte directive
|
||||
".WORD", // word directive
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// TASM assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t tasm =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_NOENS | UAS_NOSEG,
|
||||
"Table Driven Assembler (TASM) by Speech Technology Inc.",
|
||||
0,
|
||||
NULL, // 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
|
||||
NULL, // 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
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Avocet assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t avocet =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_NOENS | UAS_NOSEG,
|
||||
"Avocet Systems 2500AD 6502 Assembler",
|
||||
0,
|
||||
NULL, // headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".fcc", // 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
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] =
|
||||
{
|
||||
&ca65asm,
|
||||
|
||||
// 6502 asm_t; imported from the 6502 CPU module.
|
||||
&svasm,
|
||||
&tasm,
|
||||
&pseudosam,
|
||||
&avocet,
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "MOS Technology 658xx series:"
|
||||
static const char *const shnames[] = { "m65816", "m65c816", NULL };
|
||||
static const char *const lnames[] = { FAMILY"MOS Technology 65816", "MOS Technology 65C816", NULL };
|
||||
|
||||
static const uchar retcode_1[] = { 0x60 }; // RTS
|
||||
static const uchar retcode_2[] = { 0x40 }; // RTI
|
||||
static const uchar retcode_3[] = { 0x6b }; // RTL
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ sizeof(retcode_3), retcode_3 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_65C816, // id
|
||||
// flag
|
||||
PR_SEGS
|
||||
| PR_SEGTRANS,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
RegNames, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rCs, // first segreg
|
||||
rPB, // last segreg
|
||||
0, // size of a segment register
|
||||
rCs, // number of CS register
|
||||
rDs, // number of DS register
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0,
|
||||
M65816_last,
|
||||
Instructions, // instruc
|
||||
3, // int tbyte_size; -- doesn't exist
|
||||
|
||||
{ 0, 0, 0, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
M65816_rts, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
|
||||
55281
idasdk76/module/78k0/78k0.cfg
Normal file
55281
idasdk76/module/78k0/78k0.cfg
Normal file
File diff suppressed because it is too large
Load Diff
72
idasdk76/module/78k0/78k0.hpp
Normal file
72
idasdk76/module/78k0/78k0.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* NEC 78K0 processor module for IDA.
|
||||
* Copyright (c) 2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#ifndef _78K0_HPP
|
||||
#define _78K0_HPP
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
struct nec78k0_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
iohandler_t ioh = iohandler_t(helper);
|
||||
bool flow = false; // stop flag
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
bool nec_find_ioport_bit(outctx_t &ctx, int port, int bit);
|
||||
void N78K_header(outctx_t &ctx);
|
||||
int N78K_emu(const insn_t &insn);
|
||||
void handle_operand(const op_t &x, bool forced_op, bool isload, const insn_t &insn);
|
||||
void N78K_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void N78K_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
bool idaapi out_opnd(outctx_t &ctx, const op_t &x);
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ 78k0"
|
||||
#define PROCMOD_NAME nec78k0
|
||||
|
||||
// subtype of out format
|
||||
#define FormOut specflag1
|
||||
// o_mem, o_near
|
||||
#define FORM_OUT_VSK (0x01)
|
||||
// o_mem, o_reg, o_near
|
||||
#define FORM_OUT_SKOBA (0x02)
|
||||
// o_reg
|
||||
#define FORM_OUT_PLUS (0x04)
|
||||
#define FORM_OUT_DISP (0x08)
|
||||
#define FORM_OUT_REG (0x10)
|
||||
// o_bit
|
||||
#define FORM_OUT_HL (0x04)
|
||||
#define FORM_OUT_PSW (0x08)
|
||||
#define FORM_OUT_A (0x10)
|
||||
#define FORM_OUT_SFR (0x20)
|
||||
#define FORM_OUT_S_ADDR (0x40)
|
||||
// o_reg
|
||||
#define SecondReg specflag2
|
||||
|
||||
// bit operand
|
||||
#define o_bit o_idpspec0
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum N78K_registers { rX, rA, rC, rB, rE, rD, rL, rH, rAX, rBC, rDE, rHL,
|
||||
rPSW, rSP, bCY, rRB0, rRB1, rRB2, rRB3,
|
||||
rVcs, rVds };
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi N78K_ana(insn_t *_insn);
|
||||
int idaapi N78K_emu(const insn_t &insn);
|
||||
|
||||
#endif
|
||||
|
||||
1491
idasdk76/module/78k0/ana.cpp
Normal file
1491
idasdk76/module/78k0/ana.cpp
Normal file
File diff suppressed because it is too large
Load Diff
106
idasdk76/module/78k0/emu.cpp
Normal file
106
idasdk76/module/78k0/emu.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* NEC 78K0 processor module for IDA.
|
||||
* Copyright (c) 2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "78k0.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// usage/change of operands
|
||||
void nec78k0_t::handle_operand(const op_t &x, bool forced_op, bool isload, const insn_t &insn)
|
||||
{
|
||||
ea_t ea = map_code_ea(insn, x.addr, x.n);
|
||||
ea_t ev = map_code_ea(insn, x.value, x.n);
|
||||
switch ( x.type )
|
||||
{
|
||||
// unused!
|
||||
case o_void:
|
||||
break;
|
||||
|
||||
case o_reg:
|
||||
if ( forced_op )
|
||||
break;
|
||||
if ( is_off(get_flags(insn.ea), x.n) )
|
||||
insn.add_dref(ev, x.n, dr_O);
|
||||
break;
|
||||
|
||||
case o_imm: // immediate can't be changed
|
||||
if ( !isload )
|
||||
goto badTouch;
|
||||
// set immediate flag
|
||||
set_immd(insn.ea);
|
||||
// if not forced and not offset
|
||||
if ( !forced_op && is_off(get_flags(insn.ea), x.n) )
|
||||
insn.add_dref(ev, x.offb, dr_O); // it's an offset!
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
break;
|
||||
|
||||
|
||||
case o_near:// a call or jump
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
// add a code xref
|
||||
insn.add_cref(ea, x.offb, fl_CN);
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.add_cref(ea, x.offb, fl_JN);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_bit:
|
||||
switch ( x.FormOut )
|
||||
{
|
||||
case FORM_OUT_S_ADDR:
|
||||
case FORM_OUT_SFR:
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// other - show a warning
|
||||
default:
|
||||
badTouch:
|
||||
warning("%a %s,%d: bad optype %d",
|
||||
insn.ea, insn.get_canon_mnem(ph),
|
||||
x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// emulator
|
||||
int nec78k0_t::N78K_emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
// get operand types
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
|
||||
flow = (Feature & CF_STOP) == 0;
|
||||
|
||||
// handle xrefs for the two operands
|
||||
if ( Feature & CF_USE1 )
|
||||
handle_operand(insn.Op1, flag1, 1, insn);
|
||||
if ( Feature & CF_USE2 )
|
||||
handle_operand(insn.Op2, flag2, 1, insn);
|
||||
// add xref to the queue
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
// handle changing operands
|
||||
if ( Feature & CF_CHG1 )
|
||||
handle_operand(insn.Op1, flag1, 0, insn);
|
||||
if ( Feature & CF_CHG2 )
|
||||
handle_operand(insn.Op2, flag2, 0, insn);
|
||||
// if not stop, continue with the next instruction
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
return 1;
|
||||
}
|
||||
91
idasdk76/module/78k0/ins.cpp
Normal file
91
idasdk76/module/78k0/ins.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* NEC 78K0 processor module for IDA.
|
||||
* Copyright (c) 2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "78k0.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
{ "mov", CF_USE2 | CF_CHG1 }, // Move Byte Data Transfer
|
||||
{ "xch", CF_CHG1 | CF_CHG2 }, // Exchange Byte Data
|
||||
{ "movw", CF_USE2 | CF_CHG1 }, // Move Word Data Transfer / Word Data Transfer with Stack Pointer
|
||||
{ "xchw", CF_CHG1 | CF_CHG2 }, // Exchange Word Data
|
||||
|
||||
{ "add", CF_USE2 | CF_CHG1 }, // Add Byte Data Addition
|
||||
{ "addc", CF_USE2 | CF_CHG1 }, // Add with Carry Addition of Byte Data with Carry
|
||||
{ "sub", CF_USE2 | CF_CHG1 }, // Subtract Byte Data Subtraction
|
||||
{ "subc", CF_USE2 | CF_CHG1 }, // Subtract with Carry Subtraction of Byte Data with Carry
|
||||
{ "and", CF_USE2 | CF_CHG1 }, // And Logical Product of Byte Data
|
||||
{ "or", CF_USE2 | CF_CHG1 }, // Or Logical Sum of Byte Data
|
||||
{ "xor", CF_USE2 | CF_CHG1 }, // Exclusive Or Exclusive Logical Sum of Byte Data
|
||||
{ "cmp", CF_USE1 | CF_USE2 }, // Compare Byte Data Comparison
|
||||
|
||||
{ "addw", CF_USE2 | CF_CHG1 }, // Add Word Data Addition
|
||||
{ "subw", CF_USE2 | CF_CHG1 }, // Subtract Word Data Subtraction
|
||||
{ "cmpw", CF_USE1 | CF_USE2 }, // Compare Word Data Comparison
|
||||
|
||||
{ "mulu", 0 }, // Multiply Unsigned Multiplication of Data
|
||||
{ "divuw", 0 }, // Divide Unsigned Word Unsigned Division of Word Data
|
||||
|
||||
{ "inc", CF_CHG1 }, // Increment Byte Data Increment
|
||||
{ "dec", CF_CHG1 }, // Decrement Byte Data Decrement
|
||||
{ "incw", CF_CHG1 }, // Increment Word Data Increment
|
||||
{ "decw", CF_CHG1 }, // Decrement Word Data Decrement
|
||||
|
||||
{ "ror", CF_CHG1 }, // Rotate Right Byte Data Rotation to the Right
|
||||
{ "rol", CF_CHG1 }, // Rotate Left Byte Data Rotation to the Left
|
||||
{ "rorc", CF_CHG1 }, // Rotate Right with Carry Byte Data Rotation to the Right with Carry
|
||||
{ "rolc", CF_CHG1 }, // Rotate Left with Carry Byte Data Rotation to the Left with Carry
|
||||
{ "ror4", CF_CHG1 }, // Rotate Right Digit Digit Rotation to the Right
|
||||
{ "rol4", CF_CHG1 }, // Rotate Left Digit Digit Rotation to the Left
|
||||
|
||||
{ "adjba", 0 }, // Decimal Adjust Register for Addition Decimal Adjustment of Addition Result
|
||||
{ "adjbs", 0 }, // Decimal Adjust Register for Subtraction Decimal Adjustment of Subtraction Result
|
||||
|
||||
{ "mov1", CF_USE2 | CF_CHG1 }, // Move Single Bit 1 Bit Data Transfer
|
||||
{ "and1", CF_USE2 | CF_CHG1 }, // And Single Bit 1 Bit Data Logical Product
|
||||
{ "or1", CF_USE2 | CF_CHG1 }, // Or Single Bit 1 Bit Data Logical Sum
|
||||
{ "xor1", CF_USE2 | CF_CHG1 }, // Exclusive Or Single Bit 1 Bit Data Exclusive Logical Sum
|
||||
{ "set1", CF_CHG1 }, // Set Single Bit (Carry Flag) 1 Bit Data Set
|
||||
{ "clr1", CF_CHG1 }, // Clear Single Bit (Carry Flag) 1 Bit Data Clear
|
||||
{ "not1", CF_USE1 }, // Not Single Bit (Carry Flag) 1 Bit Data Logical Negation
|
||||
|
||||
{ "call", CF_USE1 | CF_CALL }, // Call Subroutine Call (16 Bit Direct)
|
||||
{ "callf", CF_USE1 | CF_CALL }, // Call Flag Subroutine Call (11 Bit Direct Specification)
|
||||
{ "callt", CF_USE1 | CF_CALL }, // Call Table Subroutine Call (Refer to the Call Table)
|
||||
{ "brk", 0 }, // Break Software Vectored Interrupt
|
||||
{ "ret", CF_STOP }, // Return Return from Subroutine
|
||||
{ "retb", CF_STOP }, // Return from Interrupt Return from Hardware Vectored Interrupt
|
||||
{ "reti", CF_STOP }, // Return from Break Return from Software Vectored Interrupt
|
||||
|
||||
{ "push", CF_USE1 }, // Push
|
||||
{ "pop", CF_USE1 }, // Pop
|
||||
|
||||
|
||||
{ "br", CF_USE1 | CF_STOP }, // Branch Unconditional Branch
|
||||
{ "bc", CF_USE1 }, // Branch if Carry Conditional Branch with Carry Flag (CY = 1)
|
||||
{ "bnc", CF_USE1 }, // Branch if Not Carry Conditional Branch with Carry Flag (CY = 0)
|
||||
{ "bz", CF_USE1 }, // Branch if Zero Conditional Branch with Zero Flag (Z = 1)
|
||||
{ "bnz", CF_USE1 }, // Branch if Not Zero Conditional Branch with Zero Flag (Z = 0)
|
||||
{ "bt", CF_USE1 | CF_USE2 }, // Branch if True Conditional Branch by Bit Test (Byte Data Bit = 1)
|
||||
{ "bf", CF_USE1 | CF_USE2 }, // Branch if False Conditional Branch by Bit Test (Byte Data Bit = 0)
|
||||
{ "btclr", CF_USE1 | CF_USE2 }, // Branch if True and Clear Conditional Branch and Clear by Bit Test (Byte Data Bit = 1)
|
||||
{ "dbnz", CF_CHG1 | CF_USE2 }, // Decrement and Branch if Not Zero Conditional Loop (R1!= 0)
|
||||
|
||||
{ "sel", CF_USE1 }, // Select Register Bank Register Bank Selection
|
||||
|
||||
|
||||
{ "nop", 0 }, // No Operation
|
||||
{ "EI", 0 }, // Enable Interrupt
|
||||
{ "DI", 0 }, // Disable Interrupt
|
||||
{ "HALT", 0 }, // HALT Mode Set
|
||||
{ "STOP", CF_STOP } // Stop Mode Set
|
||||
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == NEC_78K_0_last);
|
||||
95
idasdk76/module/78k0/ins.hpp
Normal file
95
idasdk76/module/78k0/ins.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* NEC 78K0 processor module for IDA.
|
||||
* Copyright (c) 2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
NEC_78K_0_null = 0, // Unknown Operation
|
||||
|
||||
NEC_78K_0_mov, // Move Byte Data Transfer
|
||||
NEC_78K_0_xch, // Exchange Byte Data
|
||||
NEC_78K_0_movw, // Move Word Data Transfer / Word Data Transfer with Stack Pointer
|
||||
NEC_78K_0_xchw, // Exchange Word Data
|
||||
|
||||
NEC_78K_0_add, // Add Byte Data Addition
|
||||
NEC_78K_0_addc, // Add with Carry Addition of Byte Data with Carry
|
||||
NEC_78K_0_sub, // Subtract Byte Data Subtraction
|
||||
NEC_78K_0_subc, // Subtract with Carry Subtraction of Byte Data with Carry
|
||||
NEC_78K_0_and, // And Logical Product of Byte Data
|
||||
NEC_78K_0_or, // Or Logical Sum of Byte Data
|
||||
NEC_78K_0_xor, // Exclusive Or Exclusive Logical Sum of Byte Data
|
||||
NEC_78K_0_cmp, // Compare Byte Data Comparison
|
||||
|
||||
NEC_78K_0_addw, // Add Word Data Addition
|
||||
NEC_78K_0_subw, // Subtract Word Data Subtraction
|
||||
NEC_78K_0_cmpw, // Compare Word Data Comparison
|
||||
|
||||
NEC_78K_0_mulu, // Multiply Unsigned Multiplication of Data
|
||||
NEC_78K_0_divuw, // Divide Unsigned Word Unsigned Division of Word Data
|
||||
|
||||
NEC_78K_0_inc, // Increment Byte Data Increment
|
||||
NEC_78K_0_dec, // Decrement Byte Data Decrement
|
||||
NEC_78K_0_incw, // Increment Word Data Increment
|
||||
NEC_78K_0_decw, // Decrement Word Data Decrement
|
||||
|
||||
NEC_78K_0_ror, // Rotate Right Byte Data Rotation to the Right
|
||||
NEC_78K_0_rol, // Rotate Left Byte Data Rotation to the Left
|
||||
NEC_78K_0_rorc, // Rotate Right with Carry Byte Data Rotation to the Right with Carry
|
||||
NEC_78K_0_rolc, // Rotate Left with Carry Byte Data Rotation to the Left with Carry
|
||||
NEC_78K_0_ror4, // Rotate Right Digit Digit Rotation to the Right
|
||||
NEC_78K_0_rol4, // Rotate Left Digit Digit Rotation to the Left
|
||||
|
||||
NEC_78K_0_adjba, // Decimal Adjust Register for Addition Decimal Adjustment of Addition Result
|
||||
NEC_78K_0_adjbs, // Decimal Adjust Register for Subtraction Decimal Adjustment of Subtraction Result
|
||||
|
||||
NEC_78K_0_mov1, // Move Single Bit 1 Bit Data Transfer
|
||||
NEC_78K_0_and1, // And Single Bit 1 Bit Data Logical Product
|
||||
NEC_78K_0_or1, // Or Single Bit 1 Bit Data Logical Sum
|
||||
NEC_78K_0_xor1, // Exclusive Or Single Bit 1 Bit Data Exclusive Logical Sum
|
||||
NEC_78K_0_set1, // Set Single Bit (Carry Flag) 1 Bit Data Set
|
||||
NEC_78K_0_clr1, // Clear Single Bit (Carry Flag) 1 Bit Data Clear
|
||||
NEC_78K_0_not1, // Not Single Bit (Carry Flag) 1 Bit Data Logical Negation
|
||||
|
||||
NEC_78K_0_call, // Call Subroutine Call (16 Bit Direct)
|
||||
NEC_78K_0_callf, // Call Flag Subroutine Call (11 Bit Direct Specification)
|
||||
NEC_78K_0_callt, // Call Table Subroutine Call (Refer to the Call Table)
|
||||
NEC_78K_0_brk, // Break Software Vectored Interrupt
|
||||
NEC_78K_0_ret, // Return Return from Subroutine
|
||||
NEC_78K_0_retb, // Return from Interrupt Return from Hardware Vectored Interrupt
|
||||
NEC_78K_0_reti, // Return from Break Return from Software Vectored Interrupt
|
||||
|
||||
NEC_78K_0_push, // Push
|
||||
NEC_78K_0_pop, // Pop
|
||||
|
||||
NEC_78K_0_br, // Branch Unconditional Branch
|
||||
NEC_78K_0_bc, // Branch if Carry Conditional Branch with Carry Flag (CY = 1)
|
||||
NEC_78K_0_bnc, // Branch if Not Carry Conditional Branch with Carry Flag (CY = 0)
|
||||
NEC_78K_0_bz, // Branch if Zero Conditional Branch with Zero Flag (Z = 1)
|
||||
NEC_78K_0_bnz, // Branch if Not Zero Conditional Branch with Zero Flag (Z = 0)
|
||||
NEC_78K_0_bt, // Branch if True Conditional Branch by Bit Test (Byte Data Bit = 1)
|
||||
NEC_78K_0_bf, // Branch if False Conditional Branch by Bit Test (Byte Data Bit = 0)
|
||||
NEC_78K_0_btclr, // Branch if True and Clear Conditional Branch and Clear by Bit Test (Byte Data Bit = 1)
|
||||
NEC_78K_0_dbnz, // Decrement and Branch if Not Zero Conditional Loop (R1!= 0)
|
||||
|
||||
NEC_78K_0_sel, // Select Register Bank Register Bank Selection
|
||||
|
||||
|
||||
NEC_78K_0_nop, // No Operation
|
||||
NEC_78K_0_EI, // Enable Interrupt
|
||||
NEC_78K_0_DI, // Disable Interrupt
|
||||
NEC_78K_0_HALT, // HALT Mode Set
|
||||
NEC_78K_0_STOP, // Stop Mode Set
|
||||
|
||||
|
||||
NEC_78K_0_last
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
57
idasdk76/module/78k0/makefile
Normal file
57
idasdk76/module/78k0/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=78k0
|
||||
CONFIGS=78k0.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)ieee.h $(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 \
|
||||
78k0.hpp ana.cpp 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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
78k0.hpp emu.cpp 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)ieee.h $(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 \
|
||||
78k0.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)ieee.h $(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 \
|
||||
78k0.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)ieee.h $(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 78k0.hpp ins.hpp reg.cpp
|
||||
242
idasdk76/module/78k0/out.cpp
Normal file
242
idasdk76/module/78k0/out.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* NEC 78K0 processor module for IDA.
|
||||
* Copyright (c) 2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "78k0.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_N78K_t : public outctx_t
|
||||
{
|
||||
out_N78K_t(void) = delete; // not used
|
||||
public:
|
||||
void OutReg(int rgnum) { out_register(ph.reg_names[rgnum]); }
|
||||
void OutVarName(const op_t &x);
|
||||
void OutVarNameVal(const op_t &x);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_N78K_t) == sizeof(outctx_t));
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void idaapi out_insn(outctx_t &ctx)
|
||||
{
|
||||
out_N78K_t *p = (out_N78K_t *)&ctx;
|
||||
p->out_insn();
|
||||
}
|
||||
|
||||
bool idaapi out_opnd(outctx_t &ctx, const op_t &x)
|
||||
{
|
||||
out_N78K_t *p = (out_N78K_t *)&ctx;
|
||||
return p->out_operand(x);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_N78K_t::OutVarName(const op_t &x)
|
||||
{
|
||||
ushort addr = ushort(x.addr);
|
||||
ea_t toea = map_code_ea(insn, addr, x.n);
|
||||
if ( !out_name_expr(x, toea, addr) )
|
||||
out_value(x, OOF_ADDR | OOFW_16);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_N78K_t::OutVarNameVal(const op_t &x)
|
||||
{
|
||||
ushort addr = ushort(x.value);
|
||||
ea_t toea = map_code_ea(insn, addr, x.n);
|
||||
if ( !out_name_expr(x, toea, addr) )
|
||||
out_value(x, OOFW_16);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_N78K_t::out_operand(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
case o_reg:
|
||||
if ( x.FormOut & FORM_OUT_SKOBA )
|
||||
out_symbol('[');
|
||||
OutReg(x.reg);
|
||||
if ( x.FormOut & FORM_OUT_PLUS )
|
||||
out_symbol('+');
|
||||
if ( x.FormOut & FORM_OUT_DISP )
|
||||
{
|
||||
if ( is_off(F, x.n) )
|
||||
OutVarNameVal(x);
|
||||
else
|
||||
out_value(x, OOFW_IMM);
|
||||
}
|
||||
if ( x.FormOut & FORM_OUT_REG )
|
||||
out_keyword(ph.reg_names[uchar(x.SecondReg)]);
|
||||
if ( x.FormOut & FORM_OUT_SKOBA )
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_bit:
|
||||
switch ( x.FormOut )
|
||||
{
|
||||
case FORM_OUT_S_ADDR:
|
||||
case FORM_OUT_SFR:
|
||||
{
|
||||
OutVarName(x);
|
||||
out_symbol('.');
|
||||
nec78k0_t &pm = *static_cast<nec78k0_t *>(procmod);
|
||||
if ( !pm.nec_find_ioport_bit(*this, (int)x.addr, (int)x.value) )
|
||||
out_value(x, OOFW_IMM);
|
||||
}
|
||||
break;
|
||||
|
||||
case FORM_OUT_A:
|
||||
out_line("A.");
|
||||
out_value(x, OOFW_IMM);
|
||||
break;
|
||||
|
||||
case FORM_OUT_PSW:
|
||||
out_line("PSW.");
|
||||
switch ( x.value )
|
||||
{
|
||||
case 0: out_line("CY"); break;
|
||||
case 1: out_line("ISP"); break;
|
||||
case 3: out_line("RBS0"); break;
|
||||
case 4: out_line("AC"); break;
|
||||
case 5: out_line("RBS1"); break;
|
||||
case 6: out_line("Z"); break;
|
||||
case 7: out_line("IE"); break;
|
||||
default:out_value(x, OOFW_IMM); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FORM_OUT_HL:
|
||||
out_symbol('[');
|
||||
OutReg(rHL);
|
||||
out_symbol(']');
|
||||
out_symbol('.');
|
||||
if ( is_off(F, x.n) )
|
||||
OutVarNameVal(x);
|
||||
else
|
||||
out_value(x, OOFW_IMM);
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
if ( is_off(F, x.n) )
|
||||
OutVarNameVal(x);
|
||||
else
|
||||
out_value(x, OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
// output variable name from the memory (for example byte_98)
|
||||
if ( x.FormOut & FORM_OUT_VSK )
|
||||
out_symbol('!');
|
||||
if ( x.FormOut & FORM_OUT_SKOBA )
|
||||
out_symbol('[');
|
||||
// output memory name
|
||||
OutVarName(x);
|
||||
if ( x.FormOut & FORM_OUT_SKOBA )
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
if ( x.FormOut & FORM_OUT_VSK )
|
||||
out_symbol('!');
|
||||
if ( x.FormOut & FORM_OUT_SKOBA )
|
||||
out_symbol('[');
|
||||
{
|
||||
ea_t adr = map_code_ea(insn, x);
|
||||
if ( !out_name_expr(x, adr, x.addr) )
|
||||
{
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFW_16);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
if ( x.FormOut & FORM_OUT_SKOBA )
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10130);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_N78K_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void nec78k0_t::N78K_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, Sarea) could be made const
|
||||
void nec78k0_t::N78K_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
const char *SegType = Sarea->type == SEG_CODE ? "CSEG"
|
||||
: Sarea->type == SEG_DATA ? "DSEG"
|
||||
: "RSEG";
|
||||
// line: RSEG <NAME>
|
||||
qstring sn;
|
||||
get_visible_segm_name(&sn, Sarea);
|
||||
ctx.gen_printf(-1,"%s %s ", SegType, sn.c_str());
|
||||
// if non-zero offfset output it (ORG XXXX)
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char bufn[MAX_NUMBUF];
|
||||
btoa(bufn, sizeof(bufn), org);
|
||||
ctx.gen_printf(-1, "%s %s", ash.origin, bufn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void nec78k0_t::N78K_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 )
|
||||
{
|
||||
size_t i = strlen(ash.end);
|
||||
do
|
||||
ctx.out_char(' ');
|
||||
while ( ++i < 8 );
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
288
idasdk76/module/78k0/reg.cpp
Normal file
288
idasdk76/module/78k0/reg.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* NEC 78K0 processor module for IDA.
|
||||
* Copyright (c) 2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "78k0.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <segregs.hpp>
|
||||
int data_id;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"X", "A", "C", "B", "E", "D", "L", "H", "AX", "BC", "DE","HL",
|
||||
"PSW", "SP", "CY", "RB0", "RB1", "RB2", "RB3",
|
||||
"cs", "ds"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static const asm_t nec78k0 =
|
||||
{
|
||||
AS_COLON | ASB_BINF4 | AS_N2CHR,
|
||||
0,
|
||||
"NEC 78K0 Assembler",
|
||||
0,
|
||||
NULL,
|
||||
".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
|
||||
".dd", // no double words
|
||||
NULL, // no qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // no float
|
||||
NULL, // no double
|
||||
NULL, // no tbytes
|
||||
NULL, // no packreal
|
||||
"#d dup(#v)", //".db.#s(b,w) #d,#v", // #h - header(.byte,.word)
|
||||
// #d - size of array
|
||||
// #v - value of array elements
|
||||
// #s - size specifier
|
||||
".rs %s",// uninited data (reserve space)
|
||||
".equ",
|
||||
NULL, // seg prefix
|
||||
"$", // a_curip
|
||||
|
||||
NULL, // returns function header line
|
||||
NULL, // returns function footer line
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
#define FAMILY "NEC series:"
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"78k0",
|
||||
NULL
|
||||
};
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"NEC 78K0",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] =
|
||||
{
|
||||
&nec78k0,
|
||||
NULL
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcNEC78K0_0[] = { 0xAF }; // ret
|
||||
static const uchar retcNEC78K0_1[] = { 0x9F }; // retb
|
||||
static const uchar retcNEC78K0_2[] = { 0x8F }; // reti
|
||||
static const uchar retcNEC78K0_3[] = { 0xBF }; // brk
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcNEC78K0_0), retcNEC78K0_0 },
|
||||
{ sizeof(retcNEC78K0_1), retcNEC78K0_1 },
|
||||
{ sizeof(retcNEC78K0_2), retcNEC78K0_2 },
|
||||
{ sizeof(retcNEC78K0_3), retcNEC78K0_3 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(nec78k0_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool nec78k0_t::nec_find_ioport_bit(outctx_t &ctx, int port, int bit)
|
||||
{
|
||||
|
||||
const ioport_bit_t *b = find_ioport_bit(ioh.ports, port, bit);
|
||||
if ( b != NULL && !b->name.empty() )
|
||||
{
|
||||
ctx.out_line(b->name.c_str(), COLOR_IMPNAME);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void set_dopolnit_info(void)
|
||||
{
|
||||
for ( int banknum = 0; banknum < 4; banknum++ )
|
||||
{
|
||||
for ( int Regs = 0; Regs < 8; Regs++ )
|
||||
{
|
||||
char temp[100];
|
||||
qsnprintf(temp, sizeof(temp), "Bank%d_%s", banknum, RegNames[Regs]);
|
||||
ushort Addr = ushort(0xFEE0+((banknum*8)+Regs));
|
||||
set_name(Addr, temp);
|
||||
qsnprintf(temp, sizeof(temp), "Internal high-speed RAM (Bank %d registr %s)", banknum, RegNames[Regs]);
|
||||
set_cmt(Addr, temp, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void nec78k0_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi nec78k0_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_be(false);
|
||||
inf_set_gen_lzero(true);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgfile, &cb) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
set_dopolnit_info();
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
{
|
||||
segment_t *s = va_arg(va, segment_t *);
|
||||
// Set default value of DS register for all segments
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
N78K_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
N78K_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 *);
|
||||
N78K_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return N78K_ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return N78K_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;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_NEC_78K0,
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_SEGTRANS
|
||||
| PR_SEGS,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs, rVds,
|
||||
2, // size of a segment register
|
||||
rVcs, rVds,
|
||||
NULL,
|
||||
retcodes,
|
||||
0, NEC_78K_0_last,
|
||||
Instructions, // instruc
|
||||
3,
|
||||
{ 0,0,0,0 },
|
||||
0,
|
||||
NULL, // micro virtual mashine
|
||||
};
|
||||
27814
idasdk76/module/78k0s/78k0s.cfg
Normal file
27814
idasdk76/module/78k0s/78k0s.cfg
Normal file
File diff suppressed because it is too large
Load Diff
94
idasdk76/module/78k0s/78k_0s.hpp
Normal file
94
idasdk76/module/78k0s/78k_0s.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2001 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NEC78K0S_HPP
|
||||
#define _NEC78K0S_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
struct nec78k0s_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
iohandler_t ioh = iohandler_t(helper);
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
bool nec_find_ioport_bit(outctx_t &ctx, int port, int bit);
|
||||
void nec78k0s_header(outctx_t &ctx);
|
||||
int emu(const insn_t &insn);
|
||||
void handle_operand(const op_t &x, bool forced_op, bool isload, const insn_t &insn);
|
||||
void nec78k0s_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
bool idaapi out_opnd(outctx_t &ctx, const op_t &x);
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ 78k0s"
|
||||
#define PROCMOD_NAME nec78k0s
|
||||
|
||||
#define UAS_NOSPA 0x0001 // no space after comma
|
||||
//#define UAS_ZVBIT 0x0002 // '*' prefixes name in bit command
|
||||
//#define UAS_AREAS 0x0004 // '.area' segment directive
|
||||
//#define UAS_CCR 0x0008 // "ccr" register is named "cc"
|
||||
// // "dpr" register is named "dp"
|
||||
// // "pcr" register is named "pc"
|
||||
//#define UAS_ORA 0x0010 // ORAA is named ORA
|
||||
// // ORAB is named ORB
|
||||
//#define UAS_CODE 0x0020 // "code", "data", "bss" directives
|
||||
//#define UAS_AUTOPC 0x0040 // Automatic relative addressing by PC
|
||||
// // (no need to substract PC value)
|
||||
//#define UAS_ALL 0x0080 // "all" keyword is recognized as
|
||||
// // a synonim for all registers
|
||||
//#define UAS_OS9 0x0100 // has OS9 directive
|
||||
//----------------------------------------------------------------------
|
||||
// Redefine temporary names
|
||||
//
|
||||
#define exten segpref
|
||||
#define xmode specflag1
|
||||
#define prepost specflag2
|
||||
#define addr16 specflag3
|
||||
|
||||
// bit operand
|
||||
#define regmode specflag1
|
||||
#define regdata specflag2
|
||||
|
||||
// callt
|
||||
#define form specflag1
|
||||
|
||||
#define o_bit o_idpspec0
|
||||
//------------------------------------------------------------------------
|
||||
enum nec_registers { rX, rA, rC, rB, rE, rD, rL, rH, rAX, rBC, rDE, rHL,
|
||||
rPSW, rSP, rS, rCC, rDPR,
|
||||
bCY,
|
||||
Rcs, Rds };
|
||||
|
||||
enum bitOper { SADDR=0, SFR, A, PSW, HL, CY };
|
||||
//------------------------------------------------------------------------
|
||||
extern qstring deviceparams;
|
||||
extern qstring device;
|
||||
|
||||
struct ioport_bit_t;
|
||||
bool nec_find_ioport_bit(outctx_t &ctx, int port, int bit);
|
||||
uint32 Get_Data_16bits();
|
||||
//------------------------------------------------------------------------
|
||||
void idaapi nec78k0s_header(outctx_t &ctx);
|
||||
void idaapi nec78k0s_footer(outctx_t &ctx);
|
||||
|
||||
void idaapi nec78k0s_segstart(outctx_t &ctx, segment_t *seg);
|
||||
|
||||
int idaapi ana(insn_t *_insn);
|
||||
int idaapi emu(const insn_t &insn);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1710
idasdk76/module/78k0s/ana.cpp
Normal file
1710
idasdk76/module/78k0s/ana.cpp
Normal file
File diff suppressed because it is too large
Load Diff
99
idasdk76/module/78k0s/emu.cpp
Normal file
99
idasdk76/module/78k0s/emu.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2001 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "78k_0s.hpp"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void DataSet(const insn_t &insn, const op_t &x, ea_t EA, int isload)
|
||||
{
|
||||
insn.create_op_data(EA, x);
|
||||
insn.add_dref(EA, x.offb, isload ? dr_R : dr_W);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void nec78k0s_t::handle_operand(const op_t &x, bool forced_op, bool isload, const insn_t &insn)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_phrase:
|
||||
case o_void:
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
case o_displ:
|
||||
set_immd(insn.ea);
|
||||
if ( !forced_op )
|
||||
{
|
||||
ushort addr = ushort(x.addr);
|
||||
if ( x.type == o_displ )
|
||||
{
|
||||
addr += (ushort)insn.ip;
|
||||
addr += insn.size;
|
||||
uint32 offb = map_code_ea(insn, addr, x.n);
|
||||
DataSet(insn, x, offb, isload);
|
||||
}
|
||||
else if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
{
|
||||
insn.add_off_drefs(x, dr_O, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_bit:
|
||||
case o_mem:
|
||||
DataSet(insn, x, map_code_ea(insn, x), isload);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
int iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
|
||||
if ( iscall )
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
int nec78k0s_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
flow = (Feature & CF_STOP) == 0;
|
||||
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
if ( Feature & CF_USE1 )
|
||||
handle_operand(insn.Op1, flag1, 1, insn);
|
||||
if ( Feature & CF_USE2 )
|
||||
handle_operand(insn.Op2, flag2, 1, insn);
|
||||
if ( Feature & CF_USE3 )
|
||||
handle_operand(insn.Op3, flag3, 1, insn);
|
||||
if ( Feature & CF_CHG1 )
|
||||
handle_operand(insn.Op1, flag1, 0, insn);
|
||||
if ( Feature & CF_CHG2 )
|
||||
handle_operand(insn.Op2, flag2, 0, insn);
|
||||
if ( Feature & CF_CHG3 )
|
||||
handle_operand(insn.Op3, flag3, 0, insn);
|
||||
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
66
idasdk76/module/78k0s/ins.cpp
Normal file
66
idasdk76/module/78k0s/ins.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2001 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include "ins.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
{ "cmp", CF_USE1 | CF_USE2 }, // Compare Byte Data Comparison
|
||||
{ "xor", CF_CHG1 | CF_USE2 }, // Exclusive Or Exclusive Logical Sum of Byte Data
|
||||
{ "and", CF_CHG1 | CF_USE2 }, // AND Logical Product of Byte Data
|
||||
{ "or", CF_CHG1 | CF_USE2 }, // OR Logical Sum of Byte Data
|
||||
{ "add", CF_CHG1 | CF_USE2 }, // ADD Byte Data Addition
|
||||
{ "sub", CF_CHG1 | CF_USE2 }, // Subtract Byte Data Subtraction
|
||||
{ "addc", CF_CHG1 | CF_USE2 }, // Add with Carry Addition of Byte Data with Carry
|
||||
{ "subc", CF_CHG1 | CF_USE2 }, // Subtract with Carry Subtraction of Byte Data with Carry
|
||||
{ "subw", CF_CHG1 | CF_USE2 }, // Subtract Word Data Subtraction
|
||||
{ "addw", CF_CHG1 | CF_USE2 }, // Add Word Data Addition
|
||||
{ "cmpw", CF_USE1 | CF_USE2 }, // Compare Word Data Comparison
|
||||
{ "inc", CF_CHG1 }, // Increment Byte Data Increment
|
||||
{ "dec", CF_CHG1 }, // Decrement Byte Data Decrement
|
||||
{ "incw", CF_CHG1 }, // Increment Word Data Increment
|
||||
{ "decw", CF_CHG1 }, // Decrement Word Data Decrement
|
||||
{ "ror", CF_CHG1 }, // Rotate Right Byte Data Rotation to the Right
|
||||
{ "rol", CF_CHG1 }, // Rotate Left Byte Data Rotation to the Left
|
||||
{ "rorc", CF_CHG1 }, // Rotate Right with Carry Byte Data Rotation to the Right with Carry
|
||||
{ "rolc", CF_CHG1 }, // Rotate Left with Carry Byte Data Rotation to the Left with Carry
|
||||
{ "call", CF_USE1 | CF_CALL }, // CALL Subroutine Call (16 Bit Direct)
|
||||
{ "callt", CF_USE1 | CF_CALL }, // Call Table Subroutine Call (Call Table Reference)
|
||||
{ "ret", CF_STOP }, // Return from Subroutine
|
||||
{ "reti", CF_STOP }, // Return from Interrupt / Return from Hardware Vectored Interrupt
|
||||
{ "mov", CF_CHG1 | CF_USE2 }, // Move Byte Data Transfer
|
||||
{ "xch", CF_CHG1 | CF_CHG2 }, // Exchange Byte Data Exchange
|
||||
{ "xchw", CF_CHG1 | CF_CHG2 }, // Exchange Word Data Exchange
|
||||
{ "set1", CF_CHG1 }, // Set Single Bit (Carry Flag) 1 Bit Data Set
|
||||
{ "clr1", CF_CHG1 }, // Clear Single Bit (Carry Flag) 1 Bit Data Clear
|
||||
{ "not1", CF_CHG1 }, // Not Single Bit (Carry Flag) 1 Bit Data Logical Negation
|
||||
{ "push", CF_USE1 }, // Push
|
||||
{ "pop", CF_CHG1 }, // Pop
|
||||
{ "movw", CF_CHG1 | CF_USE2 }, // Move Word Data Transfer / Word Data Transfer with Stack Pointer
|
||||
{ "br", CF_USE1 | CF_STOP }, // Unconditional Branch
|
||||
{ "bc", CF_USE1 }, // Branch if Carry Conditional Branch with Carry Flag (CY = 1)
|
||||
{ "bnc", CF_USE1 }, // Branch if Not Carry Conditional Branch with Carry Flag (CY = 0)
|
||||
{ "bz", CF_USE1 }, // Branch if Zero Conditional Branch with Zero Flag (Z = 1)
|
||||
{ "bnz", CF_USE1 }, // Branch if Not Zero Conditional Branch with Zero Flag (Z = 0)
|
||||
{ "bt", CF_USE1 | CF_USE2 }, // Branch if True Conditional Branch by Bit Test (Byte Data Bit = 1)
|
||||
{ "bf", CF_USE1 | CF_USE2 }, // Branch if False Conditional Branch by Bit Test (Byte Data Bit = 0)
|
||||
{ "dbnz", CF_CHG1 | CF_USE2 }, // Decrement and Branch if Not Zero Conditional Loop (R1 != 0)
|
||||
{ "nop", 0 }, // No Operation
|
||||
{ "EI", 0 }, // Enable Interrupt
|
||||
{ "DI", 0 }, // Disable Interrupt
|
||||
{ "HALT", 0 }, // HALT Mode Set
|
||||
{ "STOP", CF_STOP } // Stop Mode Set
|
||||
};
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
CASSERT(qnumber(Instructions) == NEC_78K_0S_last);
|
||||
64
idasdk76/module/78k0s/ins.hpp
Normal file
64
idasdk76/module/78k0s/ins.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
NEC_78K_0S_null = 0, // Unknown Operation
|
||||
NEC_78K_0S_cmp, // Compare Byte Data Comparison
|
||||
NEC_78K_0S_xor, // Exclusive Or Exclusive Logical Sum of Byte Data
|
||||
NEC_78K_0S_and, // AND Logical Product of Byte Data
|
||||
NEC_78K_0S_or, // OR Logical Sum of Byte Data
|
||||
NEC_78K_0S_add, // ADD Byte Data Addition
|
||||
NEC_78K_0S_sub, // Subtract Byte Data Subtraction
|
||||
NEC_78K_0S_addc, // Add with Carry Addition of Byte Data with Carry
|
||||
NEC_78K_0S_subc, // Subtract with Carry Subtraction of Byte Data with Carry
|
||||
NEC_78K_0S_subw, // Subtract Word Data Subtraction
|
||||
NEC_78K_0S_addw, // Add Word Data Addition
|
||||
NEC_78K_0S_cmpw, // Compare Word Data Comparison
|
||||
NEC_78K_0S_inc, // Increment Byte Data Increment
|
||||
NEC_78K_0S_dec, // Decrement Byte Data Decrement
|
||||
NEC_78K_0S_incw, // Increment Word Data Increment
|
||||
NEC_78K_0S_decw, // Decrement Word Data Decrement
|
||||
NEC_78K_0S_ror, // Rotate Right Byte Data Rotation to the Right
|
||||
NEC_78K_0S_rol, // Rotate Left Byte Data Rotation to the Left
|
||||
NEC_78K_0S_rorc, // Rotate Right with Carry Byte Data Rotation to the Right with Carry
|
||||
NEC_78K_0S_rolc, // Rotate Left with Carry Byte Data Rotation to the Left with Carry
|
||||
NEC_78K_0S_call, // CALL Subroutine Call (16 Bit Direct)
|
||||
NEC_78K_0S_callt, // Call Table Subroutine Call (Call Table Reference)
|
||||
NEC_78K_0S_ret, // Return from Subroutine
|
||||
NEC_78K_0S_reti, // Return from Interrupt / Return from Hardware Vectored Interrupt
|
||||
NEC_78K_0S_mov, // Move Byte Data Transfer
|
||||
NEC_78K_0S_xch, // Exchange Byte Data Exchange
|
||||
NEC_78K_0S_xchw, // Exchange Word Data Exchange
|
||||
NEC_78K_0S_set1, // Set Single Bit (Carry Flag) 1 Bit Data Set
|
||||
NEC_78K_0S_clr1, // Clear Single Bit (Carry Flag) 1 Bit Data Clear
|
||||
NEC_78K_0S_not1, // Not Single Bit (Carry Flag) 1 Bit Data Logical Negation
|
||||
NEC_78K_0S_push, // Push
|
||||
NEC_78K_0S_pop, // Pop
|
||||
NEC_78K_0S_movw, // Move Word Data Transfer / Word Data Transfer with Stack Pointer
|
||||
NEC_78K_0S_br, // Unconditional Branch
|
||||
NEC_78K_0S_bc, // Branch if Carry Conditional Branch with Carry Flag (CY = 1)
|
||||
NEC_78K_0S_bnc, // Branch if Not Carry Conditional Branch with Carry Flag (CY = 0)
|
||||
NEC_78K_0S_bz, // Branch if Zero Conditional Branch with Zero Flag (Z = 1)
|
||||
NEC_78K_0S_bnz, // Branch if Not Zero Conditional Branch with Zero Flag (Z = 0)
|
||||
NEC_78K_0S_bt, // Branch if True Conditional Branch by Bit Test (Byte Data Bit = 1)
|
||||
NEC_78K_0S_bf, // Branch if False Conditional Branch by Bit Test (Byte Data Bit = 0)
|
||||
NEC_78K_0S_dbnz, // Decrement and Branch if Not Zero Conditional Loop (R1 != 0)
|
||||
NEC_78K_0S_nop, // No Operation
|
||||
NEC_78K_0S_EI, // Enable Interrupt
|
||||
NEC_78K_0S_DI, // Disable Interrupt
|
||||
NEC_78K_0S_HALT, // HALT Mode Set
|
||||
NEC_78K_0S_STOP, // Stop Mode Set
|
||||
NEC_78K_0S_last
|
||||
};
|
||||
|
||||
#endif
|
||||
52
idasdk76/module/78k0s/makefile
Normal file
52
idasdk76/module/78k0s/makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
PROC=78k0s
|
||||
CONFIGS=78k0s.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)ieee.h $(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 \
|
||||
78k_0s.hpp ana.cpp 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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
78k_0s.hpp emu.cpp ins.hpp
|
||||
$(F)ins$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.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)ieee.h $(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 \
|
||||
78k_0s.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)ieee.h $(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 78k_0s.hpp ins.hpp reg.cpp
|
||||
232
idasdk76/module/78k0s/out.cpp
Normal file
232
idasdk76/module/78k0s/out.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2001 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "78k_0s.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_nec78k0s_t : public outctx_t
|
||||
{
|
||||
out_nec78k0s_t(void) = delete; // not used
|
||||
public:
|
||||
void OutReg(int rgnum) { out_register(ph.reg_names[rgnum]); }
|
||||
int OutVarName(const op_t &x, bool iscode);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_nec78k0s_t) == sizeof(outctx_t));
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void idaapi out_insn(outctx_t &ctx)
|
||||
{
|
||||
out_nec78k0s_t *p = (out_nec78k0s_t *)&ctx;
|
||||
p->out_insn();
|
||||
}
|
||||
|
||||
bool idaapi out_opnd(outctx_t &ctx, const op_t &x)
|
||||
{
|
||||
out_nec78k0s_t *p = (out_nec78k0s_t *)&ctx;
|
||||
return p->out_operand(x);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int out_nec78k0s_t::OutVarName(const op_t &x, bool iscode)
|
||||
{
|
||||
ushort addr = ushort(x.addr);
|
||||
// get linear address
|
||||
ea_t toea = map_ea(insn, addr, x.n, iscode);
|
||||
// get its string representation
|
||||
return out_name_expr(x, toea, x.addr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_nec78k0s_t::out_operand(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_reg:
|
||||
if ( x.prepost )
|
||||
out_symbol('[');
|
||||
OutReg(x.reg);
|
||||
if ( x.xmode )
|
||||
{
|
||||
out_symbol('+');
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFW_8);
|
||||
}
|
||||
if ( x.prepost )
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
out_line(ph.reg_names[x.reg]);
|
||||
break;
|
||||
|
||||
case o_bit:
|
||||
switch ( x.reg )
|
||||
{
|
||||
case rPSW:
|
||||
out_line("PSW.");
|
||||
switch ( x.value )
|
||||
{
|
||||
case 0:
|
||||
out_line("CY");
|
||||
break;
|
||||
case 4:
|
||||
out_line("AC");
|
||||
break;
|
||||
case 6:
|
||||
out_line("Z");
|
||||
break;
|
||||
case 7:
|
||||
out_line("IE");
|
||||
break;
|
||||
default:
|
||||
out_value(x, OOFW_IMM);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case rA:
|
||||
out_line("A.");
|
||||
out_char(char('0'+x.value));
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( !OutVarName(x, true) )
|
||||
out_value(x, OOF_ADDR | OOFW_16);
|
||||
out_symbol('.');
|
||||
// Look for a bit using its address
|
||||
nec78k0s_t &pm = *static_cast<nec78k0s_t *>(procmod);
|
||||
if ( !pm.nec_find_ioport_bit(*this, (int)x.addr, (int)x.value) )
|
||||
out_char(char('0'+x.value)); // output data as immediate
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
if ( !x.regmode )
|
||||
{
|
||||
out_symbol('#');
|
||||
out_value(x, OOFW_IMM);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_symbol('1');
|
||||
}
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
// output a memory address (e.g. byte_98)
|
||||
if ( x.addr16 )
|
||||
out_symbol('!');
|
||||
// output a name
|
||||
if ( !OutVarName(x, false) )
|
||||
out_value(x, OOF_ADDR | OOFW_16); // output just an address
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
if ( x.addr16 )
|
||||
out_symbol('!');
|
||||
if ( x.form )
|
||||
out_symbol('[');
|
||||
// get linear address
|
||||
ea_t v = to_ea(insn.cs,x.addr);
|
||||
if ( !out_name_expr(x, v, x.addr) )
|
||||
{
|
||||
// print its value
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFW_16);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
if ( x.form )
|
||||
out_symbol(']');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ip, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_nec78k0s_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
out_one_operand(0);
|
||||
|
||||
// more operands?
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');// print delimiter
|
||||
// unless UAS_NOSPA is set, add a space
|
||||
if ( !(ash.uflag & UAS_NOSPA) )
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
if ( !(ash.uflag & UAS_NOSPA) )
|
||||
out_char(' ');
|
||||
out_one_operand(2);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void nec78k0s_t::nec78k0s_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_cmt_line("Processor: %s [%s]",
|
||||
!ioh.device.empty()
|
||||
? ioh.device.c_str()
|
||||
: inf_get_procname().c_str(),
|
||||
ioh.deviceparams.c_str());
|
||||
ctx.gen_cmt_line("Target assebler: %s", ash.name);
|
||||
if ( ash.header != NULL )
|
||||
for ( const char *const *ptr=ash.header; *ptr != NULL; ptr++ )
|
||||
ctx.flush_buf(*ptr, 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi nec78k0s_segstart(outctx_t &, segment_t *)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void nec78k0s_t::nec78k0s_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 )
|
||||
{
|
||||
size_t i = strlen(ash.end);
|
||||
do
|
||||
ctx.out_char(' ');
|
||||
while ( ++i < 8 );
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
262
idasdk76/module/78k0s/reg.cpp
Normal file
262
idasdk76/module/78k0s/reg.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2001 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "78k_0s.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
int data_id;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"X", "A", "C", "B", "E", "D", "L", "H", "AX", "BC", "DE","HL",
|
||||
"PSW", "SP", "s", "cc", "dpr",
|
||||
"CY",
|
||||
"cs", "ds"
|
||||
};
|
||||
//----------------------------------------------------------------------
|
||||
static const asm_t nec78k0s =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0 | ASD_DECF0 | ASO_OCTF0 | ASB_BINF4 | AS_N2CHR | AS_ONEDUP | AS_NOXRF,
|
||||
UAS_NOSPA,
|
||||
"NEC _78K_0S Assembler",
|
||||
0,
|
||||
NULL, // header
|
||||
".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, // no double words
|
||||
NULL, // no qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // no float
|
||||
NULL, // no double
|
||||
NULL, // no tbytes
|
||||
NULL, // no packreal
|
||||
NULL, //".db.#s(b,w) #d,#v", // #h - header(.byte,.word)
|
||||
// #d - size of array
|
||||
// #v - value of array elements
|
||||
// #s - size specifier
|
||||
".rs %s", // uninited data (reserve space)
|
||||
".equ",
|
||||
NULL, // seg prefix
|
||||
"*", // a_curip
|
||||
NULL, // returns function header line
|
||||
NULL, // returns function footer line
|
||||
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
|
||||
};
|
||||
//----------------------------------------------------------------------
|
||||
#define FAMILY "NEC series:"
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"78k0s",
|
||||
NULL
|
||||
};
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"NEC 78K/0S",
|
||||
NULL
|
||||
};
|
||||
static const asm_t *const asms[] =
|
||||
{
|
||||
&nec78k0s,
|
||||
NULL
|
||||
};
|
||||
//--------------------------------------------------------------------------
|
||||
// return opcodes
|
||||
static const uchar retcNEC78K0S_0[] = { 0x24 }; // reti
|
||||
static const uchar retcNEC78K0S_1[] = { 0x20 }; // ret
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcNEC78K0S_0), retcNEC78K0S_0 },
|
||||
{ sizeof(retcNEC78K0S_1), retcNEC78K0S_1 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool nec78k0s_t::nec_find_ioport_bit(outctx_t &ctx, int port, int bit)
|
||||
{
|
||||
// find bit register in the ports list
|
||||
const ioport_bit_t *b = find_ioport_bit(ioh.ports, port, bit);
|
||||
if ( b != NULL && !b->name.empty() )
|
||||
{
|
||||
// output bit register name
|
||||
ctx.out_line(b->name.c_str(), COLOR_IMPNAME);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void nec78k0s_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(nec78k0s_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi nec78k0s_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_be(false);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
inf_set_gen_lzero(true);
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgfile, &cb) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm: // new segment
|
||||
{
|
||||
segment_t *s = va_arg(va, segment_t *);
|
||||
// Set default value of DS register for all segments
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
nec78k0s_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
nec78k0s_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 *);
|
||||
nec78k0s_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;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_NEC_78K0S, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_SEGTRANS,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
Rcs,Rds,
|
||||
0, // size of a segment register
|
||||
Rcs,Rds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0,
|
||||
NEC_78K_0S_last,
|
||||
Instructions, // instruc
|
||||
};
|
||||
597
idasdk76/module/80196/ana.cpp
Normal file
597
idasdk76/module/80196/ana.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
#include "ins.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct wsr_mapping_t
|
||||
{
|
||||
ushort base;
|
||||
uchar wsr;
|
||||
uchar wsrbase;
|
||||
uchar wsr1base;
|
||||
};
|
||||
|
||||
static const wsr_mapping_t mappings[] =
|
||||
{
|
||||
{ 0x0000, 0x10, 0x80, 0xFF }, // 0080-00FF
|
||||
{ 0x0080, 0x11, 0x80, 0xFF },
|
||||
{ 0x0100, 0x12, 0x80, 0xFF },
|
||||
{ 0x0180, 0x13, 0x80, 0xFF },
|
||||
{ 0x0200, 0x14, 0x80, 0xFF },
|
||||
{ 0x0280, 0x15, 0x80, 0xFF },
|
||||
{ 0x0300, 0x16, 0x80, 0xFF },
|
||||
{ 0x0380, 0x17, 0x80, 0xFF },
|
||||
{ 0x1F00, 0x1E, 0x80, 0xFF },
|
||||
{ 0x1F80, 0x1F, 0x80, 0xFF },
|
||||
{ 0x0000, 0x20, 0xC0, 0x40 }, // 00C0-00FF or 0040-007F
|
||||
{ 0x0040, 0x21, 0xC0, 0x40 },
|
||||
{ 0x0080, 0x22, 0xC0, 0x40 },
|
||||
{ 0x00C0, 0x23, 0xC0, 0x40 },
|
||||
{ 0x0100, 0x24, 0xC0, 0x40 },
|
||||
{ 0x0140, 0x25, 0xC0, 0x40 },
|
||||
{ 0x0180, 0x26, 0xC0, 0x40 },
|
||||
{ 0x01C0, 0x27, 0xC0, 0x40 },
|
||||
{ 0x0200, 0x28, 0xC0, 0x40 },
|
||||
{ 0x0240, 0x29, 0xC0, 0x40 },
|
||||
{ 0x0280, 0x2A, 0xC0, 0x40 },
|
||||
{ 0x02C0, 0x2B, 0xC0, 0x40 },
|
||||
{ 0x0300, 0x2C, 0xC0, 0x40 },
|
||||
{ 0x0340, 0x2D, 0xC0, 0x40 },
|
||||
{ 0x0380, 0x2E, 0xC0, 0x40 },
|
||||
{ 0x03C0, 0x2F, 0xC0, 0x40 },
|
||||
{ 0x1F00, 0x3C, 0xC0, 0x40 },
|
||||
{ 0x1F40, 0x3D, 0xC0, 0x40 },
|
||||
{ 0x1F80, 0x3E, 0xC0, 0x40 },
|
||||
{ 0x1FC0, 0x3F, 0xC0, 0x40 },
|
||||
{ 0x0000, 0x40, 0xE0, 0x60 }, // 00E0-00FF or 0060-007F
|
||||
{ 0x0020, 0x41, 0xE0, 0x60 },
|
||||
{ 0x0040, 0x42, 0xE0, 0x60 },
|
||||
{ 0x0060, 0x43, 0xE0, 0x60 },
|
||||
{ 0x0080, 0x44, 0xE0, 0x60 },
|
||||
{ 0x00A0, 0x45, 0xE0, 0x60 },
|
||||
{ 0x00C0, 0x46, 0xE0, 0x60 },
|
||||
{ 0x00E0, 0x47, 0xE0, 0x60 },
|
||||
{ 0x0100, 0x48, 0xE0, 0x60 },
|
||||
{ 0x0120, 0x49, 0xE0, 0x60 },
|
||||
{ 0x0140, 0x4A, 0xE0, 0x60 },
|
||||
{ 0x0160, 0x4B, 0xE0, 0x60 },
|
||||
{ 0x0180, 0x4C, 0xE0, 0x60 },
|
||||
{ 0x01A0, 0x4D, 0xE0, 0x60 },
|
||||
{ 0x01C0, 0x4E, 0xE0, 0x60 },
|
||||
{ 0x01E0, 0x4F, 0xE0, 0x60 },
|
||||
{ 0x0200, 0x50, 0xE0, 0x60 },
|
||||
{ 0x0220, 0x51, 0xE0, 0x60 },
|
||||
{ 0x0240, 0x52, 0xE0, 0x60 },
|
||||
{ 0x0260, 0x53, 0xE0, 0x60 },
|
||||
{ 0x0280, 0x54, 0xE0, 0x60 },
|
||||
{ 0x02A0, 0x55, 0xE0, 0x60 },
|
||||
{ 0x02C0, 0x56, 0xE0, 0x60 },
|
||||
{ 0x02E0, 0x57, 0xE0, 0x60 },
|
||||
{ 0x0300, 0x58, 0xE0, 0x60 },
|
||||
{ 0x0320, 0x59, 0xE0, 0x60 },
|
||||
{ 0x0340, 0x5A, 0xE0, 0x60 },
|
||||
{ 0x0360, 0x5B, 0xE0, 0x60 },
|
||||
{ 0x0380, 0x5C, 0xE0, 0x60 },
|
||||
{ 0x03A0, 0x5D, 0xE0, 0x60 },
|
||||
{ 0x03C0, 0x5E, 0xE0, 0x60 },
|
||||
{ 0x03E0, 0x5F, 0xE0, 0x60 },
|
||||
{ 0x1F00, 0x78, 0xE0, 0x60 },
|
||||
{ 0x1F20, 0x79, 0xE0, 0x60 },
|
||||
{ 0x1F40, 0x7A, 0xE0, 0x60 },
|
||||
{ 0x1F60, 0x7B, 0xE0, 0x60 },
|
||||
{ 0x1F80, 0x7C, 0xE0, 0x60 },
|
||||
{ 0x1FA0, 0x7D, 0xE0, 0x60 },
|
||||
{ 0x1FC0, 0x7E, 0xE0, 0x60 },
|
||||
{ 0x1FE0, 0x7F, 0xE0, 0x60 },
|
||||
};
|
||||
|
||||
static int NT_CDECL cmp(const void *x, const void *y)
|
||||
{
|
||||
const wsr_mapping_t *a = (const wsr_mapping_t *)x;
|
||||
const wsr_mapping_t *b = (const wsr_mapping_t *)y;
|
||||
return a->wsr - b->wsr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// perform WSR/WSR1 mapping
|
||||
ea_t i196_t::map(ea_t iea, ea_t v) const
|
||||
{
|
||||
if ( !extended )
|
||||
return v;
|
||||
if ( v < 0x40 )
|
||||
return v;
|
||||
sel_t wsr = get_sreg(iea, v < 0x80 ? WSR1 : WSR) & 0x7F;
|
||||
if ( wsr < 0x10 )
|
||||
return v;
|
||||
|
||||
wsr_mapping_t key;
|
||||
key.wsr = (char)wsr;
|
||||
wsr_mapping_t *p = (wsr_mapping_t *)
|
||||
bsearch(&key, mappings, qnumber(mappings), sizeof(key), cmp);
|
||||
if ( p == NULL )
|
||||
return v;
|
||||
|
||||
int delta = v < 0x80 ? p->wsr1base : p->wsrbase;
|
||||
if ( v < delta )
|
||||
return v;
|
||||
return v - delta + p->base;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void i196_t::aop(insn_t &insn, uint code, op_t &op)
|
||||
{
|
||||
switch ( code & 3 )
|
||||
{
|
||||
case 0: // direct
|
||||
op.type = o_mem;
|
||||
op.addr = map(insn.ea, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
case 1: // immediate
|
||||
op.type = o_imm;
|
||||
if ( (code & 0x10) == 0 && (code & 0xFC) != 0xAC ) // ldbze always baop
|
||||
{
|
||||
op.dtype = dt_word;
|
||||
op.value = insn.get_next_word();
|
||||
}
|
||||
else
|
||||
{
|
||||
op.value = insn.get_next_byte();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // indirect
|
||||
op.dtype = dt_word;
|
||||
op.addr = insn.get_next_byte();
|
||||
op.type = (op.addr & 1) ? o_indirect_inc : o_indirect;
|
||||
op.addr = map(insn.ea, op.addr & ~1);
|
||||
break;
|
||||
|
||||
case 3: // indexed
|
||||
op.dtype = dt_word;
|
||||
op.type = o_indexed;
|
||||
op.value = insn.get_next_byte(); // short (reg file)
|
||||
op.addr = (op.value & 1) ? insn.get_next_word() : insn.get_next_byte();
|
||||
op.value = map(insn.ea, op.value & ~1);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int i196_t::ld_st(insn_t &insn, ushort itype, char dtype, bool indirect, op_t ®, op_t &mem)
|
||||
{
|
||||
if ( !extended )
|
||||
return 0;
|
||||
insn.itype = itype;
|
||||
reg.dtype = dtype;
|
||||
mem.dtype = dtype;
|
||||
mem.addr = insn.get_next_byte();
|
||||
if ( indirect ) // indirect
|
||||
{
|
||||
mem.type = (mem.addr & 1) ? o_indirect_inc : o_indirect;
|
||||
mem.addr = map(insn.ea, mem.addr & ~1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mem.type = o_indexed;
|
||||
mem.value = map(insn.ea, mem.addr);
|
||||
mem.addr = insn.get_next_word();
|
||||
mem.addr |= insn.get_next_byte() << 16;
|
||||
}
|
||||
reg.type = o_mem;
|
||||
reg.addr = map(insn.ea, insn.get_next_byte());
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int i196_t::ana(insn_t *_insn)
|
||||
{
|
||||
if ( _insn == NULL )
|
||||
return 0;
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
insn.Op1.dtype = dt_byte;
|
||||
insn.Op2.dtype = dt_byte;
|
||||
insn.Op3.dtype = dt_byte;
|
||||
|
||||
uint code = insn.get_next_byte();
|
||||
|
||||
uint nibble0 = (code & 0xF);
|
||||
uint nibble1 = (code >> 4);
|
||||
|
||||
char offc;
|
||||
int32 off;
|
||||
uint tmp;
|
||||
|
||||
if ( nibble1 < 2 ) // 0,1
|
||||
{
|
||||
static const char cmd01[] =
|
||||
{
|
||||
I196_skip, I196_clr, I196_not, I196_neg,
|
||||
I196_xch, I196_dec, I196_ext, I196_inc,
|
||||
I196_shr, I196_shl, I196_shra, I196_xch,
|
||||
I196_shrl, I196_shll, I196_shral, I196_norml,
|
||||
I196_null, I196_clrb, I196_notb, I196_negb,
|
||||
I196_xchb, I196_decb, I196_extb, I196_incb,
|
||||
I196_shrb, I196_shlb, I196_shrab, I196_xchb,
|
||||
I196_est, I196_est, I196_estb, I196_estb
|
||||
};
|
||||
|
||||
insn.itype = cmd01[code & 0x1F];
|
||||
|
||||
if ( insn.itype == I196_null )
|
||||
return 0; // unknown instruction
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0x4: case 0x14: // xch reg,aop direct
|
||||
case 0xB: case 0x1B: // xch reg,aop indexed
|
||||
if ( (code & 0x10) == 0 )
|
||||
insn.Op2.dtype = dt_word;
|
||||
aop(insn, code, insn.Op2);
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
case 0xF: // norml lreg,breg
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
case 0x1C: // est.indirect
|
||||
case 0x1D: // est.indexed
|
||||
return ld_st(insn, I196_est, dt_word, code == 0x1C, insn.Op1, insn.Op2);
|
||||
|
||||
case 0x1E: // estb.indirect
|
||||
case 0x1F: // estb.indexed
|
||||
return ld_st(insn, I196_estb, dt_byte, code == 0x1E, insn.Op1, insn.Op2);
|
||||
|
||||
default: // shifts
|
||||
tmp = insn.get_next_byte();
|
||||
if ( tmp < 16 )
|
||||
{
|
||||
insn.Op2.value = tmp;
|
||||
insn.Op2.type = o_imm;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op2.addr = map(insn.ea, tmp);
|
||||
insn.Op2.type = o_mem;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case 0x0: case 0x1: case 0x2: case 0x3:
|
||||
case 0x5: case 0x6: case 0x7: case 0x11:
|
||||
case 0x12: case 0x13: case 0x15: case 0x16: case 0x17:
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
}
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0x1: case 0x2: case 0x3: case 0x4: case 0x5:
|
||||
case 0x7: case 0x8: case 0x9: case 0xA: case 0xB: case 0x16:
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
|
||||
case 0x6: case 0xC: case 0xD: case 0xE: case 0xF:
|
||||
insn.Op1.dtype = dt_dword;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( nibble1 < 4 ) // 2,3
|
||||
{
|
||||
static const char cmd23[] = { I196_sjmp, I196_scall, I196_jbc, I196_jbs };
|
||||
|
||||
insn.itype = cmd23[ ((code - 0x20) >> 3) & 3 ];
|
||||
|
||||
if ( nibble1 == 2 ) // sjmp/scall
|
||||
{
|
||||
insn.Op1.type = o_near;
|
||||
off = insn.get_next_byte() + ((code & 7) << 8);
|
||||
if ( off & 0x400 )
|
||||
off |= ~0x7FF;
|
||||
else
|
||||
off &= 0x7FF; // make signed
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off); // signed addition
|
||||
// insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else // jbc/jbs
|
||||
{
|
||||
insn.Op2.type = o_bit;
|
||||
insn.Op2.reg = code & 7;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op3.type = o_near;
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op3.addr = truncate(insn.ip + insn.size + offc); // signed addition
|
||||
// insn.Op3.dtype = dt_word;
|
||||
}
|
||||
}
|
||||
else if ( nibble1 < 6 ) // 4,5
|
||||
{
|
||||
static const char cmd45[] =
|
||||
{
|
||||
I196_and3, I196_add3, I196_sub3, I196_mulu3,
|
||||
I196_andb3, I196_addb3, I196_subb3, I196_mulub3
|
||||
};
|
||||
|
||||
insn.itype = cmd45[ ((code - 0x40) >> 2) & 7 ];
|
||||
|
||||
if ( (code & 0x10) == 0 )
|
||||
insn.Op1.dtype = insn.Op2.dtype = insn.Op3.dtype = dt_word;
|
||||
|
||||
if ( (code & 0xc) == 0xc ) // mulu/mulub
|
||||
insn.Op1.dtype++; // word->dword/byte->word
|
||||
|
||||
aop(insn, code, insn.Op3);
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
}
|
||||
else if ( nibble1 < 0xD ) // 6,7,8,9,A,B,C
|
||||
{
|
||||
static const char cmd6c[] =
|
||||
{
|
||||
I196_and2, I196_add2, I196_sub2, I196_mulu2,
|
||||
I196_andb2, I196_addb2, I196_subb2, I196_mulub2,
|
||||
I196_or, I196_xor, I196_cmp, I196_divu,
|
||||
I196_orb, I196_xorb, I196_cmpb, I196_divub,
|
||||
I196_ld, I196_addc, I196_subc, I196_ldbze,
|
||||
I196_ldb, I196_addcb, I196_subcb, I196_ldbse,
|
||||
I196_st, I196_stb, I196_push, I196_pop,
|
||||
I196_null, I196_null, I196_null, I196_null,
|
||||
};
|
||||
|
||||
insn.itype = cmd6c[ ((code - 0x60) >> 2) & 31 ];
|
||||
|
||||
switch ( nibble1 )
|
||||
{
|
||||
case 6: // and/add/sub/mulu
|
||||
case 8: // or/xor/cmp/duvu
|
||||
insn.Op1.dtype = insn.Op2.dtype = dt_word;
|
||||
if ( (nibble0 & 0xC) == 0xC )
|
||||
insn.Op1.dtype++; // mulu/divu
|
||||
break;
|
||||
|
||||
case 0xA: // ld/addc/subc/ldbze
|
||||
insn.Op1.dtype = insn.Op2.dtype = dt_word;
|
||||
if ( (nibble0 & 0xC) == 0xC )
|
||||
insn.Op2.dtype = dt_byte; // ldbze
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( code & 0xFC )
|
||||
{
|
||||
case 0xC0: // st
|
||||
insn.Op2.dtype = dt_word;
|
||||
|
||||
case 0x7C: case 0x9C: case 0xBC: case 0xC8: case 0xCC:
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
|
||||
switch ( code )
|
||||
{
|
||||
case 0xC1:
|
||||
insn.itype = I196_bmov;
|
||||
goto cont1;
|
||||
|
||||
case 0xC5:
|
||||
insn.itype = I196_cmpl;
|
||||
insn.Op2.dtype = dt_dword;
|
||||
goto cont2;
|
||||
|
||||
case 0xCD:
|
||||
insn.itype = I196_bmovi;
|
||||
cont1:
|
||||
insn.Op2.dtype = dt_word;
|
||||
cont2:
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.dtype = dt_dword;
|
||||
// insn.Op1.addr = insn.get_next_byte();
|
||||
// insn.Op1.type = o_mem;
|
||||
goto cont3;
|
||||
|
||||
default:
|
||||
if ( code > 0xC7 )
|
||||
{
|
||||
aop(insn, code, insn.Op1);
|
||||
}
|
||||
else
|
||||
{
|
||||
aop(insn, code, insn.Op2);
|
||||
cont3:
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( nibble1 == 0xD ) // jcc
|
||||
{
|
||||
static const char cmdd[] =
|
||||
{
|
||||
I196_jnst, I196_jnh, I196_jgt, I196_jnc,
|
||||
I196_jnvt, I196_jnv, I196_jge, I196_jne,
|
||||
I196_jst, I196_jh, I196_jle, I196_jc,
|
||||
I196_jvt, I196_jv, I196_jlt, I196_je
|
||||
};
|
||||
|
||||
insn.itype = cmdd[nibble0];
|
||||
|
||||
insn.Op1.type = o_near;
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + offc); // signed addition
|
||||
// insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else if ( nibble1 == 0xE ) // Ex
|
||||
{
|
||||
switch ( nibble0 )
|
||||
{
|
||||
case 0x0: case 0x1: // djnz, djnzw
|
||||
if ( nibble0 & 1 )
|
||||
{
|
||||
insn.itype = I196_djnzw;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = I196_djnz;
|
||||
}
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
offc = insn.get_next_byte();
|
||||
insn.Op2.type = o_near;
|
||||
insn.Op2.addr = truncate(insn.ip + insn.size + offc); // signed addition
|
||||
break;
|
||||
|
||||
case 0x2: // tijmp
|
||||
insn.itype = I196_tijmp;
|
||||
insn.Op1.dtype = insn.Op2.dtype = dt_word;
|
||||
insn.Op2.type = o_indirect;
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op3.type = o_imm;
|
||||
insn.Op3.value = insn.get_next_byte();
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
case 0x3: // br
|
||||
insn.itype = extended ? I196_ebr : I196_br;
|
||||
aop(insn, 2, insn.Op1);
|
||||
break;
|
||||
|
||||
case 0x4: // ebmovi
|
||||
if ( !extended )
|
||||
return 0;
|
||||
insn.itype = I196_ebmovi;
|
||||
insn.Op1.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
case 0x6: // ejmp
|
||||
if ( !extended )
|
||||
return 0;
|
||||
insn.itype = I196_ejmp;
|
||||
insn.Op1.type = o_near;
|
||||
off = insn.get_next_word();
|
||||
off |= int32(insn.get_next_byte()) << 16;
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off); // signed addition
|
||||
break;
|
||||
|
||||
case 0x8: // eld.indirect
|
||||
case 0x9: // eld.indexed
|
||||
return ld_st(insn, I196_eld, dt_word, nibble0 == 0x8, insn.Op1, insn.Op2);
|
||||
|
||||
case 0xA: // eldb.indirect
|
||||
case 0xB: // eldb.indexed
|
||||
return ld_st(insn, I196_eldb, dt_byte, nibble0 == 0xA, insn.Op1, insn.Op2);
|
||||
|
||||
case 0xC: // dpts
|
||||
insn.itype = I196_dpts;
|
||||
break;
|
||||
|
||||
case 0xD: // epts
|
||||
insn.itype = I196_epts;
|
||||
break;
|
||||
|
||||
case 0x7: case 0xF: // ljmp, lcall
|
||||
insn.itype = (nibble0 & 8) ? I196_lcall : I196_ljmp;
|
||||
insn.Op1.type = o_near;
|
||||
off = short(insn.get_next_word());
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off); // signed addition
|
||||
insn.Op1.dtype = dt_word;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char cmdf[] =
|
||||
{
|
||||
I196_ret, I196_ecall,I196_pushf, I196_popf,
|
||||
I196_pusha, I196_popa, I196_idlpd, I196_trap,
|
||||
I196_clrc, I196_setc, I196_di, I196_ei,
|
||||
I196_clrvt, I196_nop, I196_null, I196_rst
|
||||
};
|
||||
|
||||
insn.itype = cmdf[nibble0];
|
||||
if ( nibble0 == 1 ) // ecall
|
||||
{
|
||||
if ( !extended )
|
||||
return 0;
|
||||
off = insn.get_next_word();
|
||||
off |= int32(insn.get_next_byte()) << 16;
|
||||
insn.Op1.type = o_near;
|
||||
insn.Op1.addr = truncate(insn.ip + insn.size + off);
|
||||
}
|
||||
else if ( nibble0 == 6 ) // idlpd
|
||||
{
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = insn.get_next_byte();
|
||||
}
|
||||
else if ( nibble0 == 0xE ) // prefix
|
||||
{
|
||||
code = insn.get_next_byte();
|
||||
|
||||
switch ( code & 0xFC )
|
||||
{
|
||||
case 0x4C: case 0x5C:
|
||||
if ( code & 0x10 )
|
||||
{
|
||||
insn.itype = I196_mulb3;
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = I196_mul3;
|
||||
insn.Op3.dtype = insn.Op2.dtype = dt_word;
|
||||
insn.Op1.dtype = dt_dword;
|
||||
}
|
||||
|
||||
aop(insn, code, insn.Op3);
|
||||
insn.Op2.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
case 0x6C: case 0x7C: case 0x8C: case 0x9C:
|
||||
insn.itype = (code & 0x80)
|
||||
? (code & 0x10) ? I196_divb : I196_div
|
||||
: (code & 0x10) ? I196_mulb2 : I196_mul2;
|
||||
|
||||
if ( code & 0x10 )
|
||||
{
|
||||
insn.Op1.dtype = dt_word;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op1.dtype = dt_dword;
|
||||
insn.Op2.dtype = dt_word;
|
||||
}
|
||||
|
||||
aop(insn, code, insn.Op2);
|
||||
insn.Op1.addr = map(insn.ea, insn.get_next_byte());
|
||||
insn.Op1.type = o_mem;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return insn.size;
|
||||
}
|
||||
92
idasdk76/module/80196/emu.cpp
Normal file
92
idasdk76/module/80196/emu.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void i196_t::handle_operand(const insn_t &insn, const op_t &x, int isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
set_immd(insn.ea);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, OOF_SIGNED);
|
||||
break;
|
||||
case o_indexed: // addr[value]
|
||||
set_immd(insn.ea);
|
||||
if ( x.value == 0 && !is_defarg(get_flags(insn.ea), x.n) )
|
||||
op_plain_offset(insn.ea, x.n, to_ea(insn.cs, 0));
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) ) // xref to addr
|
||||
{
|
||||
insn_t tmp = insn;
|
||||
tmp.ops[x.n].value = x.addr;
|
||||
tmp.add_off_drefs(tmp.ops[x.n], x.value ? dr_O : isload ? dr_R : dr_W, OOF_SIGNED|OOF_ADDR);
|
||||
}
|
||||
if ( x.value != 0 ) // xref to value
|
||||
{ // no references to ZERO_REG
|
||||
ea_t ea = to_ea(insn.cs, x.value);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_indirect:
|
||||
case o_indirect_inc:
|
||||
case o_mem:
|
||||
{
|
||||
ea_t dea = to_ea(insn.cs, x.addr);
|
||||
insn.create_op_data(dea, x);
|
||||
insn.add_dref(dea, x.offb, isload ? dr_R : dr_W);
|
||||
if ( !isload && (x.addr == 0x14 || x.addr == 0x15) )
|
||||
{
|
||||
sel_t wsrval = BADSEL;
|
||||
if ( insn.Op2.type == o_imm )
|
||||
wsrval = sel_t(insn.Op2.value);
|
||||
split_sreg_range(insn.ea, x.addr == 0x14 ? WSR : WSR1, wsrval, SR_auto);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int i196_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, 1);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, 1);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, 1);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, 0);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, 0);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, 0);
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I196_popa:
|
||||
split_sreg_range(insn.ea, WSR, BADSEL, SR_auto);
|
||||
split_sreg_range(insn.ea, WSR1, BADSEL, SR_auto);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
63
idasdk76/module/80196/i196.hpp
Normal file
63
idasdk76/module/80196/i196.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I196_HPP
|
||||
#define _I196_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <segregs.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// customization of cmd structure:
|
||||
|
||||
#define o_indirect o_idpspec0 // [addr]
|
||||
#define o_indirect_inc o_idpspec1 // [addr]+
|
||||
#define o_indexed o_idpspec2 // addr[value]
|
||||
#define o_bit o_idpspec3
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
enum i196_registers { rVcs, rVds, WSR, WSR1 };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uchar addr;
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
} predefined_t;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void idaapi i196_header(outctx_t &ctx);
|
||||
void idaapi i196_footer(outctx_t &ctx);
|
||||
|
||||
void idaapi i196_segend(outctx_t &ctx, segment_t *seg);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct i196_t : public procmod_t
|
||||
{
|
||||
int extended = 0;
|
||||
int flow = false;
|
||||
|
||||
inline uint32 truncate(ea_t x)
|
||||
{
|
||||
return x & (extended ? 0xFFFFF : 0xFFFF);
|
||||
}
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
ea_t map(ea_t iea, ea_t v) const;
|
||||
void aop(insn_t &insn, uint code, op_t &op);
|
||||
int ld_st(insn_t &insn, ushort itype, char dtype, bool indirect, op_t ®, op_t &mem);
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &x, int isload);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void i196_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
180
idasdk76/module/80196/ins.cpp
Normal file
180
idasdk76/module/80196/ins.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
{ "add", CF_USE2|CF_USE1|CF_CHG1 }, // Add words (2 operands)
|
||||
{ "add", CF_USE3|CF_USE2|CF_CHG1 }, // Add words (3 operands)
|
||||
{ "addb", CF_USE2|CF_USE1|CF_CHG1 }, // Add bytes (2 operands)
|
||||
{ "addb", CF_USE3|CF_USE2|CF_CHG1 }, // Add bytes (3 operands)
|
||||
|
||||
{ "addc", CF_USE2|CF_USE1|CF_CHG1 }, // Add words with carry
|
||||
{ "addcb", CF_USE2|CF_USE1|CF_CHG1 }, // Add bytes with carry
|
||||
|
||||
{ "and", CF_USE2|CF_USE1|CF_CHG1 }, // Logical AND words (2 operands)
|
||||
{ "and", CF_USE3|CF_USE2|CF_CHG1 }, // Logical AND words (3 operands)
|
||||
{ "andb", CF_USE2|CF_USE1|CF_CHG1 }, // Logical AND bytes (2 operands)
|
||||
{ "andb", CF_USE3|CF_USE2|CF_CHG1 }, // Logical AND bytes (3 operands)
|
||||
|
||||
{ "bmov", CF_USE2|CF_USE1 }, // Block move
|
||||
{ "bmovi", CF_USE2|CF_USE1 }, // Interruptable block move
|
||||
|
||||
{ "br", CF_JUMP|CF_USE1|CF_STOP }, // Branch indirect
|
||||
|
||||
{ "clr", CF_CHG1 }, // Clear word
|
||||
{ "clrb", CF_CHG1 }, // Clear byte
|
||||
{ "clrc", 0 }, // Clear carry flag
|
||||
{ "clrvt", 0 }, // Clear overflow-trap flag
|
||||
|
||||
{ "cmp", CF_USE2|CF_USE1 }, // Compare words
|
||||
{ "cmpb", CF_USE2|CF_USE1 }, // Compare bytes
|
||||
{ "cmpl", CF_USE2|CF_USE1 }, // Compare long
|
||||
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // Decrement word
|
||||
{ "decb", CF_USE1|CF_CHG1 }, // Decrement byte
|
||||
|
||||
{ "di", 0 }, // Disable interrupts
|
||||
|
||||
{ "div", CF_USE2|CF_USE1|CF_CHG1 }, // Divide integers
|
||||
{ "divb", CF_USE2|CF_USE1|CF_CHG1 }, // Divide short-integers
|
||||
{ "divu", CF_USE2|CF_USE1|CF_CHG1 }, // Divide words, unsigned
|
||||
{ "divub", CF_USE2|CF_USE1|CF_CHG1 }, // Divide bytes, unsigned
|
||||
|
||||
{ "djnz", CF_USE2|CF_USE1|CF_CHG1 }, // Decrement and jump if not zero
|
||||
{ "djnzw", CF_USE2|CF_USE1|CF_CHG1 }, // Decrement and jump if not zero word
|
||||
|
||||
{ "dpts", 0 }, // Disable peripheral transaction server
|
||||
|
||||
{ "ei", 0 }, // Enable interrupts
|
||||
|
||||
{ "epts", 0 }, // Enable peripheral transaction server
|
||||
|
||||
{ "ext", CF_USE1|CF_CHG1 }, // Sign-extend integer into long-integer
|
||||
{ "extb", CF_USE1|CF_CHG1 }, // Sign-extend short-integer into integer
|
||||
|
||||
{ "idlpd", CF_USE1 }, // Idle/powerdown
|
||||
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // Increment word
|
||||
{ "incb", CF_USE1|CF_CHG1 }, // Increment byte
|
||||
|
||||
{ "jbc", CF_USE3|CF_USE2|CF_USE1 }, // Jump if bit is clear
|
||||
{ "jbs", CF_USE3|CF_USE2|CF_USE1 }, // Jump if bit is set
|
||||
{ "jc", CF_USE1 }, // Jump if carry flag is set
|
||||
{ "je", CF_USE1 }, // Jump if equal
|
||||
{ "jge", CF_USE1 }, // Jump if signed greater than or equal
|
||||
{ "jgt", CF_USE1 }, // Jump if signed greater than
|
||||
{ "jh", CF_USE1 }, // Jump if higher (unsigned)
|
||||
{ "jle", CF_USE1 }, // Jump if signed less than or equal
|
||||
{ "jlt", CF_USE1 }, // Jump if signed less than
|
||||
{ "jnc", CF_USE1 }, // Jump if carry flag is clear
|
||||
{ "jne", CF_USE1 }, // Jump if not equal
|
||||
{ "jnh", CF_USE1 }, // Jump if not higher (unsigned)
|
||||
{ "jnst", CF_USE1 }, // Jump if sticky bit flag is clear
|
||||
{ "jnv", CF_USE1 }, // Jump if overflow flag is clear
|
||||
{ "jnvt", CF_USE1 }, // Jump if overflow-trap flag is clear
|
||||
{ "jst", CF_USE1 }, // Jump if sticky bit flag is set
|
||||
{ "jv", CF_USE1 }, // Jump if overflow flag is set
|
||||
{ "jvt", CF_USE1 }, // Jump if overflow-trap flag is set
|
||||
|
||||
{ "lcall", CF_USE1|CF_CALL }, // Long call
|
||||
|
||||
{ "ld", CF_USE2|CF_CHG1 }, // Load word
|
||||
{ "ldb", CF_USE2|CF_CHG1 }, // Load byte
|
||||
{ "ldbse", CF_USE2|CF_CHG1 }, // Load byte sign-extended
|
||||
{ "ldbze", CF_USE2|CF_CHG1 }, // Load byte zero-extended
|
||||
|
||||
{ "ljmp", CF_USE1|CF_STOP }, // Long jump
|
||||
|
||||
{ "mul", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply integers (2 operands)
|
||||
{ "mul", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply integers (3 operands)
|
||||
{ "mulb", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply short-integers (2 operands)
|
||||
{ "mulb", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply short-integers (3 operands)
|
||||
{ "mulu", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply words, unsigned (2 operands)
|
||||
{ "mulu", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply words, unsigned (3 operands)
|
||||
{ "mulub", CF_USE2|CF_USE1|CF_CHG1 }, // Multiply bytes, unsigned (2 operands)
|
||||
{ "mulub", CF_USE3|CF_USE2|CF_CHG1 }, // Multiply bytes, unsigned (3 operands)
|
||||
|
||||
{ "neg", CF_USE1|CF_CHG1 }, // Negate integer
|
||||
{ "negb", CF_USE1|CF_CHG1 }, // Negate short-integer
|
||||
|
||||
{ "nop", 0 }, // No operation
|
||||
|
||||
{ "norml", CF_USE1|CF_CHG2|CF_CHG1 }, // Normalize long-integer
|
||||
|
||||
{ "not", CF_USE1|CF_CHG1 }, // Complement word
|
||||
{ "notb", CF_USE1|CF_CHG1 }, // Complement byte
|
||||
|
||||
{ "or", CF_USE2|CF_USE1|CF_CHG1 }, // Logical OR words
|
||||
{ "orb", CF_USE2|CF_USE1|CF_CHG1 }, // Logical OR bytes
|
||||
|
||||
{ "pop", CF_CHG1 }, // Pop word
|
||||
{ "popa", 0 }, // Pop all
|
||||
{ "popf", 0 }, // Pop flags
|
||||
{ "push", CF_USE1 }, // Push word
|
||||
{ "pusha", 0 }, // Push all
|
||||
{ "pushf", 0 }, // Push flags
|
||||
|
||||
{ "ret", CF_STOP }, // Return from subroutine
|
||||
|
||||
{ "rst", CF_STOP }, // Reset system
|
||||
|
||||
{ "scall", CF_USE1|CF_CALL }, // Short call
|
||||
|
||||
{ "setc", 0 }, // Set carry flag
|
||||
|
||||
{ "shl", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Shift word left
|
||||
{ "shlb", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Shift byte left
|
||||
{ "shll", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Shift double-word left
|
||||
{ "shr", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Logical right shift word
|
||||
{ "shra", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Arithmetic right shift word
|
||||
{ "shrab", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Arithmetic right shift byte
|
||||
{ "shral", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Arithmetic right shift double-word
|
||||
{ "shrb", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Logical right shift byte
|
||||
{ "shrl", CF_SHFT|CF_USE2|CF_USE1|CF_CHG1 }, // Logical right shift double-word
|
||||
|
||||
{ "sjmp", CF_USE1|CF_STOP }, // Short jump
|
||||
|
||||
{ "skip", CF_USE1 }, // Two byte no-operation
|
||||
|
||||
{ "st", CF_USE1|CF_CHG2 }, // Store word
|
||||
{ "stb", CF_USE1|CF_CHG2 }, // Store byte
|
||||
|
||||
{ "sub", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract words (2 operands)
|
||||
{ "sub", CF_USE3|CF_USE2|CF_CHG1 }, // Subtract words (3 operands)
|
||||
{ "subb", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract bytes (2 operands)
|
||||
{ "subb", CF_USE3|CF_USE2|CF_CHG1 }, // subtract bytes (3 operands)
|
||||
|
||||
{ "subc", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract words with borrow
|
||||
{ "subcb", CF_USE2|CF_USE1|CF_CHG1 }, // Subtract bytes with borrow
|
||||
|
||||
{ "tijmp", CF_JUMP|CF_USE3|CF_USE2|CF_USE1|CF_STOP }, // Table indirect jump
|
||||
|
||||
{ "trap", 0 }, // Software trap
|
||||
|
||||
{ "xch", CF_USE2|CF_USE1|CF_CHG2|CF_CHG1 }, // Exchange word
|
||||
{ "xchb", CF_USE2|CF_USE1|CF_CHG2|CF_CHG1 }, // Exchange byte
|
||||
|
||||
{ "xor", CF_USE2|CF_USE1|CF_CHG1 }, // Logical exclusive-or words
|
||||
{ "xorb", CF_USE2|CF_USE1|CF_CHG1 }, // Logical exclusive-or bytes
|
||||
|
||||
// 8x196NU, NP instructions
|
||||
|
||||
{ "ebmovi", CF_USE1|CF_USE2 }, // Extended interruptable block move
|
||||
{ "ebr", CF_USE1|CF_STOP }, // Extended branch indirect
|
||||
{ "ecall", CF_USE1|CF_CALL }, // Extended call
|
||||
{ "ejmp", CF_USE1|CF_STOP }, // Extended jump
|
||||
{ "eld", CF_CHG1|CF_USE2 }, // Extended load word
|
||||
{ "eldb", CF_CHG1|CF_USE2 }, // Extended load byte
|
||||
{ "est", CF_USE1|CF_CHG2 }, // Extended store word
|
||||
{ "estb", CF_USE1|CF_CHG2 }, // Extended store byte
|
||||
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == I196_last);
|
||||
184
idasdk76/module/80196/ins.hpp
Normal file
184
idasdk76/module/80196/ins.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
I196_null = 0, // Unknown Operation
|
||||
|
||||
I196_add2, // Add words (2 operands)
|
||||
I196_add3, // Add words (3 operands)
|
||||
I196_addb2, // Add bytes (2 operands)
|
||||
I196_addb3, // Add bytes (3 operands)
|
||||
|
||||
I196_addc, // Add words with carry
|
||||
I196_addcb, // Add bytes with carry
|
||||
|
||||
I196_and2, // Logical AND words (2 operands)
|
||||
I196_and3, // Logical AND words (3 operands)
|
||||
I196_andb2, // Logical AND bytes (2 operands)
|
||||
I196_andb3, // Logical AND bytes (3 operands)
|
||||
|
||||
I196_bmov, // Block move
|
||||
I196_bmovi, // Interruptable block move
|
||||
|
||||
I196_br, // Branch indirect
|
||||
|
||||
I196_clr, // Clear word
|
||||
I196_clrb, // Clear byte
|
||||
I196_clrc, // Clear carry flag
|
||||
I196_clrvt, // Clear overflow-trap flag
|
||||
|
||||
I196_cmp, // Compare words
|
||||
I196_cmpb, // Compare bytes
|
||||
I196_cmpl, // Compare long
|
||||
|
||||
I196_dec, // Decrement word
|
||||
I196_decb, // Decrement byte
|
||||
|
||||
I196_di, // Disable interrupts
|
||||
|
||||
I196_div, // Divide integers
|
||||
I196_divb, // Divide short-integers
|
||||
I196_divu, // Divide words, unsigned
|
||||
I196_divub, // Divide bytes, unsigned
|
||||
|
||||
I196_djnz, // Decrement and jump if not zero
|
||||
I196_djnzw, // Decrement and jump if not zero word
|
||||
|
||||
I196_dpts, // Disable peripheral transaction server
|
||||
|
||||
I196_ei, // Enable interrupts
|
||||
|
||||
I196_epts, // Enable peripheral transaction server
|
||||
|
||||
I196_ext, // Sign-extend integer into long-integer
|
||||
I196_extb, // Sign-extend short-integer into integer
|
||||
|
||||
I196_idlpd, // Idle/powerdown
|
||||
|
||||
I196_inc, // Increment word
|
||||
I196_incb, // Increment byte
|
||||
|
||||
I196_jbc, // Jump if bit is clear
|
||||
I196_jbs, // Jump if bit is set
|
||||
I196_jc, // Jump if carry flag is set
|
||||
I196_je, // Jump if equal
|
||||
I196_jge, // Jump if signed greater than or equal
|
||||
I196_jgt, // Jump if signed greater than
|
||||
I196_jh, // Jump if higher (unsigned)
|
||||
I196_jle, // Jump if signed less than or equal
|
||||
I196_jlt, // Jump if signed less than
|
||||
I196_jnc, // Jump if carry flag is clear
|
||||
I196_jne, // Jump if not equal
|
||||
I196_jnh, // Jump if not higher (unsigned)
|
||||
I196_jnst, // Jump if sticky bit flag is clear
|
||||
I196_jnv, // Jump if overflow flag is clear
|
||||
I196_jnvt, // Jump if overflow-trap flag is clear
|
||||
I196_jst, // Jump if sticky bit flag is set
|
||||
I196_jv, // Jump if overflow flag is set
|
||||
I196_jvt, // Jump if overflow-trap flag is set
|
||||
|
||||
I196_lcall, // Long call
|
||||
|
||||
I196_ld, // Load word
|
||||
I196_ldb, // Load byte
|
||||
I196_ldbse, // Load byte sign-extended
|
||||
I196_ldbze, // Load byte zero-extended
|
||||
|
||||
I196_ljmp, // Long jump
|
||||
|
||||
I196_mul2, // Multiply integers (2 operands)
|
||||
I196_mul3, // Multiply integers (3 operands)
|
||||
I196_mulb2, // Multiply short-integers (2 operands)
|
||||
I196_mulb3, // Multiply short-integers (3 operands)
|
||||
I196_mulu2, // Multiply words, unsigned (2 operands)
|
||||
I196_mulu3, // Multiply words, unsigned (3 operands)
|
||||
I196_mulub2, // Multiply bytes, unsigned (2 operands)
|
||||
I196_mulub3, // Multiply bytes, unsigned (3 operands)
|
||||
|
||||
I196_neg, // Negate integer
|
||||
I196_negb, // Negate short-integer
|
||||
|
||||
I196_nop, // No operation
|
||||
|
||||
I196_norml, // Normalize long-integer
|
||||
|
||||
I196_not, // Complement word
|
||||
I196_notb, // Complement byte
|
||||
|
||||
I196_or, // Logical OR words
|
||||
I196_orb, // Logical OR bytes
|
||||
|
||||
I196_pop, // Pop word
|
||||
I196_popa, // Pop all
|
||||
I196_popf, // Pop flags
|
||||
I196_push, // Push word
|
||||
I196_pusha, // Push all
|
||||
I196_pushf, // Push flags
|
||||
|
||||
I196_ret, // Return from subroutine
|
||||
|
||||
I196_rst, // Reset system
|
||||
|
||||
I196_scall, // Short call
|
||||
|
||||
I196_setc, // Set carry flag
|
||||
|
||||
I196_shl, // Shift word left
|
||||
I196_shlb, // Shift byte left
|
||||
I196_shll, // Shift double-word left
|
||||
I196_shr, // Logical right shift word
|
||||
I196_shra, // Arithmetic right shift word
|
||||
I196_shrab, // Arithmetic right shift byte
|
||||
I196_shral, // Arithmetic right shift double-word
|
||||
I196_shrb, // Logical right shift byte
|
||||
I196_shrl, // Logical right shift double-word
|
||||
|
||||
I196_sjmp, // Short jump
|
||||
|
||||
I196_skip, // Two byte no-operation
|
||||
|
||||
I196_st, // Store word
|
||||
I196_stb, // Store byte
|
||||
|
||||
I196_sub2, // Subtract words (2 operands)
|
||||
I196_sub3, // Subtract words (3 operands)
|
||||
I196_subb2, // Subtract bytes (2 operands)
|
||||
I196_subb3, // subtract bytes (3 operands)
|
||||
|
||||
I196_subc, // Subtract words with borrow
|
||||
I196_subcb, // Subtract bytes with borrow
|
||||
|
||||
I196_tijmp, // Table indirect jump
|
||||
|
||||
I196_trap, // Software trap
|
||||
|
||||
I196_xch, // Exchange word
|
||||
I196_xchb, // Exchange byte
|
||||
|
||||
I196_xor, // Logical exclusive-or words
|
||||
I196_xorb, // Logical exclusive-or bytes
|
||||
|
||||
// 8x196NU, NP instructions
|
||||
|
||||
I196_ebmovi, // Extended interruptable block move
|
||||
I196_ebr, // Extended branch indirect
|
||||
I196_ecall, // Extended call
|
||||
I196_ejmp, // Extended jump
|
||||
I196_eld, // Extended load word
|
||||
I196_eldb, // Extended load byte
|
||||
I196_est, // Extended store word
|
||||
I196_estb, // Extended store byte
|
||||
|
||||
I196_last
|
||||
};
|
||||
|
||||
#endif
|
||||
50
idasdk76/module/80196/makefile
Normal file
50
idasdk76/module/80196/makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
PROC=i196
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 \
|
||||
ana.cpp i196.hpp ins.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 \
|
||||
emu.cpp i196.hpp ins.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 \
|
||||
i196.hpp ins.cpp ins.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 \
|
||||
i196.hpp ins.hpp out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 \
|
||||
i196.hpp ins.hpp reg.cpp
|
||||
168
idasdk76/module/80196/out.cpp
Normal file
168
idasdk76/module/80196/out.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_i196_t : public outctx_t
|
||||
{
|
||||
out_i196_t(void) = delete; // not used
|
||||
public:
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_i196_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_i196_t)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi i196_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_PROC_AND_ASM);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi i196_footer(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void i196_t::i196_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, Sarea);
|
||||
ctx.gen_cmt_line(COLSTR("segment %s", SCOLOR_AUTOCMT), name.c_str());
|
||||
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_cmt_line("%s %s", ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(818, seg) could be made const
|
||||
void idaapi i196_segend(outctx_t &ctx, segment_t *seg)
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, seg);
|
||||
ctx.gen_cmt_line("end of '%s'", name.c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_i196_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
out_one_operand(0);
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool is_ext_insn(const insn_t &insn)
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I196_ebmovi: // Extended interruptable block move
|
||||
case I196_ebr: // Extended branch indirect
|
||||
case I196_ecall: // Extended call
|
||||
case I196_ejmp: // Extended jump
|
||||
case I196_eld: // Extended load word
|
||||
case I196_eldb: // Extended load byte
|
||||
case I196_est: // Extended store word
|
||||
case I196_estb: // Extended store byte
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_i196_t::out_operand(const op_t &x)
|
||||
{
|
||||
uval_t v, v1;
|
||||
// const char *ptr;
|
||||
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
out_value(x, OOF_SIGNED | OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_indexed:
|
||||
out_value(x, OOF_ADDR|OOF_SIGNED|(is_ext_insn(insn) ? OOFW_32 : OOFW_16)); //.addr
|
||||
v = x.value;
|
||||
out_symbol('[');
|
||||
if ( v != 0 )
|
||||
goto OUTPHRASE;
|
||||
out_symbol(']');
|
||||
break;
|
||||
|
||||
case o_indirect:
|
||||
case o_indirect_inc:
|
||||
out_symbol('[');
|
||||
// fallthrough
|
||||
|
||||
case o_mem:
|
||||
case o_near:
|
||||
v = x.addr;
|
||||
OUTPHRASE:
|
||||
v1 = to_ea(get_sreg(insn.ea, (x.type == o_near) ? rVcs : rVds), v);
|
||||
if ( !out_name_expr(x, v1, v ) )
|
||||
{
|
||||
out_value(x, (x.type == o_indexed ? 0 : OOF_ADDR)
|
||||
| OOF_NUMBER|OOFS_NOSIGN
|
||||
| (x.type == o_near
|
||||
? (is_ext_insn(insn) ? OOFW_32 : OOFW_16)
|
||||
: OOFW_8));
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
|
||||
if ( x.type == o_indirect
|
||||
|| x.type == o_indirect_inc
|
||||
|| x.type == o_indexed )
|
||||
{
|
||||
out_symbol(']');
|
||||
if ( x.type == o_indirect_inc )
|
||||
out_symbol('+');
|
||||
}
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_bit:
|
||||
out_symbol(char('0' + x.reg));
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
500
idasdk76/module/80196/reg.cpp
Normal file
500
idasdk76/module/80196/reg.cpp
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Intel 80196 module
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i196.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const predefined_t iregs[] =
|
||||
{
|
||||
{ 0x00, "ZERO_REG", "Zero register" },
|
||||
{ 0x08, "INT_MASK", "Interrupt mask register" },
|
||||
{ 0x09, "INT_PEND", "Interrupt pending register" },
|
||||
{ 0x0F, "IOPORT1", "Input/output port 1" },
|
||||
{ 0x10, "IOPORT2", "Input/output port 2" },
|
||||
{ 0x12, "INT_PEND1", "Interrupt pending register 1" },
|
||||
{ 0x13, "INT_MASK1", "Interrupt mask register 1" },
|
||||
{ 0x14, "WSR", "Window selection register" },
|
||||
{ 0x15, "WSR1", "Window selection register 1" },
|
||||
{ 0x18, "SP", "Stack pointer" },
|
||||
{ 0x00, NULL, NULL }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/* 80196 memory map
|
||||
*
|
||||
* 0000-03FF - register file
|
||||
* 0000 - CPU SFRs
|
||||
* 0018 - SP (LO)
|
||||
* 0019 - SP (HI)
|
||||
* 001A - Register RAM
|
||||
* 0100 - Register RAM (upper file)
|
||||
* 0400-1FFD - ext memory
|
||||
* 1FFE - port 3 (word)
|
||||
* 1FFF - port 4 (word)
|
||||
* 2000-207F - special purpose memory
|
||||
* 2000 - lower int vectors
|
||||
* 2000 - INT00 - Timer overflow
|
||||
* 2002 - INT01 - A/D conversion complete
|
||||
* 2004 - INT02 - HSI data available
|
||||
* 2006 - INT03 - High speed output
|
||||
* 2008 - INT04 - HSI.0
|
||||
* 200A - INT05 - Software timer
|
||||
* 200C - INT06 - Serial port
|
||||
* 200E - INT07 - EXTINT
|
||||
* 2010 - Software trap
|
||||
* 2012 - Unimplemented opcode
|
||||
* 2014 - reserved (FF)
|
||||
* 2018 - CCB
|
||||
* D0 - PD - Power down
|
||||
* D1 - BW0 - Bus width control
|
||||
* D2 - WR - Write strobe mode
|
||||
* D3 - ALE - Addres valid strobe mode
|
||||
* D45 - IRC - Internal ready control
|
||||
* D67 - LOC - Lock bits
|
||||
* 2019 - reserved (20)
|
||||
* 201A - reserved (FF)
|
||||
* 2020 - security key
|
||||
* 2030 - upper int vectors
|
||||
* 2030 - INT08 - Transmit
|
||||
* 2032 - INT09 - Receive
|
||||
* 2034 - INT10 - HSI FIFO 4
|
||||
* 2036 - INT11 - Timer 2 capture
|
||||
* 2038 - INT12 - Timer 2 overflow
|
||||
* 203A - INT13 - EXTINT1
|
||||
* 203C - INT14 - HSI FIFO FULL
|
||||
* 203E - INT15 - NMI
|
||||
* 2040 - PTS vectors
|
||||
* 2040 - INT00 - Timer overflow
|
||||
* 2042 - INT01 - A/D conversion complete
|
||||
* 2044 - INT02 - HSI data available
|
||||
* 2046 - INT03 - High speed output
|
||||
* 2048 - INT04 - HSI.0
|
||||
* 204A - INT05 - Software timer
|
||||
* 204C - INT06 - Serial port
|
||||
* 204E - INT07 - EXTINT
|
||||
* 2050 - INT08 - Transmit
|
||||
* 2052 - INT09 - Receive
|
||||
* 2054 - INT10 - HSI FIFO 4
|
||||
* 2056 - INT11 - Timer 2 capture
|
||||
* 2058 - INT12 - Timer 2 overflow
|
||||
* 205A - INT13 - EXTINT1
|
||||
* 205C - INT14 - HSI FIFO FULL
|
||||
* 205E - reserved (FF)
|
||||
* 2080-FFFF - program/ext memory
|
||||
*/
|
||||
|
||||
#define I196F_CMT 0 // global comment
|
||||
#define I196F_OFF 1 // offset to code
|
||||
#define I196F_BTS 2 // byte(s)
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
char type;
|
||||
int off; //lint !e958 padding is required to align members
|
||||
const char *name;
|
||||
const char *cmt;
|
||||
};
|
||||
|
||||
static const char cmt01[] = "Timer overflow";
|
||||
static const char cmt02[] = "A/D conversion complete";
|
||||
static const char cmt03[] = "HSI data available";
|
||||
static const char cmt04[] = "High speed output";
|
||||
static const char cmt05[] = "HSI.0";
|
||||
static const char cmt06[] = "Software timer";
|
||||
static const char cmt07[] = "Serial port";
|
||||
static const char cmt08[] = "EXTINT";
|
||||
static const char cmt09[] = "reserved (FF)";
|
||||
static const char cmt10[] = "Transmit";
|
||||
static const char cmt11[] = "Receive";
|
||||
static const char cmt12[] = "HSI FIFO 4";
|
||||
static const char cmt13[] = "Timer 2 capture";
|
||||
static const char cmt14[] = "Timer 2 overflow";
|
||||
static const char cmt15[] = "EXTINT1";
|
||||
static const char cmt16[] = "HSI FIFO FULL";
|
||||
|
||||
static entry_t const entries[] =
|
||||
{
|
||||
//
|
||||
// { I196F_CMT, 0x2000, 0, "\nlower int vectors\n" },
|
||||
|
||||
{ I196F_OFF, 0x2000, "Int00", cmt01 },
|
||||
{ I196F_OFF, 0x2002, "Int01", cmt02 },
|
||||
{ I196F_OFF, 0x2004, "Int02", cmt03 },
|
||||
{ I196F_OFF, 0x2006, "Int03", cmt04 },
|
||||
{ I196F_OFF, 0x2008, "Int04", cmt05 },
|
||||
{ I196F_OFF, 0x200A, "Int05", cmt06 },
|
||||
{ I196F_OFF, 0x200C, "Int06", cmt07 },
|
||||
{ I196F_OFF, 0x200E, "Int07", cmt08 },
|
||||
{ I196F_OFF, 0x2010, "Trap", "Software trap" },
|
||||
{ I196F_OFF, 0x2012, "NoOpCode", "Unimplemented opcode" },
|
||||
|
||||
{ I196F_CMT, 0x2014, 0, 0 }, // empty line
|
||||
|
||||
{ I196F_BTS, 0x2014, 0, cmt09 },
|
||||
{ I196F_BTS, 0x2018, "CCB", "D0 - PD - Power down\n"
|
||||
"D1 - BW0 - Bus width control\n"
|
||||
"D2 - WR - Write strobe mode\n"
|
||||
"D3 - ALE - Addres valid strobe mode\n"
|
||||
"D45 - IRC - Internal ready control\n"
|
||||
"D67 - LOC - Lock bits" },
|
||||
{ I196F_BTS, 0x2019, 0, "reserved (20)" },
|
||||
{ I196F_BTS, 0x201A, 0, cmt09 },
|
||||
{ I196F_BTS, 0x2020, 0, "security key" },
|
||||
|
||||
{ I196F_CMT, 0x2030, 0, "\nupper int vectors\n" },
|
||||
|
||||
{ I196F_OFF, 0x2030, "Int08", cmt10 },
|
||||
{ I196F_OFF, 0x2032, "Int09", cmt11 },
|
||||
{ I196F_OFF, 0x2034, "Int10", cmt12 },
|
||||
{ I196F_OFF, 0x2036, "Int11", cmt13 },
|
||||
{ I196F_OFF, 0x2038, "Int12", cmt14 },
|
||||
{ I196F_OFF, 0x203A, "Int13", cmt15 },
|
||||
{ I196F_OFF, 0x203C, "Int14", cmt16 },
|
||||
{ I196F_OFF, 0x203E, "Int15", "NMI" },
|
||||
|
||||
{ I196F_CMT, 0x2040, 0, "\nPTS vectors\n" },
|
||||
|
||||
{ I196F_OFF, 0x2040, "PTS_Int00", cmt01 },
|
||||
{ I196F_OFF, 0x2042, "PTS_Int01", cmt02 },
|
||||
{ I196F_OFF, 0x2044, "PTS_Int02", cmt03 },
|
||||
{ I196F_OFF, 0x2046, "PTS_Int03", cmt04 },
|
||||
{ I196F_OFF, 0x2048, "PTS_Int04", cmt05 },
|
||||
{ I196F_OFF, 0x204A, "PTS_Int05", cmt06 },
|
||||
{ I196F_OFF, 0x204C, "PTS_Int06", cmt07 },
|
||||
{ I196F_OFF, 0x204E, "PTS_Int07", cmt08 },
|
||||
{ I196F_OFF, 0x2050, "PTS_Int08", cmt10 },
|
||||
{ I196F_OFF, 0x2052, "PTS_Int09", cmt11 },
|
||||
{ I196F_OFF, 0x2054, "PTS_Int10", cmt12 },
|
||||
{ I196F_OFF, 0x2056, "PTS_Int11", cmt13 },
|
||||
{ I196F_OFF, 0x2058, "PTS_Int12", cmt14 },
|
||||
{ I196F_OFF, 0x205A, "PTS_Int13", cmt15 },
|
||||
{ I196F_OFF, 0x205C, "PTS_Int14", cmt16 },
|
||||
|
||||
{ I196F_CMT, 0x205E, 0, 0 },
|
||||
|
||||
{ I196F_BTS, 0x205E, 0, cmt09 },
|
||||
|
||||
// { I196F_CMT, 0x2080, 0, "\nProgram entry point\n" },
|
||||
|
||||
{ I196F_CMT, 0x2080, 0, 0 }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] = { "cs", "ds", "WSR", "WSR1" };
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static bool idaapi can_have_type(const op_t &x) // returns 1 - operand can have
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
case o_reg:
|
||||
case o_indirect:
|
||||
case o_indirect_inc:
|
||||
case o_bit:
|
||||
case o_mem:
|
||||
case o_near:
|
||||
return 0;
|
||||
// case o_phrase: can have type because of ASI or 0 struct offsets
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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 i196_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi i196_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
// if necessary, add to ida.cfg:
|
||||
// #ifdef __80196__
|
||||
// DUMMY_NAMES_TYPE = NM_SHORT
|
||||
// #endif
|
||||
|
||||
segment_t *sptr = get_first_seg();
|
||||
if ( sptr != NULL )
|
||||
set_segm_class(sptr, "CODE");
|
||||
|
||||
ea_t ea, ea1;
|
||||
|
||||
for ( int i = 0; i < qnumber(entries); i++ )
|
||||
{
|
||||
ea = to_ea(inf_get_baseaddr(), entries[i].off);
|
||||
|
||||
if ( is_mapped(ea) )
|
||||
{
|
||||
switch ( entries[i].type )
|
||||
{
|
||||
case I196F_BTS:
|
||||
if ( i < qnumber(entries)-1 )
|
||||
{
|
||||
create_byte(ea, entries[i+1].off-entries[i].off);
|
||||
set_cmt(ea, entries[i].cmt, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case I196F_CMT:
|
||||
if ( entries[i].cmt != NULL )
|
||||
add_extra_cmt(ea, true, "%s", entries[i].cmt);
|
||||
else
|
||||
add_extra_line(ea, true, "");
|
||||
break;
|
||||
|
||||
case I196F_OFF:
|
||||
create_word(ea, 2);
|
||||
op_plain_offset(ea, 0, to_ea(inf_get_baseaddr(), 0));
|
||||
|
||||
ea1 = to_ea(inf_get_baseaddr(), get_word(ea));
|
||||
auto_make_proc(ea1);
|
||||
// add a simple comment
|
||||
// after function is created, it will be converted
|
||||
// to function comment
|
||||
set_cmt(ea1, entries[i].cmt, 1);
|
||||
}
|
||||
|
||||
set_name(ea, entries[i].name, SN_NODUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
ea = to_ea(inf_get_baseaddr(), 0x2080);
|
||||
if ( is_mapped(ea) )
|
||||
{
|
||||
inf_set_start_ea(ea);
|
||||
inf_set_start_ip(0x2080);
|
||||
}
|
||||
|
||||
segment_t s;
|
||||
s.start_ea = to_ea(inf_get_baseaddr(), 0);
|
||||
s.end_ea = to_ea(inf_get_baseaddr(), 0x400);
|
||||
s.sel = inf_get_baseaddr();
|
||||
s.type = SEG_IMEM; // internal memory
|
||||
add_segm_ex(&s, "INTMEM", NULL, ADDSEG_OR_DIE);
|
||||
|
||||
const predefined_t *ptr;
|
||||
for ( ptr = iregs; ptr->name != NULL; ptr++ )
|
||||
{
|
||||
ea = to_ea(inf_get_baseaddr(), ptr->addr);
|
||||
ea_t oldea = get_name_ea(BADADDR, ptr->name);
|
||||
if ( oldea != ea )
|
||||
{
|
||||
if ( oldea != BADADDR )
|
||||
set_name(oldea, NULL);
|
||||
del_items(ea, DELIT_EXPAND);
|
||||
set_name(ea, ptr->name, SN_NODUMMY);
|
||||
}
|
||||
if ( ptr->cmt != NULL )
|
||||
set_cmt(ea, ptr->cmt, 1);
|
||||
}
|
||||
}
|
||||
// create_16bit_data(0x18, 2); // SP always word
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
// default DS is equal to Base Address
|
||||
{
|
||||
segment_t *sg = va_arg(va, segment_t *);
|
||||
sg->defsr[rVds-ph.reg_first_sreg] = inf_get_baseaddr();
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
// restore ptype
|
||||
extended = ph.get_proc_index();
|
||||
goto SETFLAG;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
extended = va_arg(va,int) != 0;
|
||||
SETFLAG:
|
||||
if ( !extended )
|
||||
ph.flag &= ~PR_SEGS;
|
||||
else
|
||||
ph.flag |= PR_SEGS;
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
i196_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
i196_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 *);
|
||||
i196_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
i196_segend(*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_can_have_type:
|
||||
{
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return can_have_type(*op) ? 1 : -1;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Could not find a standard assembler for this CPU :(
|
||||
static const asm_t unkasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0,
|
||||
0,
|
||||
"Abstract Assembler",
|
||||
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
|
||||
"dd", // 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
|
||||
"$",
|
||||
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
|
||||
"SIZE", // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &unkasm, NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#define FAMILY "Intel 196 series:"
|
||||
static const char *const shnames[] = { "80196", "80196NP", NULL };
|
||||
static const char *const lnames[] = { FAMILY"Intel 80196", "Intel 80196NP", NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcode[] = { 0xF0 }; // ret
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode), retcode },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_80196, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_USE32
|
||||
| PR_SEGS
|
||||
| PR_BINMEM
|
||||
| PR_RNAMESOK,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // short processor names (null term)
|
||||
lnames, // long processor names (null term)
|
||||
|
||||
asms, // array of enabled assemblers
|
||||
|
||||
notify, // Various messages:
|
||||
|
||||
RegNames, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs,WSR1,
|
||||
2, // size of a segment register
|
||||
rVcs,rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0, I196_last,
|
||||
Instructions, // instruc
|
||||
};
|
||||
2776
idasdk76/module/arc/ana.cpp
Normal file
2776
idasdk76/module/arc/ana.cpp
Normal file
File diff suppressed because it is too large
Load Diff
502
idasdk76/module/arc/arc.hpp
Normal file
502
idasdk76/module/arc/arc.hpp
Normal file
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 2012-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
* ARC (Argonaut RISC Core) processor module
|
||||
*
|
||||
* Based on code contributed by by Felix Domke <tmbinc@gmx.net>
|
||||
*/
|
||||
|
||||
#ifndef _ARC_HPP
|
||||
#define _ARC_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <typeinf.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
#define PROCMOD_NAME arc
|
||||
#define PROCMOD_NODE_NAME "$ arc"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// customization of the 'cmd' structure:
|
||||
|
||||
enum processor_subtype_t
|
||||
{
|
||||
prc_arc = 0, // ARCTangent-A4 (old 32-bit ISA)
|
||||
prc_arcompact = 1, // ARCtangent-A5 and later (32/16-bit mixed)
|
||||
prc_arcv2 = 2, // ARC EM (ARCompact successor)
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum RegNo
|
||||
{
|
||||
R0, R1, R2, R3, R4, R5, R6, R7,
|
||||
R8, R9, R10, R11, R12, R13, R14, R15,
|
||||
R16, R17, R18, R19, R20, R21, R22, R23,
|
||||
R24, R25, R26, R27, R28, R29, R30, R31,
|
||||
|
||||
R32, R33, R34, R35, R36, R37, R38, R39,
|
||||
R40, R41, R42, R43, R44, R45, R46, R47,
|
||||
R48, R49, R50, R51, R52, R53, R54, R55,
|
||||
R56, R57, R58, R59, R60, R61, R62, R63,
|
||||
|
||||
CF, ZF, NF, VF,
|
||||
|
||||
// registers used for indexed instructions
|
||||
// keep these consecutive
|
||||
NEXT_PC,
|
||||
LDI_BASE, JLI_BASE, EI_BASE,
|
||||
|
||||
GP_SEG, // virtual segment register for global pointer value
|
||||
|
||||
rVcs, rVds, // virtual registers for code and data segments
|
||||
|
||||
// aliases
|
||||
|
||||
GP = R26, // Global Pointer
|
||||
FP = R27, // Frame Pointer
|
||||
SP = R28, // Stack Pointer
|
||||
ILINK1 = R29, // Level 1 interrupt link register
|
||||
ILINK2 = R30, // Level 2 interrupt link register
|
||||
BLINK = R31, // Branch link register
|
||||
LP_COUNT = R60, // Loop count register
|
||||
PCL = R63, // 32-bit aligned PC value (ARCompact)
|
||||
|
||||
// optional extension
|
||||
MLO = R57, // Multiply low 32 bits, read only
|
||||
MMID = R58, // Multiply middle 32 bits, read only
|
||||
MHI = R59, // Multiply high 32 bits, read only
|
||||
};
|
||||
|
||||
#define SHIMM_F 61 // Short immediate data indicator setting flags
|
||||
#define LIMM 62 // Long immediate data indicator
|
||||
#define SHIMM 63 // Short immediate data indicator not setting flags (NB: not used in ARCompact)
|
||||
#define LIMM5 30 // 5-bit long immediate data indicator (used in ARCv2)
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const ioport_t *find_port(ea_t address);
|
||||
|
||||
#define PROC_MAXOP 4 // max number of operands
|
||||
CASSERT(PROC_MAXOP <= UA_MAXOP);
|
||||
|
||||
//---------------------------------
|
||||
|
||||
inline int getreg(const op_t &x)
|
||||
{
|
||||
return x.type == o_reg ? x.reg : -1;
|
||||
}
|
||||
|
||||
inline bool isreg(const op_t &x, int reg)
|
||||
{
|
||||
return getreg(x) == reg;
|
||||
}
|
||||
|
||||
inline bool issp(const op_t &x) { return isreg(x, SP); }
|
||||
|
||||
//---------------------------------
|
||||
// cmd.auxpref bits
|
||||
// instructions that use condition flags (Bcc, Jcc)
|
||||
#define aux_f 0x0100 // Flags set field (.f postfix)
|
||||
#define aux_nmask 0x0060 // Jump/Call nullify instruction mode
|
||||
#define aux_nd 0x00 // No Delayed instruction slot (only execute next instruction when not jumping)
|
||||
#define aux_d 0x20 // Delayed instruction slot (always execute next instruction)
|
||||
#define aux_jd 0x40 // Jump Delayed instruction slot (only execute next instruction when jumping)
|
||||
#define aux_cmask 0x001F // condition code mask
|
||||
// load/store instructions flags (Di.AA.ZZ.X)
|
||||
#define aux_di 0x0020 // direct to memory (cache bypass) (.di suffix)
|
||||
#define aux_amask 0x0018 // Address write-back
|
||||
#define aux_anone 0x00 // no writeback
|
||||
#define aux_a 0x08 // pre-increment (.a or .aw)
|
||||
#define aux_ab 0x10 // post-increment (.ab)
|
||||
#define aux_as 0x18 // scaled access (.as)
|
||||
#define aux_zmask 0x0006 // size mask
|
||||
#define aux_l 0x0 // long size (no suffix)
|
||||
#define aux_w 0x4 // word size (.w suffix)
|
||||
#define aux_b 0x2 // byte size (.b suffix)
|
||||
#define aux_x 0x0001 // Sign extend field (.x suffix)
|
||||
|
||||
#define aux_pcload 0x0200 // converted pc-relative to memory load (used when ARC_INLINECONST is set)
|
||||
#define aux_bhint 0x0400 // non-default static branch prediction hint (.t or .nt suffix)
|
||||
#define aux_s 0x0800 // 16-bit encoded instruction
|
||||
|
||||
// Operand types:
|
||||
#define o_reglist o_idpspec0 // register list for enter/leave
|
||||
|
||||
#define reglist specval // o_reglist: registers to save/restore
|
||||
#define REGLIST_REGS 0x0F // number of core registers to save/restore
|
||||
#define REGLISTR_MAX 0x0E // max number of core registers to save/restore
|
||||
#define REGLIST_FP 0x10 // save/restore stack frame
|
||||
#define REGLIST_BLINK 0x20 // save/restore blink register
|
||||
#define REGLIST_PCL 0x40 // jump to blink register after restore (leave only)
|
||||
|
||||
// o_phrase
|
||||
#define secreg specflag1 // o_phrase: the second register is here: [op.phrase, op.secreg]
|
||||
|
||||
// o_displ
|
||||
#define membase specflag1 // o_displ: if set, displacement is the base value: [op.addr, op.reg]
|
||||
// this is important for scaled loads, e.g. ld.as r1, [0x23445, r2]
|
||||
// o_reg
|
||||
#define regpair specflag1 // o_reg: if set, this operand is the second register of a register pair
|
||||
// the previous operand contains the other register of the pair
|
||||
// o_mem
|
||||
#define immdisp specval // o_mem: immediate displacement to immediate address.
|
||||
// addr contains the already displaced address.
|
||||
// addr - get_scale_factor(insn) * immdisp is the base address for immdisp
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Condition codes:
|
||||
enum cond_t
|
||||
{
|
||||
cAL=0, cRA=0, // Always 1 0x00
|
||||
cEQ=1, cZ=1, // Zero Z 0x01
|
||||
cNE=2, cNZ=2, // Non-Zero /Z 0x02
|
||||
cPL=3, cP=3, // Positive /N 0x03
|
||||
cMI=4, cN=4, // Negative N 0x04
|
||||
cCS=5, cC=5, cLO=5, // Carry set, lower than (unsigned) C 0x05
|
||||
cCC=6, cNC=6, cHS=6, // Carry clear, higher or same (unsigned) /C 0x06
|
||||
cVS=7, cV=7, // Over-flow set V 0x07
|
||||
cVC=8, cNV=8, // Over-flow clear /V 0x08
|
||||
cGT=9, // Greater than (signed) (N and V and /Z) or (/N and /V and /Z) 0x09
|
||||
cGE=0x0A, // Greater than or equal to (signed) (N and V) or (/N and /V) 0x0A
|
||||
cLT=0x0B, // Less than (signed) (N and /V) or (/N and V) 0x0B
|
||||
cLE=0x0C, // Less than or equal to (signed) Z or (N and /V) or (/N and V) 0x0C
|
||||
cHI=0x0D, // Higher than (unsigned) /C and /Z 0x0D
|
||||
cLS=0x0E, // Lower than or same (unsigned) C or Z 0x0E
|
||||
cPNZ=0x0F, // Positive non-zero /N and /Z 0x0F
|
||||
cLAST
|
||||
};
|
||||
inline uint8 get_cond(const insn_t &insn)
|
||||
{
|
||||
if ( insn.itype <= ARC_store_instructions )
|
||||
return cAL;
|
||||
return uint8(insn.auxpref & aux_cmask);
|
||||
}
|
||||
inline bool has_cond(const insn_t &insn)
|
||||
{
|
||||
if ( insn.itype <= ARC_store_instructions )
|
||||
return false;
|
||||
return (insn.auxpref & aux_cmask) != cAL;
|
||||
}
|
||||
inline cond_t get_core_cond(const insn_t &insn)
|
||||
{
|
||||
if ( insn.itype <= ARC_store_instructions )
|
||||
return cAL;
|
||||
uint8 cond = insn.auxpref & aux_cmask;
|
||||
if ( cond >= cLAST )
|
||||
return cLAST;
|
||||
return cond_t(cond);
|
||||
}
|
||||
inline bool has_core_cond(const insn_t &insn)
|
||||
{
|
||||
if ( insn.itype <= ARC_store_instructions )
|
||||
return false;
|
||||
uint8 cond = insn.auxpref & aux_cmask;
|
||||
return cond != cAL && cond < cLAST;
|
||||
}
|
||||
inline cond_t invert_cond(cond_t cond)
|
||||
{
|
||||
switch ( cond )
|
||||
{
|
||||
case cNE: return cEQ;
|
||||
case cEQ: return cNE;
|
||||
case cCC: return cCS;
|
||||
case cCS: return cCC;
|
||||
case cPL: return cMI;
|
||||
case cMI: return cPL;
|
||||
case cVC: return cVS;
|
||||
case cVS: return cVC;
|
||||
case cHI: return cLS;
|
||||
case cLS: return cHI;
|
||||
case cGE: return cLT;
|
||||
case cLT: return cGE;
|
||||
case cGT: return cLE;
|
||||
case cLE: return cGT;
|
||||
default: return cLAST;
|
||||
}
|
||||
}
|
||||
|
||||
// ARC ABI conventions from gdb/arc-tdep.h
|
||||
#define ARC_ABI_GLOBAL_POINTER 26
|
||||
#define ARC_ABI_FRAME_POINTER 27
|
||||
#define ARC_ABI_STACK_POINTER 28
|
||||
|
||||
#define ARC_ABI_FIRST_CALLEE_SAVED_REGISTER 13
|
||||
#define ARC_ABI_LAST_CALLEE_SAVED_REGISTER 26
|
||||
|
||||
#define ARC_ABI_FIRST_ARGUMENT_REGISTER 0
|
||||
#define ARC_ABI_LAST_ARGUMENT_REGISTER 7
|
||||
|
||||
#define ARC_ABI_RETURN_REGNUM 0
|
||||
#define ARC_ABI_RETURN_LOW_REGNUM 0
|
||||
#define ARC_ABI_RETURN_HIGH_REGNUM 1
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// does 'ins' have a delay slot? (next instruction is executed before branch/jump)
|
||||
inline bool has_dslot(const insn_t &ins)
|
||||
{
|
||||
// EXCEPTION: jl.jd <addr> uses delay slot to
|
||||
// hide the long immediate used for the address
|
||||
if ( ins.itype == ARC_jl
|
||||
&& (ins.auxpref & aux_nmask) == aux_jd
|
||||
&& ins.Op1.type == o_near )
|
||||
return false;
|
||||
return ins.itype > ARC_store_instructions && (ins.auxpref & aux_nmask) != 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Scale factor for indexed memory access
|
||||
inline int get_scale_factor(const insn_t &ins)
|
||||
{
|
||||
switch ( ins.itype )
|
||||
{
|
||||
case ARC_st:
|
||||
case ARC_ld:
|
||||
if ( (ins.auxpref & aux_amask) == aux_as )
|
||||
{
|
||||
if ( (ins.auxpref & aux_zmask) == aux_w )
|
||||
return 2;
|
||||
if ( (ins.auxpref & aux_zmask) == aux_l )
|
||||
return 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARC_bih:
|
||||
return 2;
|
||||
|
||||
case ARC_bi:
|
||||
case ARC_ldi:
|
||||
case ARC_jli:
|
||||
case ARC_ei:
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Should the register be hidden when used as base in o_displ/o_phrase?
|
||||
//
|
||||
// 0 output normally
|
||||
// 1 hide base reg
|
||||
// -1 hide base reg and output as immediate
|
||||
inline int is_hidden_base_reg(int reg)
|
||||
{
|
||||
if ( reg >= NEXT_PC && reg <= EI_BASE )
|
||||
{
|
||||
return reg == JLI_BASE || reg == EI_BASE ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// The sreg that contains the current value for the given register
|
||||
//
|
||||
// Returns -1 if there is no such sreg
|
||||
inline int get_base_sreg(int reg)
|
||||
{
|
||||
if ( reg == GP )
|
||||
return GP_SEG;
|
||||
else if ( reg >= LDI_BASE && reg <= GP_SEG )
|
||||
return reg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void idaapi arc_header(outctx_t &ctx);
|
||||
void idaapi arc_footer(outctx_t &ctx);
|
||||
|
||||
int idaapi is_sp_based(const insn_t &insn, const op_t & x);
|
||||
bool idaapi create_func_frame(func_t * pfn);
|
||||
int idaapi arc_get_frame_retsize(const func_t * pfn);
|
||||
bool is_arc_return_insn(const insn_t &insn);
|
||||
bool arc_is_switch(switch_info_t *si, const insn_t &insn);
|
||||
inline bool is_arc_simple_branch(uint16 itype)
|
||||
{
|
||||
return itype == ARC_bl
|
||||
|| itype == ARC_jl
|
||||
|| itype == ARC_b
|
||||
|| itype == ARC_j;
|
||||
}
|
||||
|
||||
int get_arc_fastcall_regs(const int **regs);
|
||||
bool calc_arc_arglocs(func_type_data_t *fti);
|
||||
bool calc_arc_varglocs(
|
||||
func_type_data_t *fti,
|
||||
regobjs_t *regargs,
|
||||
int nfixed);
|
||||
bool calc_arc_retloc(argloc_t *retloc, const tinfo_t &tif, cm_t cc);
|
||||
void use_arc_arg_types(
|
||||
ea_t ea,
|
||||
func_type_data_t *fti,
|
||||
funcargvec_t *rargs);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct arc_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct arc_t ±
|
||||
arc_iohandler_t(arc_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line) override;
|
||||
virtual void get_cfg_filename(char *buf, size_t bufsize) override;
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(pm_idb_listener_t, struct arc_t);
|
||||
|
||||
struct arc_t : public procmod_t
|
||||
{
|
||||
netnode helper; // altval(-1): idp flags
|
||||
#define CALLEE_TAG 'A' // altval(ea): callee address for indirect calls
|
||||
#define DXREF_TAG 'd' // altval(ea): resolved address for complex calculation (e.g. ADD R1, PC)
|
||||
#define DSLOT_TAG 's' // altval(ea): 1: delay slot of an unconditional jump/branch
|
||||
// 2: delay slot of a conditional jump/branch
|
||||
// 3: delay slot of a jl/bl
|
||||
inline void set_callee(ea_t ea, ea_t callee) { helper.easet(ea, callee, CALLEE_TAG); }
|
||||
inline ea_t get_callee(ea_t ea) { return helper.eaget(ea, CALLEE_TAG); }
|
||||
inline void del_callee(ea_t ea) { helper.eadel(ea, CALLEE_TAG); }
|
||||
|
||||
inline void set_dxref(ea_t ea, ea_t dxref) { helper.easet(ea, dxref, DXREF_TAG); }
|
||||
inline ea_t get_dxref(ea_t ea) { return helper.eaget(ea, DXREF_TAG); }
|
||||
inline void del_dxref(ea_t ea) { helper.eadel(ea, DXREF_TAG); }
|
||||
|
||||
instruc_t Instructions[ARC_last];
|
||||
|
||||
ioports_t auxregs;
|
||||
arc_iohandler_t ioh = arc_iohandler_t(*this, helper);
|
||||
pm_idb_listener_t idb_listener = pm_idb_listener_t(*this);
|
||||
|
||||
processor_subtype_t ptype = prc_arc;
|
||||
inline bool is_a4() { return ptype == prc_arc; }
|
||||
inline bool is_arcv2() { return ptype == prc_arcv2; }
|
||||
|
||||
int arc_respect_info = IORESP_ALL;
|
||||
|
||||
int ref_arcsoh_id = 0;
|
||||
int ref_arcsol_id = 0;
|
||||
|
||||
#define ARC_SIMPLIFY 0x01
|
||||
#define ARC_INLINECONST 0x02
|
||||
#define ARC_TRACKREGS 0x04
|
||||
ushort idpflags = ARC_SIMPLIFY | ARC_INLINECONST | ARC_TRACKREGS;
|
||||
|
||||
int g_limm = 0;
|
||||
bool got_limm = false;
|
||||
|
||||
std::set<ea_t> renamed;
|
||||
int islast = 0;
|
||||
|
||||
// is 'ea' in a delay slot of a branch/jump?
|
||||
inline bool is_dslot(ea_t ea, bool including_calls = true)
|
||||
{
|
||||
nodeidx_t v = helper.altval_ea(ea, DSLOT_TAG);
|
||||
if ( including_calls )
|
||||
return v != 0;
|
||||
else
|
||||
return v == 1 || v == 2;
|
||||
}
|
||||
|
||||
inline bool is_imm(int regno)
|
||||
{
|
||||
if ( regno == LIMM )
|
||||
return true;
|
||||
if ( regno == SHIMM_F || regno == SHIMM )
|
||||
return is_a4();
|
||||
return false;
|
||||
}
|
||||
|
||||
arc_t();
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void save_idpflags() { helper.altset(-1, idpflags); }
|
||||
void load_from_idb();
|
||||
|
||||
bool select_device(int resp_info);
|
||||
inline void add_dxref(const insn_t &insn, ea_t target);
|
||||
int emu(const insn_t &insn);
|
||||
bool is_arc_basic_block_end(
|
||||
const insn_t &insn,
|
||||
bool call_insn_stops_block);
|
||||
void del_insn_info(ea_t ea);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void *value,
|
||||
bool idb_loaded);
|
||||
void set_codeseqs() const;
|
||||
void set_instruc_names();
|
||||
void ptype_changed();
|
||||
void doIndirectOperand(const insn_t &insn, int b, int c, op_t &op, int d, int li, bool special);
|
||||
void doRegisterInstruction(insn_t &insn, uint32 code);
|
||||
int ana_old(insn_t &insn);
|
||||
void decode_operand(
|
||||
insn_t &insn,
|
||||
uint32 code,
|
||||
int &op_pos,
|
||||
uint32 opkind);
|
||||
int analyze_compact(insn_t &insn, uint32 code, int idx, const struct arcompact_opcode_t *table);
|
||||
int ana_compact(insn_t &insn);
|
||||
int ana(insn_t *_insn);
|
||||
int is_align_insn(ea_t ea) const;
|
||||
bool good_target(const insn_t &insn, ea_t target) const;
|
||||
bool copy_insn_optype(const insn_t &insn, const op_t &x, ea_t ea, void *value = NULL, bool force = false) const;
|
||||
void handle_operand(const insn_t &insn, const op_t & x, bool loading);
|
||||
int get_limm(insn_t &insn);
|
||||
inline void opreg(insn_t &insn, op_t &x, int rgnum, int limm=LIMM);
|
||||
inline void opdisp(insn_t &insn, op_t &x, int rgnum, ea_t disp);
|
||||
void rename_if_not_set(ea_t ea, const char *name);
|
||||
bool check_ac_pop_chain(int *regno, ea_t ea);
|
||||
bool detect_millicode(qstring *mname, ea_t ea);
|
||||
bool is_millicode(ea_t ea, sval_t *spdelta=nullptr);
|
||||
sval_t calc_sp_delta(const insn_t &insn);
|
||||
void trace_sp(const insn_t &insn);
|
||||
bool arc_calc_spdelta(sval_t *spdelta, const insn_t &insn);
|
||||
int arc_may_be_func(const insn_t &insn, int state);
|
||||
void force_offset(
|
||||
ea_t ea,
|
||||
int n,
|
||||
ea_t base,
|
||||
bool issub = false,
|
||||
int scale = 1);
|
||||
bool spoils(const insn_t &insn, int reg) const;
|
||||
int spoils(const insn_t &insn, const uint32 *regs, int n) const;
|
||||
bool is_arc_call_insn(const insn_t &insn);
|
||||
bool find_op_value_ex(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
struct ldr_value_info_t *lvi,
|
||||
bool /*check_fbase_reg*/);
|
||||
bool find_ldr_value_ex(
|
||||
const insn_t &insn,
|
||||
ea_t ea,
|
||||
int reg,
|
||||
struct ldr_value_info_t *lvi,
|
||||
bool /*check_fbase_reg*/);
|
||||
bool find_op_value(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
uval_t *p_val,
|
||||
ea_t *p_val_ea=NULL,
|
||||
bool check_fbase_reg=true,
|
||||
bool *was_const_load=NULL);
|
||||
bool find_ldr_value(
|
||||
const insn_t &insn,
|
||||
ea_t ea,
|
||||
int reg,
|
||||
uval_t *p_val,
|
||||
ea_t *p_val_ea=NULL,
|
||||
bool check_fbase_reg=true,
|
||||
bool *was_const_load=NULL);
|
||||
int use_arc_regarg_type(ea_t ea, const funcargvec_t &rargs);
|
||||
bool arc_set_op_type(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
const tinfo_t &tif,
|
||||
const char *name,
|
||||
eavec_t *visited);
|
||||
void use_arc_arg_types(ea_t ea, func_type_data_t *fti, funcargvec_t *rargs);
|
||||
|
||||
void arc_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
#endif
|
||||
2887
idasdk76/module/arc/emu.cpp
Normal file
2887
idasdk76/module/arc/emu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
361
idasdk76/module/arc/ins.cpp
Normal file
361
idasdk76/module/arc/ins.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* 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 "arc.hpp"
|
||||
|
||||
instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
{ "ld", CF_CHG1|CF_USE2 }, // Load
|
||||
{ "lr", CF_CHG1|CF_USE2 }, // Load from auxiliary register
|
||||
{ "st", CF_USE1|CF_CHG2 }, // Store
|
||||
{ "sr", CF_USE1|CF_USE2|CF_CHG2 }, // Store to auxiliary register
|
||||
{ "flag", CF_USE1 }, // Set flags
|
||||
{ "asr", CF_CHG1|CF_USE2|CF_USE3 }, // Arithmetic shift right
|
||||
{ "lsr", CF_CHG1|CF_USE2|CF_USE3 }, // Logical shift right
|
||||
{ "sexb", CF_CHG1|CF_USE2 }, // Sign extend byte
|
||||
{ "sexw", CF_CHG1|CF_USE2 }, // Sign extend word
|
||||
{ "extb", CF_CHG1|CF_USE2 }, // Zero extend byte
|
||||
{ "extw", CF_CHG1|CF_USE2 }, // Zero extend word
|
||||
{ "ror", CF_CHG1|CF_USE2|CF_USE3 }, // Rotate right
|
||||
{ "rrc", CF_CHG1|CF_USE2 }, // Rotate right through carry
|
||||
{ "b", CF_USE1|CF_JUMP }, // Branch
|
||||
{ "bl", CF_USE1|CF_CALL }, // Branch and link
|
||||
{ "lp", CF_USE1 }, // Zero-overhead loop setup
|
||||
{ "j", CF_USE1|CF_JUMP }, // Jump
|
||||
{ "jl", CF_USE1|CF_CALL }, // Jump and link
|
||||
{ "add", CF_CHG1|CF_USE2|CF_USE3 }, // Add
|
||||
{ "adc", CF_CHG1|CF_USE2|CF_USE3 }, // Add with carry
|
||||
{ "sub", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract
|
||||
{ "sbc", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract with carry
|
||||
{ "and", CF_CHG1|CF_USE2|CF_USE3 }, // Logical bitwise AND
|
||||
{ "or", CF_CHG1|CF_USE2|CF_USE3 }, // Logical bitwise OR
|
||||
{ "bic", CF_CHG1|CF_USE2|CF_USE3 }, // Logical bitwise AND with invert
|
||||
{ "xor", CF_CHG1|CF_USE2|CF_USE3 }, // Logical bitwise exclusive-OR
|
||||
{ "mov", CF_CHG1|CF_USE2 }, // Move
|
||||
{ "nop", 0 }, // No operation
|
||||
{ "lsl", CF_CHG1|CF_USE2|CF_USE3 }, // Logical shift left
|
||||
{ "rlc", CF_CHG1|CF_USE2 }, // Rotate left through carry
|
||||
{ "brk", 0 }, // Breakpoint
|
||||
{ "sleep", 0 }, // Sleep until interrupt or restart
|
||||
{ "swi", 0 }, // Software interrupt
|
||||
{ "asl", CF_CHG1|CF_USE2|CF_USE3 }, // Arithmetic shift left
|
||||
{ "mul64", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32x32 multiply
|
||||
{ "mulu64", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32x32 multiply
|
||||
{ "max", CF_CHG1|CF_USE2|CF_USE3 }, // Maximum of two signed integers
|
||||
{ "min", CF_CHG1|CF_USE2|CF_USE3 }, // Minimum of two signed integers
|
||||
{ "swap", CF_CHG1|CF_USE2 }, // Exchange upper and lower 16 bits
|
||||
{ "norm", CF_CHG1|CF_USE2 }, // Normalize (find-first-bit)
|
||||
|
||||
// ARCompact instructions
|
||||
{ "bbit0", CF_USE1|CF_USE2|CF_USE3 }, // Branch if bit cleared to 0
|
||||
{ "bbit1", CF_USE1|CF_USE2|CF_USE3 }, // Branch if bit set to 1
|
||||
{ "br", CF_USE1|CF_USE2|CF_USE3 }, // Branch on compare
|
||||
{ "pop", CF_CHG1 }, // Restore register value from stack
|
||||
{ "push", CF_USE1 }, // Store register value on stack
|
||||
|
||||
{ "abs", CF_CHG1|CF_USE2 }, // Absolute value
|
||||
{ "add1", CF_CHG1|CF_USE2|CF_USE3 }, // Add with left shift by 1 bit
|
||||
{ "add2", CF_CHG1|CF_USE2|CF_USE3 }, // Add with left shift by 2 bits
|
||||
{ "add3", CF_CHG1|CF_USE2|CF_USE3 }, // Add with left shift by 3 bits
|
||||
{ "bclr", CF_CHG1|CF_USE2|CF_USE3 }, // Clear specified bit (to 0)
|
||||
{ "bmsk", CF_CHG1|CF_USE2|CF_USE3 }, // Bit Mask
|
||||
{ "bset", CF_CHG1|CF_USE2|CF_USE3 }, // Set specified bit (to 1)
|
||||
{ "btst", CF_USE1|CF_USE2 }, // Test value of specified bit
|
||||
{ "bxor", CF_CHG1|CF_USE2|CF_USE3 }, // Bit XOR
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // Compare
|
||||
{ "ex", CF_CHG1|CF_USE2 }, // Atomic Exchange
|
||||
{ "mpy", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32x32 multiply (low)
|
||||
{ "mpyh", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32x32 multiply (high)
|
||||
{ "mpyhu", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32x32 multiply (high)
|
||||
{ "mpyu", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32x32 multiply (low)
|
||||
{ "neg", CF_CHG1|CF_USE2 }, // Negate
|
||||
{ "not", CF_CHG1|CF_USE2 }, // Logical bit inversion
|
||||
{ "rcmp", CF_USE1|CF_USE2 }, // Reverse Compare
|
||||
{ "rsub", CF_CHG1|CF_USE2|CF_USE3 }, // Reverse Subtraction
|
||||
{ "rtie", 0 }, // Return from Interrupt/Exception
|
||||
{ "sub1", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract with left shift by 1 bit
|
||||
{ "sub2", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract with left shift by 2 bits
|
||||
{ "sub3", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract with left shift by 3 bits
|
||||
{ "sync", 0 }, // Synchronize
|
||||
{ "trap", CF_USE1 }, // Raise an exception
|
||||
{ "tst", CF_USE1|CF_USE2 }, // Test
|
||||
{ "unimp", 0 }, // Unimplemented instruction
|
||||
|
||||
{ "abss", CF_CHG1|CF_USE2 }, // Absolute and saturate
|
||||
{ "abssw", CF_CHG1|CF_USE2 }, // Absolute and saturate of word
|
||||
{ "adds", CF_CHG1|CF_USE2|CF_USE3 }, // Add and saturate
|
||||
{ "addsdw", CF_CHG1|CF_USE2|CF_USE3 }, // Add and saturate dual word
|
||||
{ "asls", CF_CHG1|CF_USE2|CF_USE3 }, // Arithmetic shift left and saturate
|
||||
{ "asrs", CF_CHG1|CF_USE2|CF_USE3 }, // Arithmetic shift right and saturate
|
||||
{ "divaw", CF_CHG1|CF_USE2|CF_USE3 }, // Division assist
|
||||
{ "negs", CF_CHG1|CF_USE2 }, // Negate and saturate
|
||||
{ "negsw", CF_CHG1|CF_USE2 }, // Negate and saturate of word
|
||||
{ "normw", CF_CHG1|CF_USE2 }, // Normalize to 16 bits
|
||||
{ "rnd16", CF_CHG1|CF_USE2 }, // Round to word
|
||||
{ "sat16", CF_CHG1|CF_USE2 }, // Saturate to word
|
||||
{ "subs", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract and saturate
|
||||
{ "subsdw", CF_CHG1|CF_USE2|CF_USE3 }, // Subtract and saturate dual word
|
||||
|
||||
{ "muldw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "muludw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "mulrdw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "macdw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "macudw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "macrdw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "msubdw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
|
||||
{ "mululw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "mullw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "mulflw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "maclw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "macflw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "machulw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "machlw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "machflw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "mulhlw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
{ "mulhflw", CF_CHG1|CF_USE2|CF_USE3 }, //
|
||||
|
||||
// Major 6 compact insns
|
||||
{ "acm", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "addqbs", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "avgqb", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "clamp", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "daddh11", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "daddh12", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "daddh21", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "daddh22", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dexcl1", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dexcl2", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dmulh11", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dmulh12", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dmulh21", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dmulh22", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dsubh11", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dsubh12", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dsubh21", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "dsubh22", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "drsubh11", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "drsubh12", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "drsubh21", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "drsubh22", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "fadd", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "fmul", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "fsub", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "fxtr", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "iaddr", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "mpyqb", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "sfxtr", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "pkqb", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "upkqb", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
{ "xpkqb", CF_CHG1|CF_USE2|CF_USE3 },
|
||||
|
||||
|
||||
// ARCv2 only major 4 instructions
|
||||
{ "mpyw", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 16x16 multiply
|
||||
{ "mpyuw", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 16x16 multiply
|
||||
{ "bi", CF_USE1|CF_JUMP }, // Branch indexed
|
||||
{ "bih", CF_USE1|CF_JUMP }, // Branch indexed half-word
|
||||
{ "ldi", CF_CHG1|CF_USE2 }, // Load indexed
|
||||
{ "aex", CF_USE1|CF_CHG1|CF_USE2|CF_CHG2 }, // Exchange with auxiliary register
|
||||
{ "bmskn", CF_CHG1|CF_USE2|CF_USE3 }, // Bit mask negated
|
||||
{ "seteq", CF_CHG1|CF_USE2|CF_USE3 }, // Set if equal
|
||||
{ "setne", CF_CHG1|CF_USE2|CF_USE3 }, // Set if not equal
|
||||
{ "setlt", CF_CHG1|CF_USE2|CF_USE3 }, // Set if less than
|
||||
{ "setge", CF_CHG1|CF_USE2|CF_USE3 }, // Set if greater or equal
|
||||
{ "setlo", CF_CHG1|CF_USE2|CF_USE3 }, // Set if lower than
|
||||
{ "seths", CF_CHG1|CF_USE2|CF_USE3 }, // Set if higher or same
|
||||
{ "setle", CF_CHG1|CF_USE2|CF_USE3 }, // Set if less than or equal
|
||||
{ "setgt", CF_CHG1|CF_USE2|CF_USE3 }, // Set if greater than
|
||||
|
||||
{ "rol", CF_CHG1|CF_USE2 }, // Rotate left
|
||||
{ "llock", CF_CHG1|CF_USE2 }, // Load locked
|
||||
{ "scond", CF_USE1|CF_CHG2 }, // Store conditional
|
||||
|
||||
{ "seti", CF_USE1 }, // Set interrupt enable and priority level
|
||||
{ "clri", CF_CHG1 }, // Clear and get interrupt enable and priority level
|
||||
|
||||
// ARCv2 compact prolog / epilog instructions
|
||||
{ "enter", CF_USE1|CF_JUMP }, // Function prologue sequence
|
||||
{ "leave", CF_USE1|CF_JUMP }, // Function epilogue sequence
|
||||
|
||||
// ARCv2 32-bit extension major 5 DOP instructions
|
||||
{ "div", CF_CHG1|CF_USE2|CF_USE3 }, // Signed integer divsion
|
||||
{ "divu", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned integer divsion
|
||||
{ "rem", CF_CHG1|CF_USE2|CF_USE3 }, // Signed integer remainder
|
||||
{ "remu", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned integer remainder
|
||||
{ "asrsr", CF_CHG1|CF_USE2|CF_USE3 }, // Shift right rounding and saturating
|
||||
{ "valgn2h", CF_CHG1|CF_USE2|CF_USE3 }, // Two-way 16-bit vector align
|
||||
{ "setacc", CF_USE2|CF_USE3 }, // Set the accumulator
|
||||
{ "mac", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32x32 multiply accumulate
|
||||
{ "macu", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32x32 multiply accumulate
|
||||
{ "dmpyh", CF_CHG1|CF_USE2|CF_USE3 }, // Sum of dual signed 16x16 multiplication
|
||||
{ "dmpyhu", CF_CHG1|CF_USE2|CF_USE3 }, // Sum of dual unsigned 16x16 multiplication
|
||||
{ "dmach", CF_CHG1|CF_USE2|CF_USE3 }, // Dual signed 16x16 multiply accumulate
|
||||
{ "dmachu", CF_CHG1|CF_USE2|CF_USE3 }, // Dual unsigned 16x16 multiply accumulate
|
||||
{ "vadd2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit addition
|
||||
{ "vadds2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating addition
|
||||
{ "vsub2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit subtraction
|
||||
{ "vsubs2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating subtraction
|
||||
{ "vaddsub2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit addition/subtraction
|
||||
{ "vaddsubs2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating addition/subtraction
|
||||
{ "vsubadd2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit subtraction/addition
|
||||
{ "vsubadds2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating subtraction/addition
|
||||
{ "mpyd", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Signed 32x32 multiply (wide)
|
||||
{ "mpydu", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Unsigned 32x32 multiply (wide)
|
||||
{ "macd", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Signed 32x32 multiply accumulate (wide)
|
||||
{ "macdu", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Unsigned 32x32 multiply accumulate (wide)
|
||||
{ "vmpy2h", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Dual signed 16x16 multiply (wide)
|
||||
{ "vmpy2hf", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x16 saturating fractional multiply
|
||||
{ "vmpy2hu", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Dual unsigned 16x16 multiply (wide)
|
||||
{ "vmpy2hfr", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x16 saturating rounded fractional multiply
|
||||
{ "vmac2h", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Dual signed 16x16 multiply (wide)
|
||||
{ "vmac2hf", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x16 saturating fractional multiply
|
||||
{ "vmac2hu", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Dual unsigned 16x16 multiply (wide)
|
||||
{ "vmac2hfr", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x16 saturating rounded fractional multiply
|
||||
{ "vmpy2hwf", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Dual 16x16 saturating fractional multiply (wide)
|
||||
{ "vasl2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit arithmetic shift left
|
||||
{ "vasls2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating arithmetic shift left
|
||||
{ "vasr2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit arithmetic shift right
|
||||
{ "vasrs2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating arithmetic shift right
|
||||
{ "vlsr2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit logical shift right
|
||||
{ "vasrsr2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit saturating rounded arithmetic shift right
|
||||
{ "vadd4b", CF_CHG1|CF_USE2|CF_USE3 }, // Quad 8-bit addition
|
||||
{ "vmax2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit maximum
|
||||
{ "vsub4b", CF_CHG1|CF_USE2|CF_USE3 }, // Quad 8-bit subtraction
|
||||
{ "vmin2h", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16-bit minimum
|
||||
{ "adcs", CF_CHG1|CF_USE2|CF_USE3 }, // Signed saturating addition with carry in
|
||||
{ "sbcs", CF_CHG1|CF_USE2|CF_USE3 }, // Signed saturating subtraction with carry in
|
||||
{ "dmpyhwf", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional saturating sum of dual 16x16 signed fractional multiply
|
||||
{ "vpack2hl", CF_CHG1|CF_USE2|CF_USE3 }, // Compose lower 16-bits
|
||||
{ "vpack2hm", CF_CHG1|CF_USE2|CF_USE3 }, // Compose upper 16-bits
|
||||
{ "dmpyhf", CF_CHG1|CF_USE2|CF_USE3 }, // Saturating sum of dual 16x16 signed fractional multiply
|
||||
{ "dmpyhfr", CF_CHG1|CF_USE2|CF_USE3 }, // Saturating rounded sum of dual 16x16 signed fractional multiply
|
||||
{ "dmachf", CF_CHG1|CF_USE2|CF_USE3 }, // Saturating sum of dual 16x16 signed fractional multiply accumulate
|
||||
{ "dmachfr", CF_CHG1|CF_USE2|CF_USE3 }, // Saturating rounded sum of dual 16x16 signed fractional multiply accumulate
|
||||
{ "vperm", CF_CHG1|CF_USE2|CF_USE3 }, // Byte permutation with zero or sign extension
|
||||
{ "bspush", CF_CHG1|CF_USE2|CF_USE3 }, // Bitstream push
|
||||
|
||||
// ARCv2 32-bit extension major 5 SOP instructions
|
||||
{ "swape", CF_CHG1|CF_USE2 }, // Swap byte ordering
|
||||
{ "lsl16", CF_CHG1|CF_USE2 }, // Logical shift left by 16 bits
|
||||
{ "lsr16", CF_CHG1|CF_USE2 }, // Logical shift right by 16 bits
|
||||
{ "asr16", CF_CHG1|CF_USE2 }, // Arithmetic shift right by 16 bits
|
||||
{ "asr8", CF_CHG1|CF_USE2 }, // Arithmetic shift right by 8 bits
|
||||
{ "lsr8", CF_CHG1|CF_USE2 }, // Logical shift right by 8 bits
|
||||
{ "lsl8", CF_CHG1|CF_USE2 }, // Logical shift left by 8 bits
|
||||
{ "rol8", CF_CHG1|CF_USE2 }, // Rotate left by 8 bits
|
||||
{ "ror8", CF_CHG1|CF_USE2 }, // Rotate right by 8 bits
|
||||
{ "ffs", CF_CHG1|CF_USE2 }, // Find first set bit
|
||||
{ "fls", CF_CHG1|CF_USE2 }, // Find last set bit
|
||||
|
||||
|
||||
{ "getacc", CF_CHG1|CF_USE2 }, // Get accumulator
|
||||
{ "normacc", CF_CHG1|CF_USE2 }, // Normalize accumulator
|
||||
{ "satf", CF_CHG1|CF_USE2 }, // Saturate according to flags
|
||||
{ "vpack2hbl", CF_CHG1|CF_USE2 }, // Pack lower bytes into lower 16 bits
|
||||
{ "vpack2hbm", CF_CHG1|CF_USE2 }, // Pack upper bytes into upper 16 bits
|
||||
{ "vpack2hblf", CF_CHG1|CF_USE2 }, // Pack upper bytes into lower 16 bits
|
||||
{ "vpack2hbmf", CF_CHG1|CF_USE2 }, // Pack lower bytes into upper 16 bits
|
||||
{ "vext2bhlf", CF_CHG1|CF_USE2 }, // Pack lower 2 bytes into upper byte of 16 bits each
|
||||
{ "vext2bhmf", CF_CHG1|CF_USE2 }, // Pack upper 2 bytes into upper byte of 16 bits each
|
||||
{ "vrep2hl", CF_CHG1|CF_USE2 }, // Repeat lower 16 bits
|
||||
{ "vrep2hm", CF_CHG1|CF_USE2 }, // Repeat upper 16 bits
|
||||
{ "vext2bhl", CF_CHG1|CF_USE2 }, // Pack lower 2 bytes into zero extended 16 bits
|
||||
{ "vext2bhm", CF_CHG1|CF_USE2 }, // Pack upper 2 bytes into zero extended 16 bits
|
||||
{ "vsext2bhl", CF_CHG1|CF_USE2 }, // Pack lower 2 bytes into sign extended 16 bits
|
||||
{ "vsext2bhm", CF_CHG1|CF_USE2 }, // Pack upper 2 bytes into sign extended 16 bits
|
||||
{ "vabs2h", CF_CHG1|CF_USE2 }, // Dual 16-bit absolute value
|
||||
{ "vabss2h", CF_CHG1|CF_USE2 }, // Dual saturating 16-bit absolute value
|
||||
{ "vneg2h", CF_CHG1|CF_USE2 }, // Dual 16-bit negation
|
||||
{ "vnegs2h", CF_CHG1|CF_USE2 }, // Dual saturating 16-bit negation
|
||||
{ "vnorm2h", CF_CHG1|CF_USE2 }, // Dual 16-bit normalization
|
||||
{ "bspeek", CF_CHG1|CF_USE2 }, // Bitstream peek
|
||||
{ "bspop", CF_CHG1|CF_USE2 }, // Bitstream pop
|
||||
{ "sqrt", CF_CHG1|CF_USE2 }, // Integer square root
|
||||
{ "sqrtf", CF_CHG1|CF_USE2 }, // Fractional square root
|
||||
|
||||
// ARCv2 32-bit extension major 5 ZOP instructions
|
||||
{ "aslacc", CF_USE1 }, // Arithmetic shift of accumulator
|
||||
{ "aslsacc", CF_USE1 }, // Saturating arithmetic shift of accumulator
|
||||
{ "flagacc", CF_USE1 }, // Copy accumulator flags to status32 register
|
||||
{ "modif", CF_USE1 }, // Update address pointer
|
||||
|
||||
// ARCv2 32-bit extension major 6 DOP instructions
|
||||
{ "cmpyhnfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded unshifted multiply
|
||||
{ "cmpyhfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded multiply
|
||||
{ "cmpychfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded conjugated multiply
|
||||
{ "vmsub2hf", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x16 saturating fractional multiply subtract
|
||||
{ "vmsub2hfr", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x16 saturating rounded fractional multiply subtract
|
||||
{ "cmpychnfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded unshifted conjugated multiply
|
||||
{ "cmachnfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded unshifted multiply accumulate
|
||||
{ "cmachfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded unshifted accumulate
|
||||
{ "cmacchnfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded conjugated multiply accumulate
|
||||
{ "cmacchfr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex saturating rounded unshifted conjugated multiply accumulate
|
||||
{ "mpyf", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional saturating multiply
|
||||
{ "mpyfr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional saturating rounded multiply
|
||||
{ "macf", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional saturating multiply accumulate
|
||||
{ "macfr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional saturating rounded multiply accumulate
|
||||
{ "msubf", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional saturating multiply subtract
|
||||
{ "msubfr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional saturating rounded multiply subtract
|
||||
{ "divf", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32-bit fractional division
|
||||
{ "vmac2hnfr", CF_CHG1|CF_USE2|CF_USE3 }, // Dual signed 16-bit fractional saturating rounded multiply accumulate
|
||||
{ "vmsub2hnfr", CF_CHG1|CF_USE2|CF_USE3 }, // Dual signed 16-bit fractional saturating rounded multiply subtract
|
||||
{ "mpydf", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Signed 32-bit fractional multiply (wide)
|
||||
{ "macdf", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Signed 32-bit fractional multiply accumulate (wide)
|
||||
{ "msubwhfl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) fractional saturating multiply subtract
|
||||
{ "msubdf", CF_CHG1|CF_CHG2|CF_USE3|CF_USE4 }, // Signed 32-bit fractional multiply subtract (wide)
|
||||
{ "dmpyhbl", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x8 signed multiply with lower two bytes
|
||||
{ "dmpyhbm", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x8 signed multiply with upper two bytes
|
||||
{ "dmachbl", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x8 signed multiply accumulate with lower two bytes
|
||||
{ "dmachbm", CF_CHG1|CF_USE2|CF_USE3 }, // Dual 16x8 signed multiply accumulate with upper two bytes
|
||||
{ "msubwhflr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) fractional saturating rounded multiply subtract
|
||||
{ "cmpyhfmr", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex x 16bit real (upper) saturating rounded multiply
|
||||
{ "cbflyhf0r", CF_CHG1|CF_USE2|CF_USE3 }, // Fractional 16+16 bit complex FFT butterfly, first half
|
||||
{ "mpywhl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) multiply
|
||||
{ "macwhl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) multiply accumulate
|
||||
{ "mpywhul", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32 x 16 (lower) multiply
|
||||
{ "macwhul", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32 x 16 (lower) multiply accumulate
|
||||
{ "mpywhfm", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (upper) fractional saturating multiply
|
||||
{ "mpywhfmr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (upper) fractional saturating rounded multiply
|
||||
{ "macwhfm", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (upper) fractional saturating multiply accumulate
|
||||
{ "macwhfmr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (upper) fractional saturating rounded multiply accumulate
|
||||
{ "mpywhfl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) fractional saturating multiply
|
||||
{ "mpywhflr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) fractional saturating rounded multiply
|
||||
{ "macwhfl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) fractional saturating multiply accumulate
|
||||
{ "macwhflr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) fractional saturating rounded multiply accumulate
|
||||
{ "macwhkl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) 16-bit shifted multiply accumulate
|
||||
{ "macwhkul", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32 x 16 (lower) 16-bit shifted multiply accumulate
|
||||
{ "mpywhkl", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (lower) 16-bit shifted multiply
|
||||
{ "mpywhkul", CF_CHG1|CF_USE2|CF_USE3 }, // Unsigned 32 x 16 (lower) 16-bit shifted multiply
|
||||
{ "msubwhfm", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (upper) fractional saturating multiply subtract
|
||||
{ "msubwhfmr", CF_CHG1|CF_USE2|CF_USE3 }, // Signed 32 x 16 (upper) fractional saturating rounded multiply subtract
|
||||
|
||||
// ARCv2 32-bit extension major 6 SOP instructions
|
||||
{ "cbflyhf1r", CF_CHG1|CF_USE2 }, // Fractional 16+16 bit complex FFT butterfly, second half
|
||||
|
||||
{ "fscmp", CF_USE1|CF_USE2 }, // Single precision floating point compare
|
||||
{ "fscmpf", CF_USE1|CF_USE2 }, // Single precision floating point compare (IEEE 754 flag generation)
|
||||
{ "fsmadd", CF_CHG1|CF_USE2|CF_USE3 }, // Single precision floating point fused multiply add
|
||||
{ "fsmsub", CF_CHG1|CF_USE2|CF_USE3 }, // Single precision floating point fused multiply subtract
|
||||
{ "fsdiv", CF_CHG1|CF_USE2|CF_USE3 }, // Single precision floating point division
|
||||
{ "fcvt32", CF_CHG1|CF_USE2 }, // Single precision floating point / integer conversion
|
||||
{ "fssqrt", CF_CHG1|CF_USE2|CF_USE3 }, // Single precision floating point square root
|
||||
|
||||
// ARCv2 jump / execute indexed instructions
|
||||
{ "jli", CF_USE1|CF_CALL }, // Jump and link
|
||||
{ "ei", CF_USE1|CF_CALL }, // Execute indexed
|
||||
|
||||
{ "kflag", CF_USE1 }, // Set kernel flags
|
||||
{ "wevt", CF_USE1 }, // Enter sleep state
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == ARC_last);
|
||||
|
||||
387
idasdk76/module/arc/ins.hpp
Normal file
387
idasdk76/module/arc/ins.hpp
Normal file
@@ -0,0 +1,387 @@
|
||||
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INS_HPP
|
||||
#define __INS_HPP
|
||||
|
||||
extern instruc_t Instructions[];
|
||||
|
||||
enum nameNum
|
||||
{
|
||||
|
||||
ARC_null = 0, // Unknown Operation
|
||||
|
||||
ARC_ld, // Load
|
||||
ARC_lr, // Load from auxiliary register
|
||||
ARC_st, // Store
|
||||
ARC_sr, // Store to auxiliary register
|
||||
ARC_store_instructions = ARC_sr,
|
||||
ARC_flag, // Set flags
|
||||
ARC_asr, // Arithmetic shift right
|
||||
ARC_lsr, // Logical shift right
|
||||
ARC_sexb, // Sign extend byte
|
||||
ARC_sexw, // Sign extend word
|
||||
ARC_sexh = ARC_sexw,
|
||||
ARC_extb, // Zero extend byte
|
||||
ARC_extw, // Zero extend word
|
||||
ARC_exth = ARC_extw,
|
||||
ARC_ror, // Rotate right
|
||||
ARC_rrc, // Rotate right through carry
|
||||
ARC_b, // Branch
|
||||
ARC_bl, // Branch and link
|
||||
ARC_lp, // Zero-overhead loop setup
|
||||
ARC_j, // Jump
|
||||
ARC_jl, // Jump and link
|
||||
ARC_add, // Add
|
||||
ARC_adc, // Add with carry
|
||||
ARC_sub, // Subtract
|
||||
ARC_sbc, // Subtract with carry
|
||||
ARC_and, // Logical bitwise AND
|
||||
ARC_or, // Logical bitwise OR
|
||||
ARC_bic, // Logical bitwise AND with invert
|
||||
ARC_xor, // Logical bitwise exclusive-OR
|
||||
|
||||
// pseudo instructions
|
||||
ARC_mov, // Move
|
||||
ARC_nop, // No operation
|
||||
ARC_lsl, // Logical shift left
|
||||
ARC_rlc, // Rotate left through carry
|
||||
|
||||
// arc7
|
||||
ARC_brk, // Breakpoint
|
||||
ARC_sleep, // Sleep until interrupt or restart
|
||||
|
||||
// arc8
|
||||
ARC_swi, // Software interrupt
|
||||
|
||||
// extra optional instrutions
|
||||
ARC_asl, // Arithmetic shift left
|
||||
ARC_mul64, // Signed 32x32 multiply
|
||||
ARC_mulu64, // Unsigned 32x32 multiply
|
||||
ARC_max, // Maximum of two signed integers
|
||||
ARC_min, // Minimum of two signed integers
|
||||
ARC_swap, // Exchange upper and lower 16 bits
|
||||
ARC_norm, // Normalize (find-first-bit)
|
||||
|
||||
// ARCompact instructions
|
||||
ARC_bbit0, // Branch if bit cleared to 0
|
||||
ARC_bbit1, // Branch if bit set to 1
|
||||
ARC_br, // Branch on compare
|
||||
ARC_pop, // Restore register value from stack
|
||||
ARC_push, // Store register value on stack
|
||||
|
||||
ARC_abs, // Absolute value
|
||||
ARC_add1, // Add with left shift by 1 bit
|
||||
ARC_add2, // Add with left shift by 2 bits
|
||||
ARC_add3, // Add with left shift by 3 bits
|
||||
ARC_bclr, // Clear specified bit (to 0)
|
||||
ARC_bmsk, // Bit Mask
|
||||
ARC_bset, // Set specified bit (to 1)
|
||||
ARC_btst, // Test value of specified bit
|
||||
ARC_bxor, // Bit XOR
|
||||
ARC_cmp, // Compare
|
||||
ARC_ex, // Atomic Exchange
|
||||
ARC_mpy, // Signed 32x32 multiply (low)
|
||||
ARC_mpyh, // Signed 32x32 multiply (high)
|
||||
ARC_mpym = ARC_mpyh,
|
||||
ARC_mpyhu, // Unsigned 32x32 multiply (high)
|
||||
ARC_mpyhm = ARC_mpyhu,
|
||||
ARC_mpyu, // Unsigned 32x32 multiply (low)
|
||||
ARC_neg, // Negate
|
||||
ARC_not, // Logical bit inversion
|
||||
ARC_rcmp, // Reverse Compare
|
||||
ARC_rsub, // Reverse Subtraction
|
||||
ARC_rtie, // Return from Interrupt/Exception
|
||||
ARC_sub1, // Subtract with left shift by 1 bit
|
||||
ARC_sub2, // Subtract with left shift by 2 bits
|
||||
ARC_sub3, // Subtract with left shift by 3 bits
|
||||
ARC_sync, // Synchronize
|
||||
ARC_trap, // Raise an exception
|
||||
ARC_tst, // Test
|
||||
ARC_unimp, // Unimplemented instruction
|
||||
|
||||
ARC_abss, // Absolute and saturate
|
||||
ARC_abssw, // Absolute and saturate of word
|
||||
ARC_abssh = ARC_abssw,
|
||||
ARC_adds, // Add and saturate
|
||||
ARC_addsdw, // Add and saturate dual word
|
||||
ARC_asls, // Arithmetic shift left and saturate
|
||||
ARC_asrs, // Arithmetic shift right and saturate
|
||||
ARC_divaw, // Division assist
|
||||
ARC_negs, // Negate and saturate
|
||||
ARC_negsw, // Negate and saturate of word
|
||||
ARC_negsh = ARC_negsw,
|
||||
ARC_normw, // Normalize to 16 bits
|
||||
ARC_normh = ARC_normw,
|
||||
ARC_rnd16, // Round to word
|
||||
ARC_rndh = ARC_rnd16,
|
||||
ARC_sat16, // Saturate to word
|
||||
ARC_sath = ARC_sat16,
|
||||
ARC_subs, // Subtract and saturate
|
||||
ARC_subsdw, // Subtract and saturate dual word
|
||||
|
||||
// mac d16
|
||||
ARC_muldw,
|
||||
ARC_muludw,
|
||||
ARC_mulrdw,
|
||||
ARC_macdw,
|
||||
ARC_macudw,
|
||||
ARC_macrdw,
|
||||
ARC_msubdw,
|
||||
|
||||
// 32x16 MUL/MAC
|
||||
ARC_mululw,
|
||||
ARC_mullw,
|
||||
ARC_mulflw,
|
||||
ARC_maclw,
|
||||
ARC_macflw,
|
||||
ARC_machulw,
|
||||
ARC_machlw,
|
||||
ARC_machflw,
|
||||
ARC_mulhlw,
|
||||
ARC_mulhflw,
|
||||
|
||||
// Major 6 compact insns
|
||||
ARC_acm,
|
||||
ARC_addqbs,
|
||||
ARC_avgqb,
|
||||
ARC_clamp,
|
||||
ARC_daddh11,
|
||||
ARC_daddh12,
|
||||
ARC_daddh21,
|
||||
ARC_daddh22,
|
||||
ARC_dexcl1,
|
||||
ARC_dexcl2,
|
||||
ARC_dmulh11,
|
||||
ARC_dmulh12,
|
||||
ARC_dmulh21,
|
||||
ARC_dmulh22,
|
||||
ARC_dsubh11,
|
||||
ARC_dsubh12,
|
||||
ARC_dsubh21,
|
||||
ARC_dsubh22,
|
||||
ARC_drsubh11,
|
||||
ARC_drsubh12,
|
||||
ARC_drsubh21,
|
||||
ARC_drsubh22,
|
||||
ARC_fadd,
|
||||
ARC_fsadd = ARC_fadd,
|
||||
ARC_fmul,
|
||||
ARC_fsmul = ARC_fmul,
|
||||
ARC_fsub,
|
||||
ARC_fssub = ARC_fsub,
|
||||
ARC_fxtr,
|
||||
ARC_iaddr,
|
||||
ARC_mpyqb,
|
||||
ARC_sfxtr,
|
||||
ARC_pkqb,
|
||||
ARC_upkqb,
|
||||
ARC_xpkqb,
|
||||
|
||||
// ARCv2 only major 4 instructions
|
||||
ARC_mpyw, // Signed 16x16 multiply
|
||||
ARC_mpyuw, // Unsigned 16x16 multiply
|
||||
ARC_bi, // Branch indexed
|
||||
ARC_bih, // Branch indexed half-word
|
||||
ARC_ldi, // Load indexed
|
||||
ARC_aex, // Exchange with auxiliary register
|
||||
ARC_bmskn, // Bit mask negated
|
||||
ARC_seteq, // Set if equal
|
||||
ARC_setne, // Set if not equal
|
||||
ARC_setlt, // Set if less than
|
||||
ARC_setge, // Set if greater or equal
|
||||
ARC_setlo, // Set if lower than
|
||||
ARC_seths, // Set if higher or same
|
||||
ARC_setle, // Set if less than or equal
|
||||
ARC_setgt, // Set if greater than
|
||||
|
||||
ARC_rol, // Rotate left
|
||||
ARC_llock, // Load locked
|
||||
ARC_scond, // Store conditional
|
||||
|
||||
ARC_seti, // Set interrupt enable and priority level
|
||||
ARC_clri, // Cler and get interrupt enable and priority level
|
||||
|
||||
// ARCv2 compact prolog / epilog instructions
|
||||
ARC_enter, // Function prologue sequence
|
||||
ARC_leave, // Function epilogue sequence
|
||||
|
||||
// ARCv2 32-bit extension major 5 DOP instructions
|
||||
ARC_div, // Signed integer divsion
|
||||
ARC_divu, // Unsigned integer divsion
|
||||
ARC_rem, // Signed integer remainder
|
||||
ARC_remu, // Unsigned integer remainder
|
||||
ARC_asrsr, // Shift right rounding and saturating
|
||||
ARC_valgn2h, // Two-way 16-bit vector align
|
||||
ARC_setacc, // Set the accumulator
|
||||
ARC_mac, // Signed 32x32 multiply accumulate
|
||||
ARC_macu, // Unsigned 32x32 multiply accumulate
|
||||
ARC_dmpyh, // Sum of dual signed 16x16 multiplication
|
||||
ARC_dmpyhu, // Sum of dual unsigned 16x16 multiplication
|
||||
ARC_dmach, // Dual signed 16x16 multiply accumulate
|
||||
ARC_dmachu, // Dual unsigned 16x16 multiply accumulate
|
||||
ARC_vadd2h, // Dual 16-bit addition
|
||||
ARC_vadds2h, // Dual 16-bit saturating addition
|
||||
ARC_vsub2h, // Dual 16-bit subtraction
|
||||
ARC_vsubs2h, // Dual 16-bit saturating subtraction
|
||||
ARC_vaddsub2h, // Dual 16-bit addition/subtraction
|
||||
ARC_vaddsubs2h, // Dual 16-bit saturating addition/subtraction
|
||||
ARC_vsubadd2h, // Dual 16-bit subtraction/addition
|
||||
ARC_vsubadds2h, // Dual 16-bit saturating subtraction/addition
|
||||
ARC_mpyd, // Signed 32x32 multiply (wide)
|
||||
ARC_mpydu, // Unsigned 32x32 multiply (wide)
|
||||
ARC_macd, // Signed 32x32 multiply accumulate (wide)
|
||||
ARC_macdu, // Unsigned 32x32 multiply accumulate (wide)
|
||||
ARC_vmpy2h, // Dual signed 16x16 multiply (wide)
|
||||
ARC_vmpy2hf, // Dual 16x16 saturating fractional multiply
|
||||
ARC_vmpy2hu, // Dual unsigned 16x16 multiply (wide)
|
||||
ARC_vmpy2hfr, // Dual 16x16 saturating rounded fractional multiply
|
||||
ARC_vmac2h, // Dual signed 16x16 multiply (wide)
|
||||
ARC_vmac2hf, // Dual 16x16 saturating fractional multiply
|
||||
ARC_vmac2hu, // Dual unsigned 16x16 multiply (wide)
|
||||
ARC_vmac2hfr, // Dual 16x16 saturating rounded fractional multiply
|
||||
ARC_vmpy2hwf, // Dual 16x16 saturating fractional multiply (wide)
|
||||
ARC_vasl2h, // Dual 16-bit arithmetic shift left
|
||||
ARC_vasls2h, // Dual 16-bit saturating arithmetic shift left
|
||||
ARC_vasr2h, // Dual 16-bit arithmetic shift right
|
||||
ARC_vasrs2h, // Dual 16-bit saturating arithmetic shift right
|
||||
ARC_vlsr2h, // Dual 16-bit logical shift right
|
||||
ARC_vasrsr2h, // Dual 16-bit saturating rounded arithmetic shift right
|
||||
ARC_vadd4b, // Quad 8-bit addition
|
||||
ARC_vmax2h, // Dual 16-bit maximum
|
||||
ARC_vsub4b, // Quad 8-bit subtraction
|
||||
ARC_vmin2h, // Dual 16-bit minimum
|
||||
ARC_adcs, // Signed saturating addition with carry in
|
||||
ARC_sbcs, // Signed saturating subtraction with carry in
|
||||
ARC_dmpyhwf, // Fractional saturating sum of dual 16x16 signed fractional multiply
|
||||
ARC_vpack2hl, // Compose lower 16-bits
|
||||
ARC_vpack2hm, // Compose upper 16-bits
|
||||
ARC_dmpyhf, // Saturating sum of dual 16x16 signed fractional multiply
|
||||
ARC_dmpyhfr, // Saturating rounded sum of dual 16x16 signed fractional multiply
|
||||
ARC_dmachf, // Saturating sum of dual 16x16 signed fractional multiply accumulate
|
||||
ARC_dmachfr, // Saturating rounded sum of dual 16x16 signed fractional multiply accumulate
|
||||
ARC_vperm, // Byte permutation with zero or sign extension
|
||||
ARC_bspush, // Bitstream push
|
||||
|
||||
// ARCv2 32-bit extension major 5 SOP instructions
|
||||
ARC_swape, // Swap byte ordering
|
||||
ARC_lsl16, // Logical shift left by 16 bits
|
||||
ARC_lsr16, // Logical shift right by 16 bits
|
||||
ARC_asr16, // Arithmetic shift right by 16 bits
|
||||
ARC_asr8, // Arithmetic shift right by 8 bits
|
||||
ARC_lsr8, // Logical shift right by 8 bits
|
||||
ARC_lsl8, // Logical shift left by 8 bits
|
||||
ARC_rol8, // Rotate left by 8 bits
|
||||
ARC_ror8, // Rotate right by 8 bits
|
||||
ARC_ffs, // Find first set bit
|
||||
ARC_fls, // Find last set bit
|
||||
|
||||
ARC_getacc, // Get accumulator
|
||||
ARC_normacc, // Normalize accumulator
|
||||
ARC_satf, // Saturate according to flags
|
||||
ARC_vpack2hbl, // Pack lower bytes into lower 16 bits
|
||||
ARC_vpack2hbm, // Pack upper bytes into upper 16 bits
|
||||
ARC_vpack2hblf, // Pack upper bytes into lower 16 bits
|
||||
ARC_vpack2hbmf, // Pack lower bytes into upper 16 bits
|
||||
ARC_vext2bhlf, // Pack lower 2 bytes into upper byte of 16 bits each
|
||||
ARC_vext2bhmf, // Pack upper 2 bytes into upper byte of 16 bits each
|
||||
ARC_vrep2hl, // Repeat lower 16 bits
|
||||
ARC_vrep2hm, // Repeat upper 16 bits
|
||||
ARC_vext2bhl, // Pack lower 2 bytes into zero extended 16 bits
|
||||
ARC_vext2bhm, // Pack upper 2 bytes into zero extended 16 bits
|
||||
ARC_vsext2bhl, // Pack lower 2 bytes into sign extended 16 bits
|
||||
ARC_vsext2bhm, // Pack upper 2 bytes into sign extended 16 bits
|
||||
ARC_vabs2h, // Dual 16-bit absolute value
|
||||
ARC_vabss2h, // Dual saturating 16-bit absolute value
|
||||
ARC_vneg2h, // Dual 16-bit negation
|
||||
ARC_vnegs2h, // Dual saturating 16-bit negation
|
||||
ARC_vnorm2h, // Dual 16-bit normalization
|
||||
ARC_bspeek, // Bitstream peek
|
||||
ARC_bspop, // Bitstream pop
|
||||
ARC_sqrt, // Integer square root
|
||||
ARC_sqrtf, // Fractional square root
|
||||
|
||||
// ARCv2 32-bit extension major 5 ZOP instructions
|
||||
ARC_aslacc, // Arithmetic shift of accumulator
|
||||
ARC_aslsacc, // Saturating arithmetic shift of accumulator
|
||||
ARC_flagacc, // Copy accumulator flags to status32 register
|
||||
ARC_modif, // Update address pointer
|
||||
|
||||
// ARCv2 32-bit extension major 6 DOP instructions
|
||||
ARC_cmpyhnfr, // Fractional 16+16 bit complex saturating rounded unshifted multiply
|
||||
ARC_cmpyhfr, // Fractional 16+16 bit complex saturating rounded multiply
|
||||
ARC_cmpychfr, // Fractional 16+16 bit complex saturating rounded conjugated multiply
|
||||
ARC_vmsub2hf, // Dual 16x16 saturating fractional multiply subtract
|
||||
ARC_vmsub2hfr, // Dual 16x16 saturating rounded fractional multiply subtract
|
||||
ARC_cmpychnfr, // Fractional 16+16 bit complex saturating rounded unshifted conjugated multiply
|
||||
ARC_cmachnfr, // Fractional 16+16 bit complex saturating rounded unshifted multiply accumulate
|
||||
ARC_cmachfr, // Fractional 16+16 bit complex saturating rounded unshifted accumulate
|
||||
ARC_cmacchnfr, // Fractional 16+16 bit complex saturating rounded conjugated multiply accumulate
|
||||
ARC_cmacchfr, // Fractional 16+16 bit complex saturating rounded unshifted conjugated multiply accumulate
|
||||
ARC_mpyf, // Signed 32-bit fractional saturating multiply
|
||||
ARC_mpyfr, // Signed 32-bit fractional saturating rounded multiply
|
||||
ARC_macf, // Signed 32-bit fractional saturating multiply accumulate
|
||||
ARC_macfr, // Signed 32-bit fractional saturating rounded multiply accumulate
|
||||
ARC_msubf, // Signed 32-bit fractional saturating multiply subtract
|
||||
ARC_msubfr, // Signed 32-bit fractional saturating rounded multiply subtract
|
||||
ARC_divf, // Signed 32-bit fractional division
|
||||
ARC_vmac2hnfr, // Dual signed 16-bit fractional saturating rounded multiply accumulate
|
||||
ARC_vmsub2hnfr, // Dual signed 16-bit fractional saturating rounded multiply subtract
|
||||
ARC_mpydf, // Signed 32-bit fractional multiply (wide)
|
||||
ARC_macdf, // Signed 32-bit fractional multiply accumulate (wide)
|
||||
ARC_msubwhfl, // Signed 32 x 16 (lower) fractional saturating multiply subtract
|
||||
ARC_msubdf, // Signed 32-bit fractional multiply subtract (wide)
|
||||
ARC_dmpyhbl, // Dual 16x8 signed multiply with lower two bytes
|
||||
ARC_dmpyhbm, // Dual 16x8 signed multiply with upper two bytes
|
||||
ARC_dmachbl, // Dual 16x8 signed multiply accumulate with lower two bytes
|
||||
ARC_dmachbm, // Dual 16x8 signed multiply accumulate with upper two bytes
|
||||
ARC_msubwhflr, // Signed 32 x 16 (lower) fractional saturating rounded multiply subtract
|
||||
ARC_cmpyhfmr, // Fractional 16+16 bit complex x 16bit real (upper) saturating rounded multiply
|
||||
ARC_cbflyhf0r, // Fractional 16+16 bit complex FFT butterfly, first half
|
||||
ARC_mpywhl, // Signed 32 x 16 (lower) multiply
|
||||
ARC_macwhl, // Signed 32 x 16 (lower) multiply accumulate
|
||||
ARC_mpywhul, // Unsigned 32 x 16 (lower) multiply
|
||||
ARC_macwhul, // Unsigned 32 x 16 (lower) multiply accumulate
|
||||
ARC_mpywhfm, // Signed 32 x 16 (upper) fractional saturating multiply
|
||||
ARC_mpywhfmr, // Signed 32 x 16 (upper) fractional saturating rounded multiply
|
||||
ARC_macwhfm, // Signed 32 x 16 (upper) fractional saturating multiply accumulate
|
||||
ARC_macwhfmr, // Signed 32 x 16 (upper) fractional saturating rounded multiply accumulate
|
||||
ARC_mpywhfl, // Signed 32 x 16 (lower) fractional saturating multiply
|
||||
ARC_mpywhflr, // Signed 32 x 16 (lower) fractional saturating rounded multiply
|
||||
ARC_macwhfl, // Signed 32 x 16 (lower) fractional saturating multiply accumulate
|
||||
ARC_macwhflr, // Signed 32 x 16 (lower) fractional saturating rounded multiply accumulate
|
||||
ARC_macwhkl, // Signed 32 x 16 (lower) 16-bit shifted multiply accumulate
|
||||
ARC_macwhkul, // Unsigned 32 x 16 (lower) 16-bit shifted multiply accumulate
|
||||
ARC_mpywhkl, // Signed 32 x 16 (lower) 16-bit shifted multiply
|
||||
ARC_mpywhkul, // Unsigned 32 x 16 (lower) 16-bit shifted multiply
|
||||
ARC_msubwhfm, // Signed 32 x 16 (upper) fractional saturating multiply subtract
|
||||
ARC_msubwhfmr, // Signed 32 x 16 (upper) fractional saturating rounded multiply subtract
|
||||
|
||||
// ARCv2 32-bit extension major 6 SOP instructions
|
||||
ARC_cbflyhf1r, // Fractional 16+16 bit complex FFT butterfly, second half
|
||||
|
||||
// ARCv2 FPU instructions
|
||||
ARC_fscmp, // Single precision floating point compare
|
||||
ARC_fscmpf, // Single precision floating point compare (IEEE 754 flag generation)
|
||||
ARC_fsmadd, // Single precision floating point fused multiply add
|
||||
ARC_fsmsub, // Single precision floating point fused multiply subtract
|
||||
ARC_fsdiv, // Single precision floating point division
|
||||
ARC_fcvt32, // Single precision floating point / integer conversion
|
||||
ARC_fssqrt, // Single precision floating point square root
|
||||
|
||||
// ARCv2 jump / execute indexed instructions
|
||||
ARC_jli, // Jump and link indexed
|
||||
ARC_ei, // Execute indexed
|
||||
|
||||
ARC_kflag, // Set kernel flags
|
||||
ARC_wevt, // Enter sleep state
|
||||
|
||||
ARC_last,
|
||||
};
|
||||
|
||||
#endif
|
||||
57
idasdk76/module/arc/makefile
Normal file
57
idasdk76/module/arc/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=arc
|
||||
CONFIGS=arc.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)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp ana.cpp arc.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)ieee.h $(I)jumptable.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)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../idaidp.hpp ../iohandler.hpp arc.hpp emu.cpp 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)ieee.h $(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)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp arc.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)ieee.h $(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)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp arc.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)ieee.h $(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)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp arc.hpp ins.hpp reg.cpp
|
||||
539
idasdk76/module/arc/out.cpp
Normal file
539
idasdk76/module/arc/out.cpp
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* 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 "arc.hpp"
|
||||
|
||||
// generic condition codes
|
||||
static const char *const ccode[] =
|
||||
{
|
||||
"", ".z", ".nz", ".p",
|
||||
".n", ".c", ".nc", ".v",
|
||||
".nv", ".gt", ".ge", ".lt",
|
||||
".le", ".hi", ".ls", ".pnz",
|
||||
".ss", ".sc", ".c0x12", ".c0x13",
|
||||
".c0x14", ".c0x15", ".c0x16", ".c0x17",
|
||||
".c0x18", ".c0x19", ".c0x1A", ".c0x1B",
|
||||
".c0x1C", ".c0x1D", ".c0x1E", ".c0x1F",
|
||||
};
|
||||
|
||||
// generic condition codes for ARCv2
|
||||
static const char *const ccode_v2[] =
|
||||
{
|
||||
"", ".eq", ".ne", ".p",
|
||||
".n", ".c", ".nc", ".v",
|
||||
".nv", ".gt", ".ge", ".lt",
|
||||
".le", ".hi", ".ls", ".pnz",
|
||||
".c0x10", ".c0x11", ".c0x12", ".c0x13",
|
||||
".c0x14", ".c0x15", ".c0x16", ".c0x17",
|
||||
".c0x18", ".c0x19", ".c0x1A", ".c0x1B",
|
||||
".c0x1C", ".c0x1D", ".c0x1E", ".c0x1F",
|
||||
};
|
||||
|
||||
|
||||
// condition codes for branches
|
||||
static const char *const ccode_b[] =
|
||||
{
|
||||
"", "eq", "ne", "pl",
|
||||
"mi", "lo", "hs", "vs",
|
||||
"vc", "gt", "ge", "lt",
|
||||
"le", "hi", "ls", "pnz",
|
||||
"ss", "sc", "c0x12", "c0x13",
|
||||
"c0x14", "c0x15", "c0x16", "c0x17",
|
||||
"c0x18", "c0x19", "c0x1A", "c0x1B",
|
||||
"c0x1C", "c0x1D", "c0x1E", "c0x1F",
|
||||
};
|
||||
|
||||
// condition codes for ARCv2 branches
|
||||
static const char *const ccode_b_v2[] =
|
||||
{
|
||||
"", "eq", "ne", "p",
|
||||
"n", "lo", "hs", "v",
|
||||
"nv", "gt", "ge", "lt",
|
||||
"le", "hi", "ls", "pnz",
|
||||
"c0x10", "c0x11", "c0x12", "c0x13",
|
||||
"c0x14", "c0x15", "c0x16", "c0x17",
|
||||
"c0x18", "c0x19", "c0x1A", "c0x1B",
|
||||
"c0x1C", "c0x1D", "c0x1E", "c0x1F",
|
||||
};
|
||||
|
||||
|
||||
/* jump delay slot codes */
|
||||
static const char ncode[][4] = { "", ".d", ".jd", ".d?" };
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_arc_t : public outctx_t
|
||||
{
|
||||
out_arc_t(void) = delete; // not used
|
||||
void set_gr_cmt(const char *cmt) { user_data = (void *)cmt; }
|
||||
const char *get_gr_cmt(void) const { return (const char *)user_data; }
|
||||
public:
|
||||
void outreg(int rn);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
void out_specreg(const ioports_t &table, const op_t &x);
|
||||
void out_aux(const op_t &x)
|
||||
{
|
||||
arc_t &pm = *static_cast<arc_t *>(procmod);
|
||||
out_specreg(pm.auxregs, x);
|
||||
}
|
||||
};
|
||||
CASSERT(sizeof(out_arc_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_arc_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_arc_t::outreg(int rn)
|
||||
{
|
||||
const char *regname = (rn < ph.regs_num) ? ph.reg_names[rn] : "<bad register>";
|
||||
out_register(regname);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_arc_t::out_specreg(const ioports_t &table, const op_t &x)
|
||||
{
|
||||
const ioport_t *reg = find_ioport(table, x.value);
|
||||
if ( reg == NULL )
|
||||
{
|
||||
out_symbol('[');
|
||||
out_value(x, OOFS_IFSIGN | OOFW_32);
|
||||
out_symbol(']');
|
||||
}
|
||||
else
|
||||
{
|
||||
out_register(reg->name.c_str());
|
||||
if ( !reg->cmt.empty() && !has_cmt(F) )
|
||||
set_gr_cmt(reg->cmt.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/* outputs an operand 'x' */
|
||||
bool out_arc_t::out_operand(const op_t & x)
|
||||
{
|
||||
arc_t &pm = *static_cast<arc_t *>(procmod);
|
||||
ea_t v;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
{
|
||||
int hidden_base = is_hidden_base_reg(x.reg);
|
||||
if ( hidden_base != -1 )
|
||||
out_symbol('[');
|
||||
if ( hidden_base == 0 )
|
||||
{
|
||||
outreg(x.reg);
|
||||
out_symbol(',');
|
||||
}
|
||||
outreg(x.secreg);
|
||||
if ( hidden_base != -1 )
|
||||
out_symbol(']');
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
// check for: LR <dest>, [aux]
|
||||
// SR <src>, [aux]
|
||||
if ( x.n == 1
|
||||
&& !is_defarg(F, x.n) // don't use aux register if op type is set
|
||||
&& (insn.itype == ARC_lr || insn.itype == ARC_sr) )
|
||||
out_aux(x);
|
||||
else
|
||||
out_value(x, OOFS_IFSIGN | OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
if ( (insn.auxpref & aux_pcload) != 0 )
|
||||
{
|
||||
// A little hack to make the output
|
||||
// more readable...
|
||||
op_t y;
|
||||
if ( pm.copy_insn_optype(insn, x, ea, &y.value) )
|
||||
{
|
||||
y.dtype = x.dtype;
|
||||
y.flags = OF_SHOW;
|
||||
out_symbol('=');
|
||||
set_dlbind_opnd();
|
||||
ea_t insn_ea_sav = insn_ea;
|
||||
flags_t savedF = F;
|
||||
insn_ea = ea; // change context
|
||||
F = get_flags(ea);
|
||||
out_value(y, OOFS_IFSIGN|OOFW_IMM);
|
||||
insn_ea = insn_ea_sav; // restore context
|
||||
F = savedF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out_symbol('[');
|
||||
if ( insn.itype != ARC_lr && insn.itype != ARC_sr )
|
||||
{
|
||||
if ( !out_name_expr(x, ea, x.addr) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(uint32(x.addr), 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_btoa(uint32(x.addr), 16);
|
||||
}
|
||||
if ( x.immdisp != 0 )
|
||||
{
|
||||
out_symbol('-');
|
||||
out_btoa(uint32(x.immdisp * get_scale_factor(insn)), 16);
|
||||
out_symbol(',');
|
||||
out_btoa(uint32(x.immdisp), 16);
|
||||
}
|
||||
out_symbol(']');
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
v = to_ea(insn.cs, x.addr);
|
||||
if ( !out_name_expr(x, v, x.addr) )
|
||||
{
|
||||
out_value(x, OOF_ADDR|OOF_NUMBER|OOFS_NOSIGN|OOFW_32);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
{
|
||||
// membase=0: [reg, #addr]
|
||||
// membase=1: [#addr, reg]
|
||||
int hidden_base = is_hidden_base_reg(x.reg);
|
||||
if ( hidden_base != -1 )
|
||||
out_symbol('[');
|
||||
if ( x.membase == 0 && hidden_base == 0 )
|
||||
outreg(x.reg);
|
||||
if ( x.addr != 0
|
||||
|| hidden_base != 0
|
||||
|| is_off(F, x.n)
|
||||
|| is_stkvar(F, x.n)
|
||||
|| is_enum(F, x.n)
|
||||
|| is_stroff(F, x.n) )
|
||||
{
|
||||
if ( x.membase == 0 && hidden_base == 0 )
|
||||
out_symbol(',');
|
||||
out_value(x, OOF_ADDR|OOFS_IFSIGN|OOF_SIGNED|OOFW_32);
|
||||
if ( x.membase != 0 )
|
||||
out_symbol(',');
|
||||
}
|
||||
if ( x.membase != 0 )
|
||||
outreg(x.reg);
|
||||
if ( hidden_base != -1 )
|
||||
out_symbol(']');
|
||||
}
|
||||
break;
|
||||
|
||||
case o_reglist:
|
||||
{
|
||||
out_symbol('{');
|
||||
bool need_comma = false;
|
||||
int regs = x.reglist & REGLIST_REGS;
|
||||
if ( regs > REGLISTR_MAX )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(regs, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
need_comma = true;
|
||||
}
|
||||
else if ( regs > 0 )
|
||||
{
|
||||
outreg(R13);
|
||||
if ( regs > 1 )
|
||||
{
|
||||
out_symbol('-');
|
||||
outreg(R13 + regs - 1);
|
||||
}
|
||||
need_comma = true;
|
||||
}
|
||||
if ( (x.reglist & REGLIST_FP) != 0 )
|
||||
{
|
||||
if ( need_comma )
|
||||
out_symbol(',');
|
||||
outreg(FP);
|
||||
need_comma = true;
|
||||
}
|
||||
if ( (x.reglist & REGLIST_BLINK) != 0 )
|
||||
{
|
||||
if ( need_comma )
|
||||
out_symbol(',');
|
||||
outreg(BLINK);
|
||||
need_comma = true;
|
||||
}
|
||||
if ( (x.reglist & REGLIST_PCL) != 0 )
|
||||
{
|
||||
if ( need_comma )
|
||||
out_symbol(',');
|
||||
outreg(PCL);
|
||||
need_comma = true;
|
||||
}
|
||||
out_symbol('}');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
out_symbol('?');
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline bool is_branch(const insn_t &insn)
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case ARC_b:
|
||||
case ARC_lp:
|
||||
case ARC_bl:
|
||||
case ARC_j:
|
||||
case ARC_jl:
|
||||
case ARC_br:
|
||||
case ARC_bbit0:
|
||||
case ARC_bbit1:
|
||||
return true;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
// delay slot bits must be only set for branches
|
||||
QASSERT(10184, !has_dslot(insn));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_arc_t::out_proc_mnem(void)
|
||||
{
|
||||
arc_t &pm = *static_cast<arc_t *>(procmod);
|
||||
char postfix[MAXSTR];
|
||||
postfix[0] = '\0';
|
||||
if ( insn.itype == ARC_null )
|
||||
{
|
||||
uint32 code = get_dword(insn.ea);
|
||||
|
||||
int i = (code>>27)&31;
|
||||
if ( i == 3 )
|
||||
{
|
||||
int c = (code>>9)&63;
|
||||
qsnprintf(postfix, sizeof(postfix), "ext%02X_%02X", i, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsnprintf(postfix, sizeof(postfix), "ext%02X", i);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have a load or store instruction, flags are used a bit different */
|
||||
if ( insn.itype <= ARC_store_instructions )
|
||||
{
|
||||
switch ( insn.auxpref & aux_zmask )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case aux_b:
|
||||
qstrncat(postfix, "b", sizeof(postfix));
|
||||
break;
|
||||
case aux_w:
|
||||
qstrncat(postfix, pm.is_arcv2() ? "h" : "w", sizeof(postfix));
|
||||
break;
|
||||
default:
|
||||
qstrncat(postfix, "?", sizeof(postfix));
|
||||
break;
|
||||
}
|
||||
if ( (insn.auxpref & aux_s) != 0 )
|
||||
qstrncat(postfix, "_s", sizeof(postfix));
|
||||
if ( insn.auxpref & aux_x )
|
||||
qstrncat(postfix, ".x", sizeof(postfix));
|
||||
switch ( insn.auxpref & aux_amask )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case aux_a:
|
||||
qstrncat(postfix, ".a", sizeof(postfix));
|
||||
break;
|
||||
case aux_as:
|
||||
qstrncat(postfix, ".as", sizeof(postfix));
|
||||
break;
|
||||
case aux_ab:
|
||||
qstrncat(postfix, ".ab", sizeof(postfix));
|
||||
break;
|
||||
default:
|
||||
qstrncat(postfix, "?", sizeof(postfix));
|
||||
break;
|
||||
}
|
||||
if ( insn.auxpref & aux_di )
|
||||
qstrncat(postfix, ".di", sizeof(postfix));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 cond = insn.auxpref & aux_cmask;
|
||||
if ( cond != cAL && is_branch(insn) )
|
||||
{
|
||||
if ( pm.is_arcv2() )
|
||||
qstrncat(postfix, ccode_b_v2[cond], sizeof(postfix));
|
||||
else
|
||||
qstrncat(postfix, ccode_b[cond], sizeof(postfix));
|
||||
}
|
||||
|
||||
if ( (insn.auxpref & aux_s) != 0 )
|
||||
qstrncat(postfix, "_s", sizeof(postfix));
|
||||
|
||||
if ( cond != cAL && !is_branch(insn) )
|
||||
{
|
||||
if ( pm.is_arcv2() )
|
||||
qstrncat(postfix, ccode_v2[cond], sizeof(postfix));
|
||||
else
|
||||
qstrncat(postfix, ccode[cond], sizeof(postfix));
|
||||
}
|
||||
}
|
||||
if ( is_branch(insn) ) // delay slot code
|
||||
qstrncat(postfix, ncode[(insn.auxpref >> 5) & 3], sizeof(postfix));
|
||||
else if ( (insn.auxpref & aux_f) != 0 )
|
||||
{
|
||||
// for these load/store like instructions, the f bit is used for the .di
|
||||
if ( insn.itype == ARC_ex
|
||||
|| insn.itype == ARC_llock
|
||||
|| insn.itype == ARC_scond )
|
||||
{
|
||||
qstrncat(postfix, ".di", sizeof(postfix));
|
||||
}
|
||||
else if ( insn.itype != ARC_flag // flag implicitly sets this bit
|
||||
&& insn.itype != ARC_rcmp ) // rcmp implicitly sets this bit
|
||||
{
|
||||
qstrncat(postfix, ".f", sizeof(postfix));
|
||||
}
|
||||
}
|
||||
|
||||
if ( pm.is_arcv2() && ( insn.auxpref & aux_bhint ) != 0 )
|
||||
{
|
||||
// print static prediction hint
|
||||
/*
|
||||
from "Assembler Syntax for Static Branch Predictions"
|
||||
The default static prediction, in the absence of any <.T> syntax, is always BTFN (Backwards Taken, Forwards Not Taken).
|
||||
Therefore, a BRcc instruction always has the Y bit set to 0 by default, whereas a BBITn instruction always has the Y bit set to 1
|
||||
by default.
|
||||
*/
|
||||
bool backwards = insn.Op3.addr <= insn.ea;
|
||||
const char *suf = NULL;
|
||||
if ( insn.itype == ARC_br )
|
||||
suf = backwards ? ".t" : ".nt";
|
||||
else
|
||||
suf = backwards ? ".nt" : ".t";
|
||||
qstrncat(postfix, suf, sizeof(postfix));
|
||||
}
|
||||
|
||||
out_mnem(8, postfix); // output instruction mnemonics
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_arc_t::out_insn(void)
|
||||
{
|
||||
arc_t &pm = *static_cast<arc_t *>(procmod);
|
||||
out_mnemonic();
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_one_operand(0); // output the first operand
|
||||
|
||||
for ( int i = 1; i < PROC_MAXOP; ++i )
|
||||
{
|
||||
if ( insn.ops[i].type != o_void )
|
||||
{
|
||||
if ( !(insn.ops[i].type == o_reg && insn.ops[i].regpair) )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
}
|
||||
out_one_operand(i); // output the current operand
|
||||
}
|
||||
}
|
||||
|
||||
// output a character representation of the immediate values
|
||||
// embedded in the instruction as comments
|
||||
out_immchar_cmts();
|
||||
|
||||
// add comments for indirect calls or calculated data xrefs
|
||||
nodeidx_t callee = pm.get_callee(insn.ea);
|
||||
if ( callee == BADADDR )
|
||||
callee = pm.get_dxref(insn.ea);
|
||||
if ( callee != BADADDR )
|
||||
set_comment_addr(callee & ~1);
|
||||
const char *gr_cmt = get_gr_cmt();
|
||||
if ( gr_cmt != NULL )
|
||||
{
|
||||
out_char(' ');
|
||||
out_line(ash.cmnt, COLOR_AUTOCMT);
|
||||
out_char(' ');
|
||||
|
||||
out_line(gr_cmt, COLOR_AUTOCMT);
|
||||
if ( ash.cmnt2 != NULL )
|
||||
{
|
||||
out_char(' ');
|
||||
out_line(ash.cmnt2, COLOR_AUTOCMT);
|
||||
}
|
||||
}
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of the disassembly
|
||||
|
||||
void idaapi arc_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of a segment
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void arc_t::arc_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, Sarea);
|
||||
ctx.gen_printf(0, COLSTR(".section %s", SCOLOR_ASMDIR), name.c_str());
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
adiff_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
|
||||
if ( org != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_printf(0, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate end of the disassembly
|
||||
void idaapi arc_footer(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
|
||||
ctx.out_line(".end", COLOR_ASMDIR);
|
||||
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
ctx.out_line(" #");
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
908
idasdk76/module/arc/reg.cpp
Normal file
908
idasdk76/module/arc/reg.cpp
Normal file
@@ -0,0 +1,908 @@
|
||||
|
||||
/*
|
||||
* 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 "arc.hpp"
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", // 0 .. 7
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", // 8 .. 15
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", // 16 .. 23
|
||||
"r24", "r25", "gp", "fp", "sp", "ilink1", "ilink2", "blink", // 23 .. 31
|
||||
|
||||
"r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", // 31 .. 39
|
||||
"r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", // 40 .. 47
|
||||
"r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", // 48 .. 55
|
||||
"r56", "mlo", "mmid", "mhi","lp_count", "r61", "<limm>", "pcl", // 56 .. 63
|
||||
// condition codes
|
||||
"CF", "ZF", "NF", "VF",
|
||||
|
||||
// registers used for indexed instructions
|
||||
"next_pc",
|
||||
"ldi_base", "jli_base", "ei_base",
|
||||
|
||||
"gp_base",
|
||||
|
||||
"cs", "ds"
|
||||
};
|
||||
|
||||
static const uchar codeseq_arcompact[] = { 0xF1, 0xC0 }; // push blink
|
||||
static const uchar codeseq_arctg4[] = { 0x04, 0x3E, 0x0E, 0x10 }; // st blink, [sp,4]
|
||||
|
||||
static const bytes_t codestart_arcompact[] =
|
||||
{
|
||||
{ sizeof(codeseq_arcompact), codeseq_arcompact },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const bytes_t codestart_arctg4[] =
|
||||
{
|
||||
{ sizeof(codeseq_arctg4), codeseq_arctg4 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void arc_t::set_codeseqs() const
|
||||
{
|
||||
switch ( ptype )
|
||||
{
|
||||
case prc_arc:
|
||||
ph.codestart = codestart_arctg4;
|
||||
break;
|
||||
case prc_arcompact:
|
||||
case prc_arcv2:
|
||||
ph.codestart = codestart_arcompact;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// new names for old instructions in ARCv2
|
||||
//lint -e{958} padding of 6 bytes needed to align member on a 8 byte boundary
|
||||
struct instruc_alt_name_t
|
||||
{
|
||||
uint16 itype;
|
||||
const char *old_name; // ARCompact name
|
||||
const char *new_name; // ARCv2 name
|
||||
};
|
||||
|
||||
static const instruc_alt_name_t InstructionNamesARCv2[] =
|
||||
{
|
||||
{ ARC_mpyh, "mpyh", "mpym" },
|
||||
{ ARC_mpyhu, "mpyhu", "mpymu" },
|
||||
{ ARC_sexw, "sexw", "sexh" },
|
||||
{ ARC_extw, "extw", "exth" },
|
||||
{ ARC_sat16, "sat16", "sath" },
|
||||
{ ARC_rnd16, "rnd16", "rndh" },
|
||||
{ ARC_abssw, "abssw", "abssh" },
|
||||
{ ARC_negsw, "negsw", "negsh" },
|
||||
{ ARC_normw, "normw", "normh" },
|
||||
{ ARC_fadd, "fadd", "fsadd" },
|
||||
{ ARC_fmul, "fmul", "fsmul" },
|
||||
{ ARC_fsub, "fsub", "fssub" },
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
arc_t::arc_t()
|
||||
{
|
||||
memcpy(Instructions, ::Instructions, sizeof(Instructions));
|
||||
ph.instruc = Instructions;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// updates names in Instruction array to match the subtype
|
||||
void arc_t::set_instruc_names()
|
||||
{
|
||||
for ( int i = 0; i < qnumber(InstructionNamesARCv2); ++i )
|
||||
{
|
||||
const instruc_alt_name_t &name = InstructionNamesARCv2[i];
|
||||
Instructions[name.itype].name = is_arcv2() ? name.new_name : name.old_name;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// updates affected global state after a ptype change
|
||||
void arc_t::ptype_changed()
|
||||
{
|
||||
set_codeseqs();
|
||||
set_instruc_names();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// handler for some IDB events
|
||||
ssize_t idaapi pm_idb_listener_t::on_event(ssize_t notification_code, va_list va)
|
||||
{
|
||||
switch ( notification_code )
|
||||
{
|
||||
case idb_event::op_type_changed:
|
||||
// An operand type (offset, hex, etc...) has been set or deleted
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
int n = va_arg(va, int);
|
||||
if ( n >= 0 && n < UA_MAXOP && is_code(get_flags(ea)) )
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, ea);
|
||||
op_t &x = insn.ops[n];
|
||||
if ( x.type == o_mem )
|
||||
{
|
||||
ea = to_ea(insn.cs, x.addr);
|
||||
pm.copy_insn_optype(insn, x, ea, NULL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// ASMI
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t gnuas =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT | ASH_HEXF3 | ASO_OCTF1 | ASB_BINF3
|
||||
|AS_ONEDUP | AS_ASCIIC,
|
||||
0,
|
||||
"GNU assembler",
|
||||
0,
|
||||
NULL, // no headers
|
||||
".org", // org directive
|
||||
0, // end directive
|
||||
"#", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".ascii", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".short", // word directive
|
||||
".long", // dword (4 bytes)
|
||||
".quad", // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
".float", // float (4 bytes)
|
||||
".double", // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
".ds.#s(b,w,l,d) #d, #v", // arrays (#h,#d,#v,#s(...)
|
||||
".space %s", // uninited arrays
|
||||
"=", // equ
|
||||
NULL, // seg prefix
|
||||
".", // curent ip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
".global", // public
|
||||
NULL, // weak
|
||||
".extern", // extrn
|
||||
".comm", // comm
|
||||
NULL, // get_type_name
|
||||
".align", // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"!", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
|
||||
static const asm_t *const asms[] = { &gnuas, NULL };
|
||||
|
||||
static int idaapi choose_device(int, form_actions_t &);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
const char *arc_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void *value,
|
||||
bool idb_loaded)
|
||||
{
|
||||
if ( keyword == NULL )
|
||||
{
|
||||
static const char form[] =
|
||||
"HELP\n"
|
||||
"ARC specific options\n"
|
||||
"\n"
|
||||
" Simplify instructions\n"
|
||||
"\n"
|
||||
" If this option is on, IDA will simplify instructions and replace\n"
|
||||
" them by more natural pseudo-instructions or alternative mnemonics.\n"
|
||||
" For example,\n"
|
||||
"\n"
|
||||
" sub.f 0, a, b\n"
|
||||
"\n"
|
||||
" will be replaced by\n"
|
||||
"\n"
|
||||
" cmp a, b\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" Inline constant pool loads\n"
|
||||
"\n"
|
||||
" If this option is on, IDA will use =label syntax for\n"
|
||||
" pc-relative loads (commonly used to load constants)\n"
|
||||
" For example,\n"
|
||||
"\n"
|
||||
" ld r1, [pcl,0x1C]\n"
|
||||
" ...\n"
|
||||
" .long 0x2051D1C8\n"
|
||||
"\n"
|
||||
" will be replaced by\n"
|
||||
"\n"
|
||||
" ld r1, =0x2051D1C8\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" Track register accesses\n"
|
||||
"\n"
|
||||
" This option tells IDA to track values loaded\n"
|
||||
" into registers and use it to improve the listing.\n"
|
||||
" For example,\n"
|
||||
"\n"
|
||||
" mov r13, 0x172C\n"
|
||||
" ...\n"
|
||||
" add r0, r13, 0x98\n"
|
||||
"\n"
|
||||
" will be replaced by\n"
|
||||
"\n"
|
||||
" add r0, r13, (dword_17C4 - 0x172C)\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"ENDHELP\n"
|
||||
"ARC specific options\n"
|
||||
"%*\n"
|
||||
" <~S~implify instructions:C>\n"
|
||||
" <~I~nline constant pool loads:C>\n"
|
||||
" <Track ~r~egister accesses:C>>\n"
|
||||
" <~C~hoose core variant:B:0::>\n"
|
||||
"\n";
|
||||
CASSERT(sizeof(idpflags) == sizeof(ushort));
|
||||
ask_form(form, this, &idpflags, choose_device);
|
||||
goto SAVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( value_type != IDPOPT_BIT )
|
||||
return IDPOPT_BADTYPE;
|
||||
if ( strcmp(keyword, "ARC_SIMPLIFY") == 0 )
|
||||
{
|
||||
setflag(idpflags, ARC_SIMPLIFY, *(int*)value != 0);
|
||||
}
|
||||
else if ( strcmp(keyword, "ARC_INLINECONST") == 0 )
|
||||
{
|
||||
setflag(idpflags, ARC_INLINECONST, *(int*)value != 0);
|
||||
}
|
||||
else if ( strcmp(keyword, "ARC_TRACKREGS") == 0 )
|
||||
{
|
||||
setflag(idpflags, ARC_TRACKREGS, *(int*)value != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IDPOPT_BADKEY;
|
||||
}
|
||||
SAVE:
|
||||
if ( idb_loaded )
|
||||
save_idpflags();
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// The short and long names of the supported processors
|
||||
#define FAMILY "Argonaut RISC Core:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"arc",
|
||||
"arcmpct",
|
||||
"arcv2",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Argonaut RISC Core ARCtangent-A4",
|
||||
"Argonaut RISC Core ARCompact",
|
||||
"Argonaut RISC Core ARCv2",
|
||||
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 bytes_t retcodes[] =
|
||||
{
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void arc_iohandler_t::get_cfg_filename(char *buf, size_t bufsize)
|
||||
{
|
||||
qstrncpy(buf, "arc.cfg", bufsize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *arc_iohandler_t::iocallback(const ioports_t &iop, const char *line)
|
||||
{
|
||||
int len;
|
||||
sval_t ea1;
|
||||
char word[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
CASSERT(MAXSTR == 1024);
|
||||
if ( qsscanf(line, "aux %1023s %" FMT_EA "i%n", word, &ea1, &len) == 2 )
|
||||
{
|
||||
const char *cmt = &line[len];
|
||||
cmt = skip_spaces(cmt);
|
||||
ioport_t &port = pm.auxregs.push_back();
|
||||
port.address = ea1;
|
||||
port.name = word;
|
||||
if ( cmt[0] != '\0' )
|
||||
port.cmt = cmt;
|
||||
return NULL;
|
||||
}
|
||||
return standard_callback(iop, line);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool arc_t::select_device(int resp_info)
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
arc_respect_info = resp_info;
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
if ( !choose_ioport_device(&ioh.device, cfgfile) )
|
||||
{
|
||||
ioh.device = NONEPROC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !ioh.display_infotype_dialog(IORESP_ALL, &arc_respect_info, cfgfile) )
|
||||
return false;
|
||||
|
||||
ioh.set_device_name(ioh.device.c_str(), arc_respect_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int idaapi choose_device(int, form_actions_t &fa)
|
||||
{
|
||||
arc_t &pm = *(arc_t *)fa.get_ud();
|
||||
if ( pm.select_device(IORESP_ALL) )
|
||||
{
|
||||
// load_symbols(IORESP_ALL);
|
||||
// apply_symbols();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int idaapi arcso_gen_scaled_expr(
|
||||
qstring * /*buf*/,
|
||||
qstring *format,
|
||||
ea_t /*ea*/,
|
||||
int /*numop*/,
|
||||
const refinfo_t &ri,
|
||||
ea_t /*from*/,
|
||||
adiff_t * /*opval*/,
|
||||
ea_t * /*target*/,
|
||||
ea_t * /*fullvalue*/,
|
||||
int /*getn_flags*/)
|
||||
{
|
||||
arc_t &pm = *GET_MODULE_DATA(arc_t);
|
||||
int scale = ri.type() == pm.ref_arcsoh_id ? 2 : 4;
|
||||
format->sprnt("%%s " COLSTR("/", SCOLOR_SYMBOL) " %i", scale);
|
||||
return 4; // normal processing with custom format
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool idaapi arcso_calc_reference_data(
|
||||
ea_t *target,
|
||||
ea_t *base,
|
||||
ea_t from,
|
||||
const refinfo_t &ri,
|
||||
adiff_t opval)
|
||||
{
|
||||
arc_t &pm = *GET_MODULE_DATA(arc_t);
|
||||
qnotused(from);
|
||||
if ( ri.base == BADADDR || ri.is_subtract() )
|
||||
return false;
|
||||
|
||||
int scale = ri.type() == pm.ref_arcsoh_id ? 2 : 4;
|
||||
|
||||
*base = ri.base;
|
||||
*target = ri.base + scale * opval;
|
||||
|
||||
if ( ri.target != BADADDR && ri.target != *target )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const custom_refinfo_handler_t ref_arcsoh =
|
||||
{
|
||||
sizeof(custom_refinfo_handler_t),
|
||||
"ARCSOH",
|
||||
"ARC 16-bit scaled offset",
|
||||
RHF_TGTOPT, // properties: target be calculated using operand value
|
||||
arcso_gen_scaled_expr, // gen_expr
|
||||
arcso_calc_reference_data, // calc_reference_data
|
||||
NULL, // get_format
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const custom_refinfo_handler_t ref_arcsol =
|
||||
{
|
||||
sizeof(custom_refinfo_handler_t),
|
||||
"ARCSOL",
|
||||
"ARC 32-bit scaled offset",
|
||||
RHF_TGTOPT, // properties: target be calculated using operand value
|
||||
arcso_gen_scaled_expr, // gen_expr
|
||||
arcso_calc_reference_data, // calc_reference_data
|
||||
NULL, // get_format
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(arc_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void arc_t::load_from_idb()
|
||||
{
|
||||
ptype = processor_subtype_t(ph.get_proc_index());
|
||||
ptype_changed();
|
||||
idpflags = (ushort)helper.altval(-1);
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi arc_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
inf_set_be(false); // Set little-endian mode of the IDA kernel
|
||||
set_codeseqs();
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
ref_arcsol_id = register_custom_refinfo(&ref_arcsol);
|
||||
ref_arcsoh_id = register_custom_refinfo(&ref_arcsoh);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
unregister_custom_refinfo(ref_arcsoh_id);
|
||||
unregister_custom_refinfo(ref_arcsol_id);
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
save_idpflags();
|
||||
set_codeseqs();
|
||||
if ( inf_like_binary() )
|
||||
{
|
||||
// ask the user
|
||||
select_device(IORESP_ALL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// load the default AUX regs
|
||||
ioh.set_device_name(is_a4() ? "ARC4": "ARCompact", IORESP_NONE);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
ptype = va_argi(va, processor_subtype_t);
|
||||
// bool keep_cfg = va_argi(va, bool);
|
||||
if ( uint(ptype) > prc_arcv2 ) //lint !e685 //-V547 is always false
|
||||
{
|
||||
code = -1;
|
||||
break;
|
||||
}
|
||||
ptype_changed();
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_mnem(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_call_insn:
|
||||
// Is the instruction a "call"?
|
||||
// ea_t ea - instruction address
|
||||
// returns: 1-unknown, 0-no, 2-yes
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
code = is_arc_call_insn(*insn) ? 1 : -1;
|
||||
return code;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_ret_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
// bool strict = va_argi(va, bool);
|
||||
code = is_arc_return_insn(*insn) ? 1 : -1;
|
||||
return code;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_basic_block_end:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
bool call_insn_stops_block = va_argi(va, bool);
|
||||
return is_arc_basic_block_end(*insn, call_insn_stops_block) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_delay_slot_insn:
|
||||
// Get delay slot instruction
|
||||
// ea_t *ea in: instruction address in question,
|
||||
// it may point to the instruction with a
|
||||
// delay slot or to the delay slot
|
||||
// instruction itself
|
||||
// out: (if the answer is positive)
|
||||
// if the delay slot contains valid insn:
|
||||
// the address of the delay slot insn
|
||||
// else:
|
||||
// BADADDR (invalid insn, e.g. a branch)
|
||||
// bool *bexec execute slot if jumping
|
||||
// bool *fexec execute slot if not jumping
|
||||
// returns: 1 positive answer
|
||||
// <=0 ordinary insn
|
||||
{
|
||||
ea_t *ea = va_arg(va, ea_t *);
|
||||
bool *bexec = va_arg(va, bool *);
|
||||
bool *fexec = va_arg(va, bool *);
|
||||
insn_t insn;
|
||||
if ( decode_insn(&insn, *ea) == 0 )
|
||||
return -1;
|
||||
if ( has_dslot(insn) )
|
||||
{
|
||||
// the current instruction is a delayed slot instruction
|
||||
// set EA to the address of the delay slot
|
||||
*ea = insn.ea + insn.size;
|
||||
// check the insn in the delay slot
|
||||
// doc: "The Illegal Instruction Sequence type also occurs when
|
||||
// any of the following instructions are attempted in an executed
|
||||
// delay slot of a jump or branch:
|
||||
// * Another jump or branch instruction (Bcc, BLcc, Jcc, JLcc)
|
||||
// * Conditional loop instruction (LPcc)
|
||||
// * Return from interrupt (RTIE)
|
||||
// * Any instruction with long-immediate data as a source operand"
|
||||
insn_t dslot_insn;
|
||||
if ( decode_insn(&dslot_insn, *ea) == 0
|
||||
|| is_arc_simple_branch(dslot_insn.itype)
|
||||
|| dslot_insn.itype == ARC_lp
|
||||
|| dslot_insn.itype == ARC_rtie
|
||||
|| dslot_insn.size > 4
|
||||
|| dslot_insn.itype == ARC_br // ARCompact instructions
|
||||
|| dslot_insn.itype == ARC_bbit0
|
||||
|| dslot_insn.itype == ARC_bbit1 )
|
||||
{
|
||||
*ea = BADADDR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !is_flow(get_flags(*ea))
|
||||
|| decode_prev_insn(&insn, *ea) == BADADDR
|
||||
|| !has_dslot(insn) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// the previous instruction is a delayed slot instruction
|
||||
// EA already has the address of the delay slot
|
||||
}
|
||||
*bexec = true;
|
||||
*fexec = (insn.auxpref & aux_nmask) != aux_jd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_switch:
|
||||
{
|
||||
switch_info_t *si = va_arg(va, switch_info_t *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return arc_is_switch(si, *insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_may_be_func:
|
||||
// can a function start here?
|
||||
///< \param insn (const ::insn_t*) the instruction
|
||||
///< \param state (int) autoanalysis phase
|
||||
///< 0: creating functions
|
||||
///< 1: creating chunks
|
||||
///< \return probability 0..100
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
int state = va_arg(va, int);
|
||||
return arc_may_be_func(*insn, state);
|
||||
}
|
||||
|
||||
case processor_t::ev_undefine:
|
||||
{
|
||||
// an item is being undefined; delete data attached to it
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
del_insn_info(ea);
|
||||
}
|
||||
return 1;
|
||||
|
||||
// +++ TYPE CALLBACKS
|
||||
case processor_t::ev_decorate_name:
|
||||
{
|
||||
qstring *outbuf = va_arg(va, qstring *);
|
||||
const char *name = va_arg(va, const char *);
|
||||
bool mangle = va_argi(va, bool);
|
||||
cm_t cc = va_argi(va, cm_t);
|
||||
tinfo_t *type = va_arg(va, tinfo_t *);
|
||||
return gen_decorate_name(outbuf, name, mangle, cc, type) ? 1 : 0;
|
||||
}
|
||||
|
||||
case processor_t::ev_max_ptr_size:
|
||||
return 4;
|
||||
|
||||
case processor_t::ev_calc_arglocs:
|
||||
{
|
||||
func_type_data_t *fti = va_arg(va, func_type_data_t *);
|
||||
return calc_arc_arglocs(fti) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_calc_varglocs:
|
||||
{
|
||||
func_type_data_t *fti = va_arg(va, func_type_data_t *);
|
||||
regobjs_t *regargs = va_arg(va, regobjs_t *);
|
||||
/*relobj_t *stkargs =*/ va_arg(va, relobj_t *);
|
||||
int nfixed = va_arg(va, int);
|
||||
return calc_arc_varglocs(fti, regargs, nfixed) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_calc_retloc:
|
||||
{
|
||||
argloc_t *retloc = va_arg(va, argloc_t *);
|
||||
const tinfo_t *type = va_arg(va, const tinfo_t *);
|
||||
cm_t cc = va_argi(va, cm_t);
|
||||
return calc_arc_retloc(retloc, *type, cc) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_use_stkarg_type:
|
||||
return 0;
|
||||
|
||||
case processor_t::ev_use_regarg_type:
|
||||
{
|
||||
int *used = va_arg(va, int *);
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
const funcargvec_t *rargs = va_arg(va, const funcargvec_t *);
|
||||
*used = use_arc_regarg_type(ea, *rargs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_use_arg_types:
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
func_type_data_t *fti = va_arg(va, func_type_data_t *);
|
||||
funcargvec_t *rargs = va_arg(va, funcargvec_t *);
|
||||
use_arc_arg_types(ea, fti, rargs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_get_cc_regs:
|
||||
{
|
||||
callregs_t *callregs = va_arg(va, callregs_t *);
|
||||
cm_t cc = va_argi(va, cm_t);
|
||||
if ( cc == CM_CC_FASTCALL || cc == CM_CC_ELLIPSIS )
|
||||
{
|
||||
const int *regs;
|
||||
get_arc_fastcall_regs(®s);
|
||||
callregs->set(ARGREGS_INDEPENDENT, regs, NULL);
|
||||
return 1;
|
||||
}
|
||||
else if ( cc == CM_CC_THISCALL )
|
||||
{
|
||||
callregs->reset();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_calc_cdecl_purged_bytes:
|
||||
// calculate number of purged bytes after call
|
||||
{
|
||||
// ea_t ea = va_arg(va, ea_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case processor_t::ev_get_stkarg_offset:
|
||||
// get offset from SP to the first stack argument
|
||||
// args: none
|
||||
// returns: the offset+2
|
||||
return 0;
|
||||
|
||||
|
||||
// --- TYPE CALLBACKS
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
arc_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
arc_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 *);
|
||||
arc_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_is_sp_based:
|
||||
{
|
||||
int *mode = va_arg(va, int *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
*mode = is_sp_based(*insn, *op);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
create_func_frame(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_calc_spdelta:
|
||||
{
|
||||
sval_t *spdelta = va_arg(va, sval_t *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return arc_calc_spdelta(spdelta, *insn);
|
||||
}
|
||||
|
||||
case processor_t::ev_get_frame_retsize:
|
||||
{
|
||||
int *frsize = va_arg(va, int *);
|
||||
const func_t *pfn = va_arg(va, const func_t *);
|
||||
*frsize = arc_get_frame_retsize(pfn);
|
||||
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;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_align_insn:
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
return is_align_insn(ea);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_ARC, // id
|
||||
// flag
|
||||
PR_USE32 // 32-bit processor
|
||||
| PR_DEFSEG32 // create 32-bit segments by default
|
||||
| PRN_HEX // Values are hexadecimal by default
|
||||
| PR_TYPEINFO // Support the type system notifications
|
||||
| PR_CNDINSNS // Has conditional instructions
|
||||
| PR_DELAYED // Has delay slots
|
||||
| PR_USE_ARG_TYPES // use ph.use_arg_types callback
|
||||
| PR_RNAMESOK // register names can be reused for location names
|
||||
| PR_SEGS // has segment registers
|
||||
| PR_SGROTHER, // the segment registers don't contain the segment selectors.
|
||||
// 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, // Register names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
LDI_BASE, // first
|
||||
rVds, // last
|
||||
4, // size of a segment register
|
||||
rVcs, rVds,
|
||||
|
||||
codestart_arcompact, // code start sequences
|
||||
retcodes,
|
||||
|
||||
0, ARC_last,
|
||||
Instructions, // instruc
|
||||
0, // size of tbyte
|
||||
{0}, // real width
|
||||
0, // Icode of a return instruction
|
||||
NULL, // Micro virtual machine description
|
||||
};
|
||||
1745
idasdk76/module/arm/arm.hpp
Normal file
1745
idasdk76/module/arm/arm.hpp
Normal file
File diff suppressed because it is too large
Load Diff
142
idasdk76/module/arm/notify_codes.hpp
Normal file
142
idasdk76/module/arm/notify_codes.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ARM_NOTIFY_CODES_HPP
|
||||
#define __ARM_NOTIFY_CODES_HPP
|
||||
|
||||
struct pushinfo_t;
|
||||
struct arm_arch_t;
|
||||
//----------------------------------------------------------------------
|
||||
// The following events are supported by the ARM module in the ph.notify() function
|
||||
namespace arm_module_t
|
||||
{
|
||||
enum event_codes_t
|
||||
{
|
||||
// obsolete, use processor_t::set_code16_mode()
|
||||
ev_set_thumb_mode = processor_t::ev_loader,
|
||||
ev_set_arm_mode,
|
||||
// obsolete, use processor_t::get_code16_mode()
|
||||
ev_get_thumb_mode,
|
||||
ev_restore_pushinfo, // Restore function prolog info from the database
|
||||
// in: pushinfo_t *pi
|
||||
// ea_t func_start
|
||||
// Returns: 1-ok, otherwise-failed
|
||||
ev_save_pushinfo, // Save function prolog info to the database
|
||||
// in: ea_t func_start
|
||||
// const pushinfo_t *pi
|
||||
// Returns: 1-ok, otherwise-failed
|
||||
ev_is_push_insn, // Is push instruction?
|
||||
// in: uint32 *reglist
|
||||
// const insn_t* insn
|
||||
// Returns: 1-yes, -1-no
|
||||
ev_is_pop_insn, // Is pop instruction?
|
||||
// in: uint32 *reglist
|
||||
// const insn_t* insn
|
||||
// bool allow_ldmed
|
||||
// Returns: 1-yes, -1-no
|
||||
ev_is_gnu_mcount_nc, // Is __gnu_mcount_nc function?
|
||||
// in: ea_t ea
|
||||
// Returns: 1-yes, -1-no
|
||||
ev_is_special_func, // Is special function?
|
||||
// in: ea_t ea
|
||||
// Returns: special_func_t
|
||||
ev_get_arch_settings, // in: arm_arch_t *arch to be filled in
|
||||
// size_t strucsize;(init to sizeof(arm_arch_t)
|
||||
// Returns: 1-ok, otherwise-failed
|
||||
ev_get_fptr_info, // Get frame pointer info for given function
|
||||
// in: ushort *reg (out) FP register number
|
||||
// ea_t *addr (out) address where the fp register is set
|
||||
// ea_t func_start
|
||||
// Returns: 1-ok, 0-no FP register
|
||||
ev_serialize_pushinfo, // Save function prolog info to the buffer
|
||||
// in: bytevec_t *buf
|
||||
// ea_t func_start
|
||||
// const pushinfo_t *pi
|
||||
// int flags (reserved)
|
||||
// Returns: 1-ok, otherwise-failed
|
||||
ev_deserialize_pushinfo,
|
||||
// Restore function prolog info from the buffer
|
||||
// in: pushinfo_t *pi
|
||||
// memory_deserializer_t *buf
|
||||
// ea_t func_start
|
||||
// int flags (reserved)
|
||||
// Returns: 1-ok, otherwise-failed
|
||||
};
|
||||
|
||||
inline processor_t::event_t idp_ev(event_codes_t ev)
|
||||
{
|
||||
return processor_t::event_t(ev);
|
||||
}
|
||||
|
||||
inline bool restore_pushinfo(pushinfo_t *pi, ea_t func_start)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_restore_pushinfo), pi, func_start) == 1;
|
||||
}
|
||||
|
||||
inline bool save_pushinfo(ea_t func_start, const pushinfo_t &pi)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_save_pushinfo), func_start, &pi) == 1;
|
||||
}
|
||||
|
||||
inline bool is_push_insn(uint32 *reglist, const insn_t &insn)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_is_push_insn), reglist, &insn) == 1;
|
||||
}
|
||||
|
||||
inline bool is_pop_insn(uint32 *reglist, const insn_t &insn, bool allow_ldmed)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_is_pop_insn), reglist, &insn, allow_ldmed) == 1;
|
||||
}
|
||||
|
||||
inline bool is_gnu_mcount_nc(ea_t ea)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_is_gnu_mcount_nc), ea) == 1;
|
||||
}
|
||||
|
||||
inline int is_special_func(ea_t ea)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_is_special_func), ea);
|
||||
}
|
||||
|
||||
inline bool get_arch_settings(arm_arch_t *arch)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_get_arch_settings), arch) == 1;
|
||||
}
|
||||
|
||||
inline bool get_fptr_info(ushort *reg, ea_t *addr, ea_t func_start)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_get_fptr_info), reg, addr, func_start) == 1;
|
||||
}
|
||||
|
||||
inline bool serialize_pushinfo(
|
||||
bytevec_t *buf,
|
||||
ea_t func_start,
|
||||
const pushinfo_t &pi,
|
||||
int flags = 0)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_serialize_pushinfo),
|
||||
buf,
|
||||
func_start,
|
||||
&pi,
|
||||
flags) == 1;
|
||||
}
|
||||
|
||||
inline bool deserialize_pushinfo(
|
||||
pushinfo_t *pi,
|
||||
memory_deserializer_t *buf,
|
||||
ea_t func_start,
|
||||
int flags = 0)
|
||||
{
|
||||
return processor_t::notify(idp_ev(ev_deserialize_pushinfo),
|
||||
pi,
|
||||
buf,
|
||||
func_start,
|
||||
flags) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __NOTIFY_CODES_HPP
|
||||
819
idasdk76/module/avr/ana.cpp
Normal file
819
idasdk76/module/avr/ana.cpp
Normal file
@@ -0,0 +1,819 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include <fixup.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
0000 0000 0000 0000 nop
|
||||
0000 0001 dddd rrrr movw Rd,Rr
|
||||
0000 0010 dddd rrrr muls Rd,Rr
|
||||
0000 0011 0ddd 0rrr mulsu Rd,Rr
|
||||
0000 0011 0ddd 1rrr fmul Rd,Rr
|
||||
0000 0011 1ddd 0rrr fmuls Rd,Rr
|
||||
0000 0011 1ddd 1rrr fmulsu Rd,Rr
|
||||
0000 01rd dddd rrrr cpc rd, rr
|
||||
0000 10rd dddd rrrr sbc rd, rr
|
||||
0000 11rd dddd rrrr add rd, rr lsl rd if rd==rr
|
||||
0001 00rd dddd rrrr cpse rd, rr
|
||||
0001 01rd dddd rrrr cp rd, rr
|
||||
0001 10rd dddd rrrr sub rd, rr
|
||||
0001 11rd dddd rrrr adc rd, rr rol rd if rd==rr
|
||||
0010 00rd dddd rrrr and rd, rr tst rd if rd==rr
|
||||
0010 01rd dddd rrrr eor rd, rr clr rd if rd==rr
|
||||
0010 10rd dddd rrrr or rd, rr
|
||||
0010 11rd dddd rrrr mov rd, rr
|
||||
0011 kkkk dddd kkkk cpi rd, k (16<=d<=31)
|
||||
0100 kkkk dddd kkkk sbci rd, k (16<=d<=31)
|
||||
0101 kkkk dddd kkkk subi rd, k (16<=d<=31)
|
||||
0110 kkkk dddd kkkk ori/sbr rd, k (16<=d<=31)
|
||||
0111 kkkk dddd kkkk andi rd, k (16<=d<=31) cbr rd, k if op2 is bitwise negated
|
||||
1000 000d dddd 0000 ld rd, Z
|
||||
1000 000d dddd 1000 ld rd, Y
|
||||
1000 001r rrrr 0000 st Z, rr
|
||||
1000 001r rrrr 1000 st Y, rr
|
||||
1001 000d dddd 0000(1*k)lds rd, k
|
||||
1001 000d dddd 0001 ld rd, Z+
|
||||
1001 000d dddd 0010 ld rd, -Z
|
||||
1001 000d dddd 0100 lpm Rd, Z
|
||||
1001 000d dddd 0101 lpm Rd, Z+
|
||||
1001 000d dddd 0110 elpm Rd, Z
|
||||
1001 000d dddd 0111 elpm Rd, Z+
|
||||
1001 000d dddd 1001 ld rd, Y+
|
||||
1001 000d dddd 1010 ld rd, -Y
|
||||
1001 000d dddd 1100 ld rd, X
|
||||
1001 000d dddd 1101 ld rd, X+
|
||||
1001 000d dddd 1110 ld rd, -X
|
||||
1001 000d dddd 1111 pop rd
|
||||
1001 001d dddd 0000(1*k)sts k, rd
|
||||
1001 001d dddd 1111 push rd
|
||||
1001 001r rrrr 0001 st Z+, rr
|
||||
1001 001r rrrr 0010 st -Z, rr
|
||||
1001 001r rrrr 0100 xch Z, rr
|
||||
1001 001r rrrr 0101 las Z, rr
|
||||
1001 001r rrrr 0110 lac Z, rr
|
||||
1001 001r rrrr 0111 lat Z, rr
|
||||
1001 001r rrrr 1001 st Y+, rr
|
||||
1001 001r rrrr 1010 st -Y, rr
|
||||
1001 001r rrrr 1100 st X, rr
|
||||
1001 001r rrrr 1101 st X+, rr
|
||||
1001 001r rrrr 1110 st -X, rr
|
||||
1001 0100 0000 1000 sec
|
||||
1001 0100 0001 1000 sez
|
||||
1001 0100 0010 1000 sen
|
||||
1001 0100 0011 1000 sev
|
||||
1001 0100 0100 1000 ses
|
||||
1001 0100 0101 1000 seh
|
||||
1001 0100 0110 1000 set
|
||||
1001 0100 0111 1000 sei
|
||||
1001 0100 0sss 1000 bset s
|
||||
1001 0100 1000 1000 clc
|
||||
1001 0100 1001 1000 clz
|
||||
1001 0100 1010 1000 cln
|
||||
1001 0100 1011 1000 clv
|
||||
1001 0100 1100 1000 cls
|
||||
1001 0100 1101 1000 clh
|
||||
1001 0100 1110 1000 clt
|
||||
1001 0100 1111 1000 cli
|
||||
1001 0100 1sss 1000 bclr s
|
||||
1001 0100 0000 1001 ijmp
|
||||
1001 0100 0001 1001 eijmp
|
||||
1001 0100 KKKK 1011 des K
|
||||
1001 0101 0xx0 1000 ret
|
||||
1001 0101 0xx1 1000 reti
|
||||
1001 0101 100x 1000 sleep
|
||||
1001 0101 101x 1000 wdr
|
||||
1001 0101 110x 1000 lpm
|
||||
1001 0101 1101 1000 elpm
|
||||
1001 0101 1110 1000 spm
|
||||
1001 0101 1111 1000 espm
|
||||
1001 0101 0000 1001 icall
|
||||
1001 0101 0001 1001 eicall
|
||||
1001 010d dddd 0000 com rd
|
||||
1001 010d dddd 0001 neg rd
|
||||
1001 010d dddd 0010 swap rd
|
||||
1001 010d dddd 0011 inc rd
|
||||
1001 010d dddd 0101 asr rd
|
||||
1001 010d dddd 0110 lsr rd
|
||||
1001 010d dddd 0111 ror rd
|
||||
1001 010d dddd 1010 dec rd
|
||||
1001 010k kkkk 110k(1*k)jmp k
|
||||
1001 010k kkkk 111k(1*k)call k
|
||||
1001 0110 kkdd kkkk adiw rd, k (d=24,26,28,30)
|
||||
1001 0111 kkdd kkkk sbiw rd, k (d=24,26,28,30)
|
||||
1001 1000 pppp pbbb cbi p, b
|
||||
1001 1001 pppp pbbb sbic p, b
|
||||
1001 1010 pppp pbbb sbi p, b
|
||||
1001 1011 pppp pbbb sbis p, b
|
||||
1001 11rd dddd rrrr mul rd, rr
|
||||
1011 0ppd dddd pppp in rd, p
|
||||
1011 1ppr rrrr pppp out p, rr
|
||||
10q0 qq0d dddd 0qqq ldd rd, Z+q
|
||||
10q0 qq0d dddd 1qqq ldd rd, Y+q
|
||||
10q0 qq1r rrrr 0qqq std Z+d, rr
|
||||
10q0 qq1r rrrr 1qqq std Y+d, rr
|
||||
1100 kkkk kkkk kkkk rjmp k
|
||||
1101 kkkk kkkk kkkk rcall k
|
||||
1110 1111 dddd 1111 ser rd (16<=d<=31)
|
||||
1110 kkkk dddd kkkk ldi rd, k
|
||||
1111 00kk kkkk k000 brcs/brlo k
|
||||
1111 00kk kkkk k001 brne k
|
||||
1111 00kk kkkk k010 brmi k
|
||||
1111 00kk kkkk k011 brvs k
|
||||
1111 00kk kkkk k100 brlt k
|
||||
1111 00kk kkkk k101 brhs k
|
||||
1111 00kk kkkk k110 brts k
|
||||
1111 00kk kkkk k111 brie k
|
||||
1111 00kk kkkk ksss brbs s, k
|
||||
1111 01kk kkkk k000 brcc/brsh k
|
||||
1111 01kk kkkk k001 breq k
|
||||
1111 01kk kkkk k010 brpl k
|
||||
1111 01kk kkkk k011 brvc k
|
||||
1111 01kk kkkk k100 brge k
|
||||
1111 01kk kkkk k101 brhc k
|
||||
1111 01kk kkkk k110 brtc k
|
||||
1111 01kk kkkk k111 brid k
|
||||
1111 01kk kkkk ksss brbc s, k
|
||||
1111 100d dddd 0bbb bld rd, b
|
||||
1111 101d dddd Xbbb bst rd, b
|
||||
1111 110r rrrr xbbb sbrc rr, b
|
||||
1111 111r rrrr xbbb sbrs rr, b
|
||||
*/
|
||||
|
||||
// handle wraparound jumps
|
||||
inline uint32 avr_t::code_address(const insn_t &insn, signed int delta) const
|
||||
{
|
||||
ea_t newip = insn.ip + 1 + delta;
|
||||
uint32 size = romsize != 0 ? romsize : 0x10000;
|
||||
if ( insn.ip > size )
|
||||
return newip;
|
||||
else
|
||||
return newip % size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline ushort ua_next_full_byte(insn_t &insn)
|
||||
{
|
||||
return (ushort)get_wide_byte(insn.ea + insn.size++);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opreg(op_t &x, uint16 n, bool rpair = false)
|
||||
{
|
||||
x.type = o_reg;
|
||||
x.dtype = dt_byte;
|
||||
x.reg = n;
|
||||
if ( rpair )
|
||||
x.reg_pair = 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void avr_t::opimm(const insn_t &insn, op_t &x, int value) const
|
||||
{
|
||||
x.type = o_imm;
|
||||
x.dtype = dt_byte;
|
||||
x.value = value;
|
||||
x.specflag1 = uchar(helper.charval_ea(insn.ea, ELF_AVR_TAG) == ELF_AVR_LDI_NEG);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opnear(op_t &x, ea_t addr)
|
||||
{
|
||||
x.type = o_near;
|
||||
x.dtype = dt_code;
|
||||
x.addr = addr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opmem(insn_t &insn, op_t &x)
|
||||
{
|
||||
x.type = o_mem;
|
||||
x.dtype = dt_byte;
|
||||
x.offb = (char)insn.size;
|
||||
x.addr = ua_next_full_byte(insn);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 0001 10rd dddd rrrr sub rd, rr 6
|
||||
static void tworegs(insn_t &insn, int code)
|
||||
{
|
||||
opreg(insn.Op1, (code >> 4) & 31);
|
||||
opreg(insn.Op2, (code & 15) | ((code >> 5) & 16));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 1000 000d dddd 1000 ld rd, Y
|
||||
inline void opregd(op_t &x, int code)
|
||||
{
|
||||
opreg(x, (code >> 4) & 31);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opphr(op_t &x, phrase_t phrase)
|
||||
{
|
||||
x.type = o_phrase;
|
||||
x.phrase = phrase;
|
||||
x.dtype = dt_byte;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opport(op_t &x, int portnum)
|
||||
{
|
||||
x.type = o_port;
|
||||
x.addr = portnum;
|
||||
x.dtype = dt_byte;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opdisp(op_t &x, phrase_t phrase, int delta)
|
||||
{
|
||||
if ( delta )
|
||||
{
|
||||
x.type = o_displ;
|
||||
x.phrase = phrase;
|
||||
x.addr = delta;
|
||||
x.dtype = dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
opphr(x, phrase);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int avr_t::ana(insn_t *_insn)
|
||||
{
|
||||
if ( _insn == NULL )
|
||||
return 0;
|
||||
insn_t &insn = *_insn;
|
||||
// if ( insn.ip & 1 ) return 0; // alignment error
|
||||
int code = ua_next_full_byte(insn);
|
||||
switch ( code >> 12 )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
// 0000 0000 0000 0000 nop 0
|
||||
// 0000 0001 dddd rrrr movw Rd, Rr 0
|
||||
// 0000 0010 dddd rrrr muls Rd, Rr 0
|
||||
// 0000 0011 0ddd 0rrr mulsu Rd, Rr 0
|
||||
// 0000 0011 0ddd 1rrr fmul Rd, Rr 0
|
||||
// 0000 0011 1ddd 0rrr fmuls Rd, Rr 0
|
||||
// 0000 0011 1ddd 1rrr fmulsu Rd, Rr 0
|
||||
// 0000 01rd dddd rrrr cpc rd, rr 1
|
||||
// 0000 10rd dddd rrrr sbc rd, rr 2
|
||||
// 0000 11rd dddd rrrr add rd, rr 3 lsl rd if rd==rr
|
||||
// 0001 00rd dddd rrrr cpse rd, rr 4
|
||||
// 0001 01rd dddd rrrr cp rd, rr 5
|
||||
// 0001 10rd dddd rrrr sub rd, rr 6
|
||||
// 0001 11rd dddd rrrr adc rd, rr 7 rol rd if rd==rr
|
||||
// 0010 00rd dddd rrrr and rd, rr 8 tst rd if rd==rr
|
||||
// 0010 01rd dddd rrrr eor rd, rr 9 clr rd if rd==rr
|
||||
// 0010 10rd dddd rrrr or rd, rr A
|
||||
// 0010 11rd dddd rrrr mov rd, rr B
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_nop, // 0
|
||||
AVR_cpc, // 1
|
||||
AVR_sbc, // 2
|
||||
AVR_add, // 3
|
||||
AVR_cpse, // 4
|
||||
AVR_cp, // 5
|
||||
AVR_sub, // 6
|
||||
AVR_adc, // 7
|
||||
AVR_and, // 8
|
||||
AVR_eor, // 9
|
||||
AVR_or, // A
|
||||
AVR_mov // B
|
||||
};
|
||||
int idx = (code >> 10) & 15;
|
||||
insn.itype = itypes[idx];
|
||||
tworegs(insn, code);
|
||||
switch ( idx )
|
||||
{
|
||||
case 0:
|
||||
switch ( (code>>8) & 3 )
|
||||
{
|
||||
case 0: // nop
|
||||
if ( code != 0 )
|
||||
return 0;
|
||||
insn.Op1.type = insn.Op2.type = o_void;
|
||||
break;
|
||||
case 1: // movw
|
||||
insn.itype = AVR_movw;
|
||||
opreg(insn.Op1, ((code >> 3) & 30), true);
|
||||
opreg(insn.Op2, ((code << 1) & 30), true);
|
||||
break;
|
||||
case 2: // muls
|
||||
insn.itype = AVR_muls;
|
||||
opreg(insn.Op1, 16 + (((code >> 4) & 15)));
|
||||
opreg(insn.Op2, 16 + (((code >> 0) & 15)));
|
||||
break;
|
||||
// 0000 0011 0ddd 0rrr mulsu Rd, Rr 0
|
||||
// 0000 0011 0ddd 1rrr fmul Rd, Rr 0
|
||||
// 0000 0011 1ddd 0rrr fmuls Rd, Rr 0
|
||||
// 0000 0011 1ddd 1rrr fmulsu Rd, Rr 0
|
||||
case 3: // mulsu, fmul, fmuls, fmulsu
|
||||
{
|
||||
idx = ((code >> 6) & 2) | ((code>>3) & 1);
|
||||
static const uchar subtypes[] =
|
||||
{ AVR_mulsu, AVR_fmul, AVR_fmuls, AVR_fmulsu };
|
||||
insn.itype = subtypes[idx];
|
||||
}
|
||||
opreg(insn.Op1, 16 + (((code >> 4) & 7)));
|
||||
opreg(insn.Op2, 16 + (((code >> 0) & 7)));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3: // lsl
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_lsl;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
case 7: // rol
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_rol;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
case 8: // tst
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_tst;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
case 9: // clr
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_clr;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
// 0011 kkkk dddd kkkk cpi rd, k (16<=d<=31)
|
||||
// 0100 kkkk dddd kkkk sbci rd, k (16<=d<=31)
|
||||
// 0101 kkkk dddd kkkk subi rd, k (16<=d<=31)
|
||||
// 0110 kkkk dddd kkkk ori/sbr rd, k (16<=d<=31)
|
||||
// 0111 kkkk dddd kkkk andi rd, k (16<=d<=31) cbr rd, k if op2 is bitwise negated
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_cpi,
|
||||
AVR_sbci,
|
||||
AVR_subi,
|
||||
AVR_ori,
|
||||
AVR_andi,
|
||||
};
|
||||
insn.itype = itypes[(code >> 12) - 3];
|
||||
opreg(insn.Op1, ((code >> 4) & 15) + 16);
|
||||
opimm(insn, insn.Op2, (code & 0x0F) | ((code >> 4) & 0xF0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 10:
|
||||
// 10q0 qq0d dddd 0qqq ldd rd, Z+q
|
||||
// 10q0 qq0d dddd 1qqq ldd rd, Y+q
|
||||
// 10q0 qq1r rrrr 0qqq std Z+d, rr
|
||||
// 10q0 qq1r rrrr 1qqq std Y+d, rr
|
||||
// 1000 000d dddd 0000 ld rd, Z
|
||||
// 1000 000d dddd 1000 ld rd, Y
|
||||
// 1000 001r rrrr 0000 st Z, rr
|
||||
// 1000 001r rrrr 1000 st Y, rr
|
||||
{
|
||||
int delta = ((code & 0x2000) >> 8)
|
||||
| ((code & 0x0C00) >> 7)
|
||||
| (code & 0x0007);
|
||||
if ( code & 0x200 )
|
||||
{
|
||||
insn.itype = delta ? AVR_std : AVR_st;
|
||||
opdisp(insn.Op1, (code & 8) ? PH_Y : PH_Z, delta);
|
||||
opregd(insn.Op2, code);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = delta ? AVR_ldd : AVR_ld;
|
||||
opregd(insn.Op1, code);
|
||||
opdisp(insn.Op2, (code & 8) ? PH_Y : PH_Z, delta);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
switch ( (code >> 8) & 15 )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// 1001 000d dddd 0000(8*k)lds rd, k 0
|
||||
// 1001 000d dddd 0001 ld rd, Z+ 1
|
||||
// 1001 000d dddd 0010 ld rd, -Z 2
|
||||
// 1001 000d dddd 0100 lpm Rd, Z 4
|
||||
// 1001 000d dddd 0101 lpm Rd, Z+ 5
|
||||
// 1001 000d dddd 0110 elpm Rd, Z 6
|
||||
// 1001 000d dddd 0111 elpm Rd, Z+ 7
|
||||
// 1001 000d dddd 1001 ld rd, Y+ 9
|
||||
// 1001 000d dddd 1010 ld rd, -Y A
|
||||
// 1001 000d dddd 1100 ld rd, X C
|
||||
// 1001 000d dddd 1101 ld rd, X+ D
|
||||
// 1001 000d dddd 1110 ld rd, -X E
|
||||
// 1001 000d dddd 1111 pop rd F
|
||||
|
||||
// 1001 001d dddd 0000(8*k)sts k, rd 0
|
||||
// 1001 001r rrrr 0001 st Z+, rr 1
|
||||
// 1001 001r rrrr 0010 st -Z, rr 2
|
||||
// 1001 001r rrrr 0011 <unallocated> 3
|
||||
// 1001 001r rrrr 0100 xch Z, rr 4
|
||||
// 1001 001r rrrr 0101 las Z, rr 5
|
||||
// 1001 001r rrrr 0110 lac Z, rr 6
|
||||
// 1001 001r rrrr 0111 lat Z, rr 7
|
||||
// 1001 001r rrrr 1000 <unallocated> 8
|
||||
// 1001 001r rrrr 1001 st Y+, rr 9
|
||||
// 1001 001r rrrr 1010 st -Y, rr A
|
||||
// 1001 001r rrrr 1100 st X, rr C
|
||||
// 1001 001r rrrr 1101 st X+, rr D
|
||||
// 1001 001r rrrr 1110 st -X, rr E
|
||||
// 1001 001d dddd 1111 push rd F
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_lds, AVR_ld, AVR_ld, 0,
|
||||
AVR_lpm, AVR_lpm, AVR_elpm, AVR_elpm,
|
||||
0, AVR_ld, AVR_ld, 0,
|
||||
AVR_ld, AVR_ld, AVR_ld, AVR_pop
|
||||
};
|
||||
insn.itype = itypes[code & 15];
|
||||
opregd(insn.Op1, code);
|
||||
switch ( code & 15 )
|
||||
{
|
||||
case 0x0:
|
||||
opmem(insn, insn.Op2);
|
||||
switch ( helper.charval_ea(insn.ea+1, ELF_AVR_TAG) )
|
||||
{
|
||||
case ELF_AVR_EEP_OFF:
|
||||
insn.Op2.addr += ELF_AVR_EEPROMBASE-ELF_AVR_RAMBASE;
|
||||
case ELF_AVR_RAM_OFF:
|
||||
insn.Op2.addr += ELF_AVR_RAMBASE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x1: opphr(insn.Op2, PH_ZPLUS); break;
|
||||
case 0x2: opphr(insn.Op2, PH_MINUSZ); break;
|
||||
case 0x4: opphr(insn.Op2, PH_Z); break;
|
||||
case 0x5: opphr(insn.Op2, PH_ZPLUS); break;
|
||||
case 0x6: opphr(insn.Op2, PH_Z); break;
|
||||
case 0x7: opphr(insn.Op2, PH_ZPLUS); break;
|
||||
case 0x9: opphr(insn.Op2, PH_YPLUS); break;
|
||||
case 0xA: opphr(insn.Op2, PH_MINUSY); break;
|
||||
case 0xC: opphr(insn.Op2, PH_X); break;
|
||||
case 0xD: opphr(insn.Op2, PH_XPLUS); break;
|
||||
case 0xE: opphr(insn.Op2, PH_MINUSX); break;
|
||||
case 0xF: break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if ( code & 0x200 )
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case AVR_pop:
|
||||
insn.itype = AVR_push;
|
||||
break;
|
||||
case AVR_lds:
|
||||
insn.itype = AVR_sts;
|
||||
goto SWAP_OPERANDS;
|
||||
case AVR_ld:
|
||||
insn.itype = AVR_st;
|
||||
SWAP_OPERANDS:
|
||||
{
|
||||
op_t tmp = insn.Op1;
|
||||
insn.Op1 = insn.Op2;
|
||||
insn.Op2 = tmp;
|
||||
}
|
||||
break;
|
||||
case AVR_lpm:
|
||||
case AVR_elpm:
|
||||
// 1001 001r rrrr 0100 xch Z, rr 4
|
||||
// 1001 001r rrrr 0101 las Z, rr 5
|
||||
// 1001 001r rrrr 0110 lac Z, rr 6
|
||||
// 1001 001r rrrr 0111 lat Z, rr 7
|
||||
{
|
||||
static const uchar itypes2[] =
|
||||
{
|
||||
AVR_xch, AVR_las, AVR_lac, AVR_lat,
|
||||
};
|
||||
insn.itype = itypes2[code & 3];
|
||||
opphr(insn.Op1, PH_Z);
|
||||
opregd(insn.Op2, code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
switch ( code & 0xF )
|
||||
{
|
||||
case 11:
|
||||
// 1001 0100 KKKK 1011 des K
|
||||
switch ( code & 0x0F00 )
|
||||
{
|
||||
case 0x0400:
|
||||
insn.itype = AVR_des;
|
||||
opimm(insn, insn.Op1, (code >> 4) & 0xF);
|
||||
break;
|
||||
default: return 0;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
// 1001 0100 0000 1001 ijmp
|
||||
// 1001 0100 0001 1001 eijmp
|
||||
// 1001 0101 0000 1001 icall
|
||||
// 1001 0101 0001 1001 eicall
|
||||
switch ( code & 0xFF0 )
|
||||
{
|
||||
case 0x400: insn.itype = AVR_ijmp; break;
|
||||
case 0x410: insn.itype = AVR_eijmp; break;
|
||||
case 0x500: insn.itype = AVR_icall; break;
|
||||
case 0x510: insn.itype = AVR_eicall; break;
|
||||
default: return 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
// 1001 0101 0xx0 1000 ret
|
||||
// 1001 0101 0xx1 1000 reti
|
||||
// 1001 0101 100x 1000 sleep
|
||||
// 1001 0101 101x 1000 wdr
|
||||
// 1001 0101 1100 1000 lpm
|
||||
// 1001 0101 1101 1000 elpm
|
||||
// 1001 0101 1110 1000 spm
|
||||
// 1001 0101 1111 1000 espm
|
||||
if ( (code & 0x0F00) == 0x0500 )
|
||||
{
|
||||
if ( (code & 0x0090) == 0x0000 )
|
||||
insn.itype = AVR_ret;
|
||||
else if ( (code & 0x0090) == 0x0010 )
|
||||
insn.itype = AVR_reti;
|
||||
else if ( (code & 0x00E0) == 0x0080 )
|
||||
insn.itype = AVR_sleep;
|
||||
else if ( (code & 0x00E0) == 0x00A0 )
|
||||
insn.itype = AVR_wdr;
|
||||
else if ( (code & 0x00F0) == 0x00C0 )
|
||||
insn.itype = AVR_lpm;
|
||||
else if ( (code & 0x00F0) == 0x00D0 )
|
||||
insn.itype = AVR_elpm;
|
||||
else if ( (code & 0x00F0) == 0x00E0 )
|
||||
insn.itype = AVR_spm;
|
||||
else if ( (code & 0x00F0) == 0x00F0 )
|
||||
insn.itype = AVR_espm;
|
||||
break;
|
||||
}
|
||||
// 1001 0100 0000 1000 sec 0
|
||||
// 1001 0100 0001 1000 sez 1
|
||||
// 1001 0100 0010 1000 sen 2
|
||||
// 1001 0100 0011 1000 sev 3
|
||||
// 1001 0100 0100 1000 ses 4
|
||||
// 1001 0100 0101 1000 seh 5
|
||||
// 1001 0100 0110 1000 set 6
|
||||
// 1001 0100 0111 1000 sei 7
|
||||
// 1001 0100 0sss 1000 bset s
|
||||
// 1001 0100 1000 1000 clc 8
|
||||
// 1001 0100 1001 1000 clz 9
|
||||
// 1001 0100 1010 1000 cln a
|
||||
// 1001 0100 1011 1000 clv b
|
||||
// 1001 0100 1100 1000 cls c
|
||||
// 1001 0100 1101 1000 clh d
|
||||
// 1001 0100 1110 1000 clt e
|
||||
// 1001 0100 1111 1000 cli f
|
||||
// 1001 0100 1sss 1000 bclr s
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_sec, AVR_sez, AVR_sen, AVR_sev,
|
||||
AVR_ses, AVR_seh, AVR_set, AVR_sei,
|
||||
AVR_clc, AVR_clz, AVR_cln, AVR_clv,
|
||||
AVR_cls, AVR_clh, AVR_clt, AVR_cli,
|
||||
};
|
||||
insn.itype = itypes[(code >> 4) & 15];
|
||||
}
|
||||
break; // case 8
|
||||
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 10:
|
||||
// 1001 010d dddd 0000 com rd 0
|
||||
// 1001 010d dddd 0001 neg rd 1
|
||||
// 1001 010d dddd 0010 swap rd 2
|
||||
// 1001 010d dddd 0011 inc rd 3
|
||||
// 1001 010d dddd 0101 asr rd 5
|
||||
// 1001 010d dddd 0110 lsr rd 6
|
||||
// 1001 010d dddd 0111 ror rd 7
|
||||
// 1001 010d dddd 1010 dec rd 10
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_com, AVR_neg, AVR_swap, AVR_inc,
|
||||
0, AVR_asr, AVR_lsr, AVR_ror,
|
||||
0, 0, AVR_dec,
|
||||
};
|
||||
insn.itype = itypes[code & 15];
|
||||
opregd(insn.Op1, code);
|
||||
}
|
||||
break; // case 8
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
// 1001 010k kkkk 110k(1*k)jmp k
|
||||
// 1001 010k kkkk 111k(1*k)call k
|
||||
insn.itype = (code & 2) ? AVR_call : AVR_jmp;
|
||||
opnear(insn.Op1, (ea_t((code & 1) | ((code >> 3) & 0x3E)) << 16)
|
||||
| ua_next_full_byte(insn));
|
||||
if ( helper.charval_ea(insn.ea+1, ELF_AVR_TAG) == ELF_AVR_ABS_OFF )
|
||||
insn.Op1.addr += ELF_AVR_ABSBASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 7:
|
||||
// 1001 0110 kkdd kkkk adiw rd, k (d=24,26,28,30)
|
||||
// 1001 0111 kkdd kkkk sbiw rd, k (d=24,26,28,30)
|
||||
insn.itype = (code & 0x100) ? AVR_sbiw : AVR_adiw;
|
||||
opreg(insn.Op1, R24 + ((code >> 3) & 6), true);
|
||||
opimm(insn, insn.Op2, ((code >> 2) & 0x30) | (code & 0x0F));
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
// 1001 1000 pppp pbbb cbi p, b
|
||||
// 1001 1001 pppp pbbb sbic p, b
|
||||
// 1001 1010 pppp pbbb sbi p, b
|
||||
// 1001 1011 pppp pbbb sbis p, b
|
||||
{
|
||||
static const uchar itypes[] = { AVR_cbi, AVR_sbic, AVR_sbi, AVR_sbis };
|
||||
insn.itype = itypes[(code >> 8) & 3];
|
||||
opport(insn.Op1, (code >> 3) & 0x1F);
|
||||
opimm(insn, insn.Op2, code & 7);
|
||||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
// 1001 11rd dddd rrrr mul rd, rr
|
||||
insn.itype = AVR_mul;
|
||||
tworegs(insn, code);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
// 1011 0ppd dddd pppp in rd, p
|
||||
// 1011 1ppr rrrr pppp out p, rr
|
||||
if ( code & 0x800 )
|
||||
{
|
||||
insn.itype = AVR_out;
|
||||
opport(insn.Op1, ((code & 0x0600) >> 5) | (code & 15));
|
||||
opregd(insn.Op2, code);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = AVR_in;
|
||||
opregd(insn.Op1, code);
|
||||
opport(insn.Op2, ((code & 0x0600) >> 5) | (code & 15));
|
||||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
// 1100 kkkk kkkk kkkk rjmp k
|
||||
// 1101 kkkk kkkk kkkk rcall k
|
||||
{
|
||||
insn.itype = (code & 0x1000) ? AVR_rcall : AVR_rjmp;
|
||||
signed int delta = (code & 0xFFF);
|
||||
if ( delta & 0x800 )
|
||||
delta |= ~0xFFF;
|
||||
opnear(insn.Op1, code_address(insn, delta));
|
||||
}
|
||||
break;
|
||||
|
||||
case 14:
|
||||
// 1110 1111 dddd 1111 ser rd (16<=d<=31)
|
||||
// 1110 kkkk dddd kkkk ldi rd, k
|
||||
{
|
||||
insn.itype = AVR_ldi;
|
||||
opreg(insn.Op1, ((code >> 4) & 15) + 16);
|
||||
int x = ((code >> 4) & 0xF0) | (code & 0x0F);
|
||||
if ( x == 0xFF && !exists_fixup(insn.ea) )
|
||||
{
|
||||
insn.itype = AVR_ser;
|
||||
break;
|
||||
}
|
||||
opimm(insn, insn.Op2, x);
|
||||
}
|
||||
break;
|
||||
|
||||
case 15:
|
||||
switch ( (code >> 9) & 7 )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// 1111 00kk kkkk k000 brcs/brlo k
|
||||
// 1111 00kk kkkk k001 breq k
|
||||
// 1111 00kk kkkk k010 brmi k
|
||||
// 1111 00kk kkkk k011 brvs k
|
||||
// 1111 00kk kkkk k100 brlt k
|
||||
// 1111 00kk kkkk k101 brhs k
|
||||
// 1111 00kk kkkk k110 brts k
|
||||
// 1111 00kk kkkk k111 brie k
|
||||
// 1111 00kk kkkk ksss brbs s, k
|
||||
// 1111 01kk kkkk k000 brcc/brsh k
|
||||
// 1111 01kk kkkk k001 brne k
|
||||
// 1111 01kk kkkk k010 brpl k
|
||||
// 1111 01kk kkkk k011 brvc k
|
||||
// 1111 01kk kkkk k100 brge k
|
||||
// 1111 01kk kkkk k101 brhc k
|
||||
// 1111 01kk kkkk k110 brtc k
|
||||
// 1111 01kk kkkk k111 brid k
|
||||
// 1111 01kk kkkk ksss brbc s, k
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_brcs, AVR_breq, AVR_brmi, AVR_brvs,
|
||||
AVR_brlt, AVR_brhs, AVR_brts, AVR_brie,
|
||||
AVR_brcc, AVR_brne, AVR_brpl, AVR_brvc,
|
||||
AVR_brge, AVR_brhc, AVR_brtc, AVR_brid,
|
||||
};
|
||||
insn.itype = itypes[((code >> 7) & 8) | (code & 7)];
|
||||
signed int delta = (code >> 3) & 0x7F;
|
||||
if ( delta & 0x40 )
|
||||
delta |= ~0x7F;
|
||||
opnear(insn.Op1, code_address(insn, delta));
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// 1111 100d dddd 0bbb bld rd, b
|
||||
if ( code & 8 )
|
||||
return 0;
|
||||
insn.itype = AVR_bld;
|
||||
goto REGBIT;
|
||||
case 5:
|
||||
// 1111 101d dddd Xbbb bst rd, b
|
||||
insn.itype = AVR_bst;
|
||||
goto REGBIT;
|
||||
case 6:
|
||||
// 1111 110r rrrr xbbb sbrc rr, b
|
||||
insn.itype = AVR_sbrc;
|
||||
goto REGBIT;
|
||||
case 7:
|
||||
insn.itype = AVR_sbrs;
|
||||
// 1111 111r rrrr xbbb sbrs rr, b
|
||||
REGBIT:
|
||||
opregd(insn.Op1, code);
|
||||
opimm(insn, insn.Op2, code & 7);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( insn.itype == AVR_null )
|
||||
return 0;
|
||||
return insn.size;
|
||||
}
|
||||
17813
idasdk76/module/avr/avr.cfg
Normal file
17813
idasdk76/module/avr/avr.cfg
Normal file
File diff suppressed because it is too large
Load Diff
136
idasdk76/module/avr/avr.hpp
Normal file
136
idasdk76/module/avr/avr.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AVR_HPP
|
||||
#define _AVR_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <fixup.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
#include "../../ldr/elf/elfr_avr.h"
|
||||
extern int data_id;
|
||||
|
||||
#define PROCMOD_NAME avr
|
||||
#define PROCMOD_NODE_NAME AVR_INFO_NODENAME
|
||||
|
||||
//---------------------------------
|
||||
// Operand types:
|
||||
|
||||
enum phrase_t ENUM_SIZE(uint16)
|
||||
{
|
||||
PH_X, // X
|
||||
PH_XPLUS, // X+
|
||||
PH_MINUSX, // -X
|
||||
PH_Y, // Y
|
||||
PH_YPLUS, // Y+
|
||||
PH_MINUSY, // -Y
|
||||
PH_Z, // Z
|
||||
PH_ZPLUS, // Z+
|
||||
PH_MINUSZ, // -Z
|
||||
};
|
||||
|
||||
|
||||
#define reg_pair specflag1 // o_reg: operand is 16bit a register pair (even register is in op.reg)
|
||||
#define o_port o_idpspec0 // port number in x.addr
|
||||
|
||||
//------------------------------------------------------------------
|
||||
enum RegNo
|
||||
{
|
||||
R0, R1, R2, R3, R4, R5, R6, R7,
|
||||
R8, R9, R10, R11, R12, R13, R14, R15,
|
||||
R16, R17, R18, R19, R20, R21, R22, R23,
|
||||
R24, R25, R26, R27, R28, R29, R30, R31,
|
||||
rVcs, rVds, // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void idaapi avr_segend(outctx_t &ctx, segment_t *seg);
|
||||
void idaapi avr_assumes(outctx_t &ctx); // function to produce assume directives
|
||||
|
||||
int idaapi is_align_insn(ea_t ea);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct avr_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct avr_t ±
|
||||
avr_iohandler_t(avr_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line) override;
|
||||
virtual bool entry_processing(ea_t &, const char * /*word*/, const char * /*cmt*/) override;
|
||||
virtual bool check_ioresp() const override;
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(idb_listener_t, struct avr_t);
|
||||
|
||||
struct avr_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
avr_iohandler_t ioh = avr_iohandler_t(*this, helper);
|
||||
idb_listener_t idb_listener = idb_listener_t(*this);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// not tested
|
||||
fixup_handler_t cfh_avr16 =
|
||||
{
|
||||
sizeof(fixup_handler_t),
|
||||
"AVR16", // Format name, must be unique
|
||||
0, // props
|
||||
2, 16, 0, 0, // size, width, shift
|
||||
REFINFO_CUSTOM, // reftype
|
||||
nullptr, // apply, will be inited in processor_t::ev_init
|
||||
NULL, // get_value
|
||||
NULL, // patch_value
|
||||
};
|
||||
fixup_type_t cfh_avr16_id = 0;
|
||||
int ref_avr16_id = 0;
|
||||
|
||||
int subarch = 0;
|
||||
|
||||
// memory configuration
|
||||
ea_t ram = BADADDR;
|
||||
uint32 ramsize = 0;
|
||||
uint32 romsize = 0;
|
||||
uint32 eepromsize = 0;
|
||||
|
||||
bool imageFile = false;
|
||||
bool nonBinary = false;
|
||||
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
const ioport_t *find_port(ea_t address);
|
||||
const char *find_bit(ea_t address, size_t bit);
|
||||
void setup_avr_device(int resp_info);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void *value,
|
||||
bool idb_loaded);
|
||||
bool set_param_by_arch(void);
|
||||
bool is_possible_subarch(int addr) const;
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool isAlt, bool isload);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void avr_header(outctx_t &ctx);
|
||||
|
||||
inline void opimm(const insn_t &insn, op_t &x, int value) const;
|
||||
inline uint32 code_address(const insn_t &insn, signed int delta) const;
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void avr_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void avr_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
#endif // _AVR_HPP
|
||||
170
idasdk76/module/avr/emu.cpp
Normal file
170
idasdk76/module/avr/emu.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include "../../ldr/elf/elfr_avr.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void set_immd_bit(const insn_t &insn, int n)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(get_flags(insn.ea), n) )
|
||||
return;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case AVR_andi:
|
||||
case AVR_ori:
|
||||
op_num(insn.ea, n);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void avr_t::handle_operand(const insn_t &insn, const op_t &x, bool isforced, bool isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
case o_phrase:
|
||||
break;
|
||||
case o_imm:
|
||||
if ( !isload )
|
||||
goto WRONG_CALL;
|
||||
set_immd_bit(insn, x.n);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, OOF_SIGNED);
|
||||
break;
|
||||
case o_displ:
|
||||
set_immd_bit(insn, x.n);
|
||||
if ( !isforced && op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
{
|
||||
int outf = OOF_ADDR|OOFS_NEEDSIGN|OOFW_32;
|
||||
ea_t ea = insn.add_off_drefs(x, isload ? dr_R : dr_W, outf);
|
||||
if ( ea != BADADDR )
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_near:
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
}
|
||||
break;
|
||||
case o_port:
|
||||
if ( ram != BADADDR )
|
||||
{
|
||||
ea_t ea = ram + x.addr;
|
||||
if ( subarch < E_AVR_MACH_TINY )
|
||||
ea += 0x20; // skip 32 mapped GPRs for legacy archs
|
||||
if ( x.type == o_port )
|
||||
{ // verify that the calculated address corresponds to the register name
|
||||
const ioport_t *port = find_port(x.addr);
|
||||
if ( port == NULL || port->name.empty() )
|
||||
break;
|
||||
ea_t rev = get_name_ea(BADADDR, port->name.c_str());
|
||||
if ( rev != ea )
|
||||
break;
|
||||
}
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
}
|
||||
break;
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = map_data_ea(insn, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WRONG_CALL:
|
||||
if ( insn.itype != AVR_lpm && insn.itype != AVR_elpm )
|
||||
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool may_be_skipped(const insn_t &insn)
|
||||
{
|
||||
ea_t ea = insn.ea - 1;
|
||||
if ( is_code(get_flags(ea)) )
|
||||
{
|
||||
int code = get_wide_byte(ea);
|
||||
switch ( code & 0xFC00 )
|
||||
{
|
||||
// 0001 00rd dddd rrrr cpse rd, rr 4 Compare, Skip if Equal
|
||||
case 0x1000:
|
||||
// 1111 110r rrrr xbbb sbrc rr, b Skip if Bit in I/O Register Cleared
|
||||
// 1111 111r rrrr xbbb sbrs rr, b Skip if Bit in I/O Register Set
|
||||
case 0xFC00:
|
||||
return true;
|
||||
// 1001 1001 pppp pbbb sbic p, b Skip if Bit in Register Cleared
|
||||
// 1001 1011 pppp pbbb sbis p, b Skip if Bit in Register Set
|
||||
case 0x9800:
|
||||
return (code & 0x0100) != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int avr_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
flow = (Feature & CF_STOP) == 0;
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, flag1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, flag2, true);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, flag3, true);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, flag1, false);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, flag2, false);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, flag3, false);
|
||||
|
||||
//
|
||||
// Determine if the next instruction should be executed
|
||||
//
|
||||
if ( !flow )
|
||||
flow = may_be_skipped(insn);
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
flow = false;
|
||||
if ( flow )
|
||||
add_cref(insn.ea,insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, ea);
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case AVR_mov:
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case AVR_nop:
|
||||
break;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
150
idasdk76/module/avr/ins.cpp
Normal file
150
idasdk76/module/avr/ins.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
// ARITHMETIC AND LOGIC INSTRUCTIONS
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // Add without Carry
|
||||
{ "adc", CF_USE1|CF_USE2|CF_CHG1 }, // Add with Carry
|
||||
{ "adiw", CF_USE1|CF_USE2|CF_CHG1 }, // Add Immediate to Word
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract without Carry
|
||||
{ "subi", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Immediate
|
||||
{ "sbc", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract with Carry
|
||||
{ "sbci", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Immediate with Carry
|
||||
{ "sbiw", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Immediate from Word
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND
|
||||
{ "andi", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND with Immediate
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR
|
||||
{ "ori", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR with Immediate
|
||||
{ "eor", CF_USE1|CF_USE2|CF_CHG1 }, // Exclusive OR
|
||||
{ "com", CF_USE1| CF_CHG1 }, // One's Complement
|
||||
{ "neg", CF_USE1| CF_CHG1 }, // Two's Complement
|
||||
{ "sbr", CF_USE1|CF_USE2|CF_CHG1 }, // Set Bit(s) in Register
|
||||
{ "cbr", CF_USE1|CF_USE2|CF_CHG1 }, // Clear Bit(s) in Register
|
||||
{ "inc", CF_USE1| CF_CHG1 }, // Increment
|
||||
{ "dec", CF_USE1| CF_CHG1 }, // Decrement
|
||||
{ "tst", CF_USE1| CF_CHG1 }, // Test for Zero or Minus
|
||||
{ "clr", CF_CHG1 }, // Clear Register
|
||||
{ "ser", CF_CHG1 }, // Set Register
|
||||
{ "cp", CF_USE1|CF_USE2 }, // Compare
|
||||
{ "cpc", CF_USE1|CF_USE2 }, // Compare with Carry
|
||||
{ "cpi", CF_USE1|CF_USE2 }, // Compare with Immediate
|
||||
{ "mul", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply
|
||||
|
||||
// BRANCH INSTRUCTIONS
|
||||
{ "rjmp", CF_USE1|CF_STOP }, // Relative Jump
|
||||
{ "ijmp", CF_STOP|CF_JUMP }, // Indirect Jump to (Z)
|
||||
{ "jmp", CF_USE1|CF_STOP }, // Jump
|
||||
{ "rcall", CF_USE1 |CF_CALL }, // Relative Call Subroutine
|
||||
{ "icall", CF_JUMP|CF_CALL }, // Indirect Call to (Z)
|
||||
{ "call", CF_USE1 |CF_CALL }, // Call Subroutine
|
||||
{ "ret", CF_STOP }, // Subroutine Return
|
||||
{ "reti", CF_STOP }, // Interrupt Return
|
||||
{ "cpse", CF_USE1|CF_USE2 }, // Compare", Skip if Equal
|
||||
{ "sbrc", CF_USE1|CF_USE2 }, // Skip if Bit in Register Cleared
|
||||
{ "sbrs", CF_USE1|CF_USE2 }, // Skip if Bit in Register Set
|
||||
{ "sbic", CF_USE1|CF_USE2 }, // Skip if Bit in I/O Register Cleared
|
||||
{ "sbis", CF_USE1|CF_USE2 }, // Skip if Bit in I/O Register Set
|
||||
{ "brbs", CF_USE1|CF_USE2 }, // Branch if Status Flag Set
|
||||
{ "brbc", CF_USE1|CF_USE2 }, // Branch if Status Flag Cleared
|
||||
{ "breq", CF_USE1 }, // Branch if Equal
|
||||
{ "brne", CF_USE1 }, // Branch if Not Equal
|
||||
{ "brcs", CF_USE1 }, // Branch if Carry Set
|
||||
{ "brcc", CF_USE1 }, // Branch if Carry Cleared
|
||||
{ "brsh", CF_USE1 }, // Branch if Same or Higher
|
||||
{ "brlo", CF_USE1 }, // Branch if Lower
|
||||
{ "brmi", CF_USE1 }, // Branch if Minus
|
||||
{ "brpl", CF_USE1 }, // Branch if Plus
|
||||
{ "brge", CF_USE1 }, // Branch if Greater or Equal
|
||||
{ "brlt", CF_USE1 }, // Branch if Less Than
|
||||
{ "brhs", CF_USE1 }, // Branch if Half Carry Flag Set
|
||||
{ "brhc", CF_USE1 }, // Branch if Half Carry Flag Cleared
|
||||
{ "brts", CF_USE1 }, // Branch if T Flag Set
|
||||
{ "brtc", CF_USE1 }, // Branch if T Flag Cleared
|
||||
{ "brvs", CF_USE1 }, // Branch if Overflow Flag is Set
|
||||
{ "brvc", CF_USE1 }, // Branch if Overflow Flag is Cleared
|
||||
{ "brie", CF_USE1 }, // Branch if Interrupt Enabled
|
||||
{ "brid", CF_USE1 }, // Branch if Interrupt Disabled
|
||||
|
||||
// DATA TRANSFER INSTRUCTIONS
|
||||
{ "mov", CF_CHG1|CF_USE2 }, // Copy Register
|
||||
{ "ldi", CF_CHG1|CF_USE2 }, // Load Immediate
|
||||
{ "lds", CF_CHG1|CF_USE2 }, // Load Direct
|
||||
{ "ld", CF_CHG1|CF_USE2 }, // Load Indirect
|
||||
{ "ldd", CF_CHG1|CF_USE2 }, // Load Indirect with Displacement
|
||||
{ "sts", CF_CHG1|CF_USE2 }, // Store Direct to SRAM
|
||||
{ "st", CF_USE1|CF_USE2 }, // Store Indirect
|
||||
{ "std", CF_USE1|CF_USE2 }, // Store Indirect with Displacement
|
||||
{ "lpm", CF_USE1|CF_USE2|CF_CHG1 }, // Load Program Memory
|
||||
{ "in", CF_CHG1|CF_USE2 }, // In Port
|
||||
{ "out", CF_USE1|CF_USE2 }, // Out Port
|
||||
{ "push", CF_USE1 }, // Push Register on Stack
|
||||
{ "pop", CF_CHG1 }, // Pop Register from Stack
|
||||
|
||||
// BIT AND BIT-TEST INSTRUCTIONS
|
||||
{ "lsl", CF_USE1|CF_CHG1 }, // Logical Shift Left
|
||||
{ "lsr", CF_USE1|CF_CHG1 }, // Logical Shift Right
|
||||
{ "rol", CF_USE1|CF_CHG1 }, // Rotate Left Through Carry
|
||||
{ "ror", CF_USE1|CF_CHG1 }, // Rotate Right Through Carry
|
||||
{ "asr", CF_USE1|CF_CHG1 }, // Arithmetic Shift Right
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // Swap Nibbles
|
||||
{ "bset", CF_USE1 }, // Flag Set
|
||||
{ "bclr", CF_USE1 }, // Flag Clear
|
||||
{ "sbi", CF_USE1|CF_USE2 }, // Set Bit in I/O Register
|
||||
{ "cbi", CF_USE1|CF_USE2 }, // Clear Bit in I/O Register
|
||||
{ "bst", CF_USE1|CF_USE2 }, // Bit Store from Register to T
|
||||
{ "bld", CF_USE1|CF_USE2 }, // Bit load from T to Register
|
||||
{ "sec", 0 }, // Set Carry
|
||||
{ "clc", 0 }, // Clear Carry
|
||||
{ "sen", 0 }, // Set Negative Flag
|
||||
{ "cln", 0 }, // Clear Negative Flag
|
||||
{ "sez", 0 }, // Set Zero Flag
|
||||
{ "clz", 0 }, // Clear Zero Flag
|
||||
{ "sei", 0 }, // Global Interrupt Enable
|
||||
{ "cli", 0 }, // Global Interrupt Disable
|
||||
{ "ses", 0 }, // Set Signed Test Flag
|
||||
{ "cls", 0 }, // Clear Signed Test Flag
|
||||
{ "sev", 0 }, // Set Two's Complement Overflow
|
||||
{ "clv", 0 }, // Clear Two's Complement Overflow
|
||||
{ "set", 0 }, // Set T in SREG
|
||||
{ "clt", 0 }, // Clear T in SREG
|
||||
{ "seh", 0 }, // Set Half Carry Flag in SREG
|
||||
{ "clh", 0 }, // Clear Half Carry Flag in SREG
|
||||
{ "nop", 0 }, // No Operation
|
||||
{ "sleep", 0 }, // Sleep
|
||||
{ "wdr", 0 }, // Watchdog Reset
|
||||
|
||||
// New MegaAVR instructions
|
||||
{ "elpm", CF_USE2|CF_CHG1 }, // Extended Load Program Memory
|
||||
{ "espm", 0 }, // Extended Store Program Memory
|
||||
{ "fmul", CF_USE1|CF_USE2|CF_CHG1 }, // Fractional Multiply Unsigned
|
||||
{ "fmuls", CF_USE1|CF_USE2|CF_CHG1 }, // Fractional Multiply Signed
|
||||
{ "fmulsu", CF_USE1|CF_USE2|CF_CHG1 }, // Fractional Multiply Signed with Unsigned
|
||||
{ "movw", CF_USE1|CF_USE2|CF_CHG1 }, // Copy Register Word
|
||||
{ "muls", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply Signed
|
||||
{ "mulsu", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply Signed with Unsigned
|
||||
{ "spm", 0 }, // Store Program Memory
|
||||
{ "eicall", 0 }, // Extended Indirect Call to Subroutine
|
||||
{ "eijmp", 0 }, // Extended Indirect Jump
|
||||
|
||||
// New XMega instructions
|
||||
{ "des", CF_USE1 }, // Data Encryption Standard
|
||||
{ "lac", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Load And Clear
|
||||
{ "las", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Load And Set
|
||||
{ "lat", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Load And Toggle
|
||||
{ "xch", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Exchange
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == AVR_last);
|
||||
157
idasdk76/module/avr/ins.hpp
Normal file
157
idasdk76/module/avr/ins.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
|
||||
AVR_null = 0, // Unknown Operation
|
||||
|
||||
// ARITHMETIC AND LOGIC INSTRUCTIONS
|
||||
AVR_add, // Add without Carry
|
||||
AVR_adc, // Add with Carry
|
||||
AVR_adiw, // Add Immediate to Word
|
||||
AVR_sub, // Subtract without Carry
|
||||
AVR_subi, // Subtract Immediate
|
||||
AVR_sbc, // Subtract with Carry
|
||||
AVR_sbci, // Subtract Immediate with Carry
|
||||
AVR_sbiw, // Subtract Immediate from Word
|
||||
AVR_and, // Logical AND
|
||||
AVR_andi, // Logical AND with Immediate
|
||||
AVR_or, // Logical OR
|
||||
AVR_ori, // Logical OR with Immediate
|
||||
AVR_eor, // Exclusive OR
|
||||
AVR_com, // One's Complement
|
||||
AVR_neg, // Two's Complement
|
||||
AVR_sbr, // Set Bit(s) in Register
|
||||
AVR_cbr, // Clear Bit(s) in Register
|
||||
AVR_inc, // Increment
|
||||
AVR_dec, // Decrement
|
||||
AVR_tst, // Test for Zero or Minus
|
||||
AVR_clr, // Clear Register
|
||||
AVR_ser, // Set Register
|
||||
AVR_cp, // Compare
|
||||
AVR_cpc, // Compare with Carry
|
||||
AVR_cpi, // Compare with Immediate
|
||||
AVR_mul, // Multiply
|
||||
|
||||
// BRANCH INSTRUCTIONS
|
||||
AVR_rjmp, // Relative Jump
|
||||
AVR_ijmp, // Indirect Jump to (Z)
|
||||
AVR_jmp, // Jump
|
||||
AVR_rcall, // Relative Call Subroutine
|
||||
AVR_icall, // Indirect Call to (Z)
|
||||
AVR_call, // Call Subroutine
|
||||
AVR_ret, // Subroutine Return
|
||||
AVR_reti, // Interrupt Return
|
||||
AVR_cpse, // Compare, Skip if Equal
|
||||
AVR_sbrc, // Skip if Bit in Register Cleared
|
||||
AVR_sbrs, // Skip if Bit in Register Set
|
||||
AVR_sbic, // Skip if Bit in I/O Register Cleared
|
||||
AVR_sbis, // Skip if Bit in I/O Register Set
|
||||
AVR_brbs, // Branch if Status Flag Set
|
||||
AVR_brbc, // Branch if Status Flag Cleared
|
||||
AVR_breq, // Branch if Equal
|
||||
AVR_brne, // Branch if Not Equal
|
||||
AVR_brcs, // Branch if Carry Set
|
||||
AVR_brcc, // Branch if Carry Cleared
|
||||
AVR_brsh, // Branch if Same or Higher
|
||||
AVR_brlo, // Branch if Lower
|
||||
AVR_brmi, // Branch if Minus
|
||||
AVR_brpl, // Branch if Plus
|
||||
AVR_brge, // Branch if Greater or Equal
|
||||
AVR_brlt, // Branch if Less Than
|
||||
AVR_brhs, // Branch if Half Carry Flag Set
|
||||
AVR_brhc, // Branch if Half Carry Flag Cleared
|
||||
AVR_brts, // Branch if T Flag Set
|
||||
AVR_brtc, // Branch if T Flag Cleared
|
||||
AVR_brvs, // Branch if Overflow Flag is Set
|
||||
AVR_brvc, // Branch if Overflow Flag is Cleared
|
||||
AVR_brie, // Branch if Interrupt Enabled
|
||||
AVR_brid, // Branch if Interrupt Disabled
|
||||
|
||||
// DATA TRANSFER INSTRUCTIONS
|
||||
AVR_mov, // Copy Register
|
||||
AVR_ldi, // Load Immediate
|
||||
AVR_lds, // Load Direct
|
||||
AVR_ld, // Load Indirect
|
||||
AVR_ldd, // Load Indirect with Displacement
|
||||
AVR_sts, // Store Direct to SRAM
|
||||
AVR_st, // Store Indirect
|
||||
AVR_std, // Store Indirect with Displacement
|
||||
AVR_lpm, // Load Program Memory
|
||||
AVR_in, // In Port
|
||||
AVR_out, // Out Port
|
||||
AVR_push, // Push Register on Stack
|
||||
AVR_pop, // Pop Register from Stack
|
||||
|
||||
// BIT AND BIT-TEST INSTRUCTIONS
|
||||
AVR_lsl, // Logical Shift Left
|
||||
AVR_lsr, // Logical Shift Right
|
||||
AVR_rol, // Rotate Left Through Carry
|
||||
AVR_ror, // Rotate Right Through Carry
|
||||
AVR_asr, // Arithmetic Shift Right
|
||||
AVR_swap, // Swap Nibbles
|
||||
AVR_bset, // Flag Set
|
||||
AVR_bclr, // Flag Clear
|
||||
AVR_sbi, // Set Bit in I/O Register
|
||||
AVR_cbi, // Clear Bit in I/O Register
|
||||
AVR_bst, // Bit Store from Register to T
|
||||
AVR_bld, // Bit load from T to Register
|
||||
AVR_sec, // Set Carry
|
||||
AVR_clc, // Clear Carry
|
||||
AVR_sen, // Set Negative Flag
|
||||
AVR_cln, // Clear Negative Flag
|
||||
AVR_sez, // Set Zero Flag
|
||||
AVR_clz, // Clear Zero Flag
|
||||
AVR_sei, // Global Interrupt Enable
|
||||
AVR_cli, // Global Interrupt Disable
|
||||
AVR_ses, // Set Signed Test Flag
|
||||
AVR_cls, // Clear Signed Test Flag
|
||||
AVR_sev, // Set Two's Complement Overflow
|
||||
AVR_clv, // Clear Two's Complement Overflow
|
||||
AVR_set, // Set T in SREG
|
||||
AVR_clt, // Clear T in SREG
|
||||
AVR_seh, // Set Half Carry Flag in SREG
|
||||
AVR_clh, // Clear Half Carry Flag in SREG
|
||||
AVR_nop, // No Operation
|
||||
AVR_sleep, // Sleep
|
||||
AVR_wdr, // Watchdog Reset
|
||||
|
||||
// New MegaAVR instructions
|
||||
|
||||
AVR_elpm, // Extended Load Program Memory
|
||||
AVR_espm, // Extended Store Program Memory
|
||||
AVR_fmul, // Fractional Multiply Unsigned
|
||||
AVR_fmuls, // Fractional Multiply Signed
|
||||
AVR_fmulsu, // Fractional Multiply Signed with Unsigned
|
||||
AVR_movw, // Copy Register Word
|
||||
AVR_muls, // Multiply Signed
|
||||
AVR_mulsu, // Multiply Signed with Unsigned
|
||||
AVR_spm, // Store Program Memory
|
||||
AVR_eicall, // Extended Indirect Call to Subroutine
|
||||
AVR_eijmp, // Extended Indirect Jump
|
||||
|
||||
// New XMega instructions
|
||||
|
||||
AVR_des, // Data Encryption Standard
|
||||
AVR_lac, // Load And Clear
|
||||
AVR_las, // Load And Set
|
||||
AVR_lat, // Load And Toggle
|
||||
AVR_xch, // Exchange
|
||||
|
||||
AVR_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
63
idasdk76/module/avr/makefile
Normal file
63
idasdk76/module/avr/makefile
Normal file
@@ -0,0 +1,63 @@
|
||||
PROC=avr
|
||||
CONFIGS=avr.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)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
ana.cpp avr.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)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
avr.hpp emu.cpp ins.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
avr.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)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
avr.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)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(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 \
|
||||
../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp avr.hpp ins.hpp \
|
||||
notify_codes.hpp reg.cpp
|
||||
34
idasdk76/module/avr/notify_codes.hpp
Normal file
34
idasdk76/module/avr/notify_codes.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AVR_NOTIFY_CODES_HPP
|
||||
#define __AVR_NOTIFY_CODES_HPP
|
||||
|
||||
#include <idp.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// The following events are supported by the AVR module in the ph.notify() function
|
||||
namespace avr_module_t
|
||||
{
|
||||
enum event_codes_t
|
||||
{
|
||||
ev_set_machine_type = processor_t::ev_loader,
|
||||
// elf-loader 'set machine type' and file type
|
||||
};
|
||||
|
||||
inline processor_t::event_t idp_ev(event_codes_t ev)
|
||||
{
|
||||
return processor_t::event_t(ev);
|
||||
}
|
||||
|
||||
inline void set_machine_type(int subarch, bool image_file)
|
||||
{
|
||||
processor_t::notify(idp_ev(ev_set_machine_type), subarch, image_file);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __AVR_NOTIFY_CODES_HPP
|
||||
257
idasdk76/module/avr/out.cpp
Normal file
257
idasdk76/module/avr/out.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include "../../ldr/elf/elfr_avr.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_avr_t : public outctx_t
|
||||
{
|
||||
void out_regop(const op_t &x);
|
||||
out_avr_t(void) = delete; // not used
|
||||
public:
|
||||
void out_phrase(int phn);
|
||||
void out_bad_address(ea_t addr);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_avr_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_avr_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_avr_t::out_phrase(int phn)
|
||||
{
|
||||
switch ( phn )
|
||||
{
|
||||
case PH_XPLUS: // X+
|
||||
out_register("X");
|
||||
out_symbol('+');
|
||||
break;
|
||||
case PH_MINUSX: // -X
|
||||
out_symbol('-');
|
||||
case PH_X: // X
|
||||
out_register("X");
|
||||
break;
|
||||
case PH_YPLUS: // Y+
|
||||
out_register("Y");
|
||||
out_symbol('+');
|
||||
break;
|
||||
case PH_MINUSY: // -Y
|
||||
out_symbol('-');
|
||||
case PH_Y: // Y
|
||||
out_register("Y");
|
||||
break;
|
||||
case PH_ZPLUS: // Z+
|
||||
out_register("Z");
|
||||
out_symbol('+');
|
||||
break;
|
||||
case PH_MINUSZ: // -Z
|
||||
out_symbol('-');
|
||||
case PH_Z: // Z
|
||||
out_register("Z");
|
||||
break;
|
||||
default:
|
||||
error("%a: bad phrase number", insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_avr_t::out_bad_address(ea_t addr)
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(addr, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
|
||||
void out_avr_t::out_regop(const op_t &x)
|
||||
{
|
||||
avr_t &pm = *static_cast<avr_t *>(procmod);
|
||||
qstring name;
|
||||
// for legacy architectures, try to get SRAM name if available
|
||||
if ( x.reg_pair
|
||||
|| pm.ram == BADADDR || pm.subarch >= E_AVR_MACH_TINY
|
||||
|| get_visible_name(&name, pm.ram+x.reg) <= 0 )
|
||||
{
|
||||
// no name or reg pair: use standard reg name
|
||||
name = ph.reg_names[x.reg];
|
||||
if ( x.reg_pair )
|
||||
{
|
||||
switch ( x.reg )
|
||||
{
|
||||
case R26: name = "X"; break;
|
||||
case R28: name = "Y"; break;
|
||||
case R30: name = "Z"; break;
|
||||
default:
|
||||
// r1:r2
|
||||
out_register(name.begin());
|
||||
out_symbol(':');
|
||||
name = ph.reg_names[x.reg+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out_register(name.begin());
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
bool out_avr_t::out_operand(const op_t &x)
|
||||
{
|
||||
avr_t &pm = *static_cast<avr_t *>(procmod);
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_reg:
|
||||
out_regop(x);
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
{
|
||||
if ( insn.itype == AVR_cbi
|
||||
|| insn.itype == AVR_sbic
|
||||
|| insn.itype == AVR_sbi
|
||||
|| insn.itype == AVR_sbis )
|
||||
{
|
||||
const char *bit = pm.find_bit(insn.Op1.addr, (size_t)x.value);
|
||||
if ( bit != NULL && bit[0] != '\0' )
|
||||
{
|
||||
out_line(bit, COLOR_REG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( x.specflag1 && is_off1(F) && !is_invsign(insn.ea, F, 1) )
|
||||
out_symbol('-');
|
||||
int flags = OOFS_IFSIGN|OOFW_8;
|
||||
if ( insn.itype == AVR_subi || insn.itype == AVR_sbci )
|
||||
flags |= OOF_SIGNED;
|
||||
out_value(x, flags);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
if ( !out_name_expr(x, ea, x.addr) )
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = map_data_ea(insn, x);
|
||||
if ( !out_name_expr(x, ea, x.addr) )
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
out_phrase(x.phrase);
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
out_phrase(x.phrase);
|
||||
out_value(x, OOF_ADDR|OOFS_NEEDSIGN|OOFW_32);
|
||||
break;
|
||||
|
||||
case o_port:
|
||||
{
|
||||
const ioport_t *port = pm.find_port(x.addr);
|
||||
if ( port != NULL && !port->name.empty() )
|
||||
out_register(port->name.c_str());
|
||||
else
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_avr_t::out_insn(void)
|
||||
{
|
||||
avr_t &pm = *static_cast<avr_t *>(procmod);
|
||||
// output .org for enties without any labels
|
||||
if ( !has_any_name(F) && pm.helper.altval_ea(insn.ea) )
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
btoa(buf, sizeof(buf), insn.ip);
|
||||
int saved_flags = forbid_annotations();
|
||||
gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
restore_ctxflags(saved_flags);
|
||||
}
|
||||
|
||||
out_mnemonic();
|
||||
|
||||
out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void avr_t::avr_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
if ( is_spec_segm(Sarea->type) )
|
||||
return;
|
||||
qstring sname;
|
||||
qstring sclas;
|
||||
get_visible_segm_name(&sname, Sarea);
|
||||
get_segm_class(&sclas, Sarea);
|
||||
ctx.gen_printf(0,
|
||||
COLSTR("%s", SCOLOR_ASMDIR) " " COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sclas == "CODE"
|
||||
? ".CSEG"
|
||||
: sclas == "DATA"
|
||||
? ".DSEG"
|
||||
: ".ESEG",
|
||||
ash.cmnt,
|
||||
sname.c_str());
|
||||
if ( Sarea->orgbase != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), Sarea->orgbase);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi avr_segend(outctx_t &, segment_t *)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void avr_t::avr_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void avr_t::avr_footer(outctx_t &ctx) const
|
||||
{
|
||||
qstring name = get_visible_name(inf_get_start_ea());
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
|
||||
ash.end, ash.cmnt, name.c_str());
|
||||
}
|
||||
803
idasdk76/module/avr/reg.cpp
Normal file
803
idasdk76/module/avr/reg.cpp
Normal file
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <fixup.hpp>
|
||||
#include "notify_codes.hpp"
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const register_names[] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "XL", "XH", "YL", "YH", "ZL", "ZH",
|
||||
"cs","ds", // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// AVR assembler
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const avr_header[] =
|
||||
{
|
||||
".equ XL, 26",
|
||||
".equ XH, 27",
|
||||
".equ YL, 28",
|
||||
".equ YH, 29",
|
||||
".equ ZL, 30",
|
||||
".equ ZH, 31",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t avrasm =
|
||||
{
|
||||
AS_COLON|AS_N2CHR|ASH_HEXF3|ASD_DECF0|ASB_BINF3|ASO_OCTF0|AS_ONEDUP,
|
||||
0,
|
||||
"AVR Assembler",
|
||||
0,
|
||||
avr_header, // header lines
|
||||
".org", // org
|
||||
".exit", // end
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\"'", // special symbols in char and string constants
|
||||
|
||||
".db", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
".dd", // double words
|
||||
NULL, // no qwords
|
||||
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 %s", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
NULL, // current IP (instruction pointer)
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
NULL, // "extrn" name keyword
|
||||
NULL, // "comm" (communal variable)
|
||||
NULL, // get_type_name
|
||||
NULL, // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"~", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &avrasm, NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char cfgname[] = "avr.cfg";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_iohandler_t::entry_processing(ea_t &ea1, const char * /*word*/, const char * /*cmt*/)
|
||||
{
|
||||
pm.helper.altset_ea(ea1, 1);
|
||||
create_insn(ea1);
|
||||
ea_t ea = get_first_fcref_from(ea1);
|
||||
if ( ea != BADADDR )
|
||||
ea1 = ea;
|
||||
return false; // continue processing
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_iohandler_t::check_ioresp() const
|
||||
{
|
||||
return inf_like_binary() || pm.imageFile;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_t::is_possible_subarch(int addr) const
|
||||
{
|
||||
// old version of gcc-arm don't use 31/51/etc subarches - only 3/5/... :(
|
||||
// maybe make option?
|
||||
return subarch == 0 || subarch == addr || (addr/10 == subarch);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *avr_iohandler_t::iocallback(const ioports_t &_ports, const char *line)
|
||||
{
|
||||
int addr;
|
||||
char word[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
CASSERT(MAXSTR == 1024);
|
||||
if ( qsscanf(line, "%1023[^=] = %d", word, &addr) == 2 )
|
||||
{
|
||||
if ( streq(word, "RAM") )
|
||||
{
|
||||
pm.ramsize = addr;
|
||||
return NULL;
|
||||
}
|
||||
if ( streq(word, "ROM") )
|
||||
{
|
||||
pm.romsize = addr >> 1;
|
||||
return NULL;
|
||||
}
|
||||
if ( streq(word, "EEPROM") )
|
||||
{
|
||||
pm.eepromsize = addr;
|
||||
return NULL;
|
||||
}
|
||||
if ( streq(word, "SUBARCH") )
|
||||
{
|
||||
// set pm.subarch based on SUBARCH in the config file
|
||||
// it is needed to do XMEGA specific things for non-elf files
|
||||
pm.subarch = addr;
|
||||
return pm.is_possible_subarch(addr) ? NULL : IOPORT_SKIP_DEVICE;
|
||||
}
|
||||
}
|
||||
return standard_callback(_ports, line);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct avr_ioport_parser_t : public choose_ioport_parser_t
|
||||
{
|
||||
avr_t ±
|
||||
|
||||
avr_ioport_parser_t(avr_t &_pm) : pm(_pm) {}
|
||||
virtual bool parse(qstring *, const char *line) override
|
||||
{
|
||||
int addr;
|
||||
char word[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
CASSERT(MAXSTR == 1024);
|
||||
bool skip = qsscanf(line, "%1023[^=] = %d", word, &addr) == 2
|
||||
&& strcmp(word, "SUBARCH") == 0
|
||||
&& !pm.is_possible_subarch(addr);
|
||||
return !skip;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const ioport_t *avr_t::find_port(ea_t address)
|
||||
{
|
||||
return find_ioport(ioh.ports, address);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *avr_t::find_bit(ea_t address, size_t bit)
|
||||
{
|
||||
const ioport_bit_t *b = find_ioport_bit(ioh.ports, address, bit);
|
||||
return b ? b->name.c_str() : NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void avr_t::setup_avr_device(int resp_info)
|
||||
{
|
||||
if ( !choose_ioport_device(&ioh.device, cfgname) )
|
||||
return;
|
||||
|
||||
ioh.set_device_name(ioh.device.c_str(), resp_info);
|
||||
if ( get_first_seg() == NULL ) // set processor options before load file
|
||||
return;
|
||||
plan_range(0, BADADDR); // reanalyze program
|
||||
|
||||
// resize the ROM segment
|
||||
{
|
||||
segment_t *s = getseg(node2ea(helper.altval(-1)));
|
||||
if ( s == NULL )
|
||||
s = get_first_seg(); // for the old databases
|
||||
if ( s != NULL ) //-V547 's != 0' is always true
|
||||
{
|
||||
if ( s->size() > romsize )
|
||||
warning("The input file is bigger than the ROM size of the current device");
|
||||
set_segm_end(s->start_ea, s->start_ea+romsize, SEGMOD_KILL);
|
||||
}
|
||||
}
|
||||
// resize the RAM segment
|
||||
{
|
||||
segment_t *s = get_segm_by_name("RAM");
|
||||
if ( s == NULL && ramsize != 0 )
|
||||
{
|
||||
ea_t start = (inf_get_max_ea() + 0xFFFFF) & ~0xFFFFF;
|
||||
add_segm(start>>4, start, start+ramsize, "RAM", "DATA");
|
||||
s = getseg(start);
|
||||
}
|
||||
ram = BADADDR;
|
||||
if ( s != NULL )
|
||||
{
|
||||
int i;
|
||||
// offset added to I/O port address to get RAM address
|
||||
int ram_offset = 0;
|
||||
ram = s->start_ea;
|
||||
set_segm_end(ram, ram+ramsize, SEGMOD_KILL);
|
||||
|
||||
if ( subarch < E_AVR_MACH_TINY )
|
||||
{
|
||||
// legacy devices start with 32 GPRs
|
||||
// 0x20 needs to be added to the port address
|
||||
ram_offset = 0x20;
|
||||
// set register names for aliases in data memory
|
||||
for ( i=0; i < 32; i++ )
|
||||
if ( !has_any_name(get_flags(ram+i)) )
|
||||
set_name(ram+i, register_names[i], SN_NODUMMY);
|
||||
}
|
||||
|
||||
// set I/O port names
|
||||
for ( i=0; i < ioh.ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ioh.ports[i];
|
||||
set_name(ram+p.address+ram_offset, p.name.c_str(), SN_NODUMMY);
|
||||
set_cmt(ram+p.address+ram_offset, p.cmt.c_str(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *avr_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void *value,
|
||||
bool idb_loaded)
|
||||
{
|
||||
if ( keyword == NULL )
|
||||
{
|
||||
setup_avr_device(IORESP_INT);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
else if ( strcmp(keyword, "AVR_MCPU") == 0 )
|
||||
{
|
||||
if ( value_type != IDPOPT_STR )
|
||||
return IDPOPT_BADTYPE;
|
||||
|
||||
ioh.device = (const char *) value;
|
||||
if ( idb_loaded )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_NONE);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
return IDPOPT_BADKEY;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_t::set_param_by_arch(void)
|
||||
{
|
||||
int max_rom, max_ram, max_eeprom;
|
||||
// preset MAXIMUM's of memory size's by mcpu subtype
|
||||
switch ( subarch )
|
||||
{
|
||||
default:
|
||||
subarch = 0;
|
||||
return false; // LOGICAL ERROR?
|
||||
|
||||
// at90s1200, attiny10, attiny11, attiny12, attiny15, attiny28
|
||||
case E_AVR_MACH_AVR1: // ROM<=1k
|
||||
max_rom = 1024;
|
||||
max_ram = 32;
|
||||
max_eeprom = 64;
|
||||
break;
|
||||
// at90s2313, at90s2323, at90s2333, at90s2343, attiny22, attiny26,
|
||||
// at90s4414 /* XXX -> 8515 */, at90s4433, at90s4434 /* XXX -> 8535 */,
|
||||
// at90s8515, at90c8534, at90s8535
|
||||
case E_AVR_MACH_AVR2: // ROM<=8k
|
||||
// attiny13, attiny13a, attiny2313, attiny24, attiny44, attiny84,
|
||||
// attiny25, attiny45, attiny85, attiny261, attiny461, attiny861,
|
||||
// attiny43u, attiny48, attiny88, at86rf401
|
||||
// PASS THRU
|
||||
case E_AVR_MACH_AVR25: // ROM<=8k
|
||||
max_rom = 8*1024;
|
||||
max_ram = 512;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// at43usb355, at76c711
|
||||
case E_AVR_MACH_AVR3: // ROM>=8k<=64k
|
||||
max_rom = 64*1024;
|
||||
max_ram = 1024;
|
||||
max_eeprom = 0;
|
||||
break;
|
||||
// atmega103, at43usb320,
|
||||
case E_AVR_MACH_AVR31: // ROM>=65k&&<=128k, (RAM=65k, EEPROM=4k)
|
||||
max_rom = 128*1024;
|
||||
max_ram = 4*1024;
|
||||
max_eeprom = 4*1024;
|
||||
break;
|
||||
// attiny167, at90usb82, at90usb162
|
||||
case E_AVR_MACH_AVR35: // ROM>=8k&&<=64k,
|
||||
max_rom = 64*1024;
|
||||
max_ram = 512;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// atmega8, atmega48, atmega48p, atmega88, atmega88p, atmega8515,
|
||||
// atmega8535, atmega8hva, at90pwm1, at90pwm2, at90pwm2b, at90pwm3,
|
||||
// at90pwm3b
|
||||
case E_AVR_MACH_AVR4: // ROM<=8k
|
||||
max_rom = 8*1024;
|
||||
max_ram = 1024;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// atmega16, atmega161, atmega162, atmega163, atmega164p, atmega165,
|
||||
// atmega165p, atmega168, atmega168p, atmega169, atmega169p, atmega32,
|
||||
// atmega323, atmega324p, atmega325, atmega325p, atmega3250, atmega3250p,
|
||||
// atmega328p, atmega329, atmega329p, atmega3290, atmega3290p, atmega406,
|
||||
// atmega64, atmega640, atmega644, atmega644p, atmega645, atmega649,
|
||||
// atmega6450, atmega6490, atmega16hva, at90can32, at90can64, at90pwm216,
|
||||
// at90pwm316, atmega32c1, atmega32m1, atmega32u4, at90usb646, at90usb647,
|
||||
// at94k
|
||||
case E_AVR_MACH_AVR5: // ROM>=8k&&<=64k
|
||||
max_rom = 64*1024;
|
||||
max_ram = 4*1024;
|
||||
max_eeprom = 2*1024;
|
||||
break;
|
||||
// atmega128, atmega1280, atmega1281, atmega1284p,
|
||||
// at90can128, at90usb1286, at90usb1287
|
||||
case E_AVR_MACH_AVR51: // ROM=128k
|
||||
max_rom = 128*1024;
|
||||
max_ram = 16*1024;
|
||||
max_eeprom = 4*1024;
|
||||
break;
|
||||
// atmega2560, atmega2561
|
||||
case E_AVR_MACH_AVR6: // ROM=256k (3-byte pc -- is supported?)
|
||||
max_rom = 256*1024;
|
||||
max_ram = 8*1024;
|
||||
max_eeprom = 4*1024;
|
||||
break;
|
||||
case E_AVR_MACH_XMEGA1: // ROM < 8K, ram=?
|
||||
max_rom = 8*1024;
|
||||
max_ram = 1024;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// ATxmega16A4, ATxmega16D4, ATxmega32D4
|
||||
case E_AVR_MACH_XMEGA2: // 8K < FLASH <= 64K, RAM <= 64K
|
||||
max_rom = 64*1024;
|
||||
max_ram = 64*1024;
|
||||
max_eeprom = 1024;
|
||||
break;
|
||||
// ATxmega32A4
|
||||
case E_AVR_MACH_XMEGA3: // 8K < FLASH <= 64K, RAM > 64K
|
||||
max_rom = 64*1024;
|
||||
max_ram = 128*1024; // ?
|
||||
max_eeprom = 1024;
|
||||
break;
|
||||
// ATxmega64A3, ATxmega64D3
|
||||
case E_AVR_MACH_XMEGA4: // 64K < FLASH <= 128K, RAM <= 64K
|
||||
max_rom = 128*1024;
|
||||
max_ram = 64*1024;
|
||||
max_eeprom = 2048;
|
||||
break;
|
||||
// ATxmega64A1
|
||||
case E_AVR_MACH_XMEGA5: // 64K < FLASH <= 128K, RAM > 64K
|
||||
max_rom = 128*1024;
|
||||
max_ram = 128*1024;
|
||||
max_eeprom = 2048;
|
||||
break;
|
||||
// ATxmega128A3, ATxmega128D3, ATxmega192A3, ATxmega192D3,
|
||||
// ATxmega256A3B, ATxmega256A3, ATxmega256D3
|
||||
case E_AVR_MACH_XMEGA6: // 128K < FLASH <= 256K, RAM <= 64K
|
||||
max_rom = 256*1024;
|
||||
max_ram = 64*1024;
|
||||
max_eeprom = 4096;
|
||||
break;
|
||||
// ATxmega128A1
|
||||
case E_AVR_MACH_XMEGA7: // 128K < FLASH <= 256K, RAM > 64K
|
||||
max_rom = 256*1024;
|
||||
max_ram = 128*1024;
|
||||
max_eeprom = 4096;
|
||||
break;
|
||||
}
|
||||
avr_ioport_parser_t parser(*this);
|
||||
if ( !choose_ioport_device2(&ioh.device, cfgname, &parser) )
|
||||
{
|
||||
ioh.device.sprnt("avr%d", subarch);
|
||||
ioh.device[sizeof("avrX")-1] = '\0';
|
||||
romsize = max_rom >> 1;
|
||||
ramsize = max_ram;
|
||||
eepromsize = max_eeprom;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_INT);
|
||||
plan_range(0, BADADDR); // reanalyze program
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static inline ea_t get16bit(ea_t ea)
|
||||
{
|
||||
if ( segtype(ea) == SEG_CODE )
|
||||
return get_wide_byte(ea);
|
||||
|
||||
return get_word(ea);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case idb_event::segm_added:
|
||||
{
|
||||
segment_t *s = va_arg(va, segment_t *);
|
||||
qstring sclass;
|
||||
if ( get_segm_class(&sclass, s) > 0 && sclass == "DATA" )
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
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);
|
||||
|
||||
nodeidx_t ndx1 = ea2node(from);
|
||||
nodeidx_t ndx2 = ea2node(to);
|
||||
pm.helper.altshift(ndx1, ndx2, size); // move address information
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool idaapi avr16_apply(
|
||||
const fixup_handler_t *fh,
|
||||
ea_t item_ea,
|
||||
ea_t fixup_ea,
|
||||
int opnum,
|
||||
bool /*is_macro*/,
|
||||
const fixup_data_t &fd)
|
||||
{
|
||||
avr_t &pm = *GET_MODULE_DATA(avr_t);
|
||||
if ( !pm.nonBinary
|
||||
|| fd.has_base()
|
||||
|| fd.is_unused()
|
||||
|| fd.displacement != 0 )
|
||||
{
|
||||
msg("%a: Unexpected or incorrect CUSTOM_FIXUP\n", fixup_ea);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_unknown(get_flags(item_ea)) )
|
||||
create_16bit_data(item_ea, 2);
|
||||
|
||||
refinfo_t ri;
|
||||
ri.flags = fh->reftype;
|
||||
ri.base = fd.get_base();
|
||||
ri.target = ri.base + fd.off;
|
||||
ri.tdelta = fd.displacement;
|
||||
op_offset_ex(item_ea, opnum, &ri);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{818} could be declared const
|
||||
static int idaapi avr16_gen_expr(
|
||||
qstring * /*buf*/,
|
||||
qstring * /*format*/,
|
||||
ea_t ea,
|
||||
int numop,
|
||||
const refinfo_t &ri,
|
||||
ea_t /*from*/,
|
||||
adiff_t *opval,
|
||||
ea_t * /*target*/,
|
||||
ea_t * /*fullvalue*/,
|
||||
int /*getn_flags*/)
|
||||
{
|
||||
avr_t &pm = *GET_MODULE_DATA(avr_t);
|
||||
if ( !pm.nonBinary
|
||||
|| numop != 0
|
||||
|| ri.type() == (pm.ref_avr16_id | REFINFO_CUSTOM)
|
||||
|| ri.tdelta != 0
|
||||
|| ri.target == BADADDR
|
||||
|| *opval != get16bit(ea) )
|
||||
{
|
||||
msg("%a: Unexpected or incorrect CUSTOM offset\n", ea);
|
||||
return 0;
|
||||
}
|
||||
return 3; // process as a regular fixup
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const custom_refinfo_handler_t ref_avr16 =
|
||||
{
|
||||
sizeof(custom_refinfo_handler_t),
|
||||
"AVR16",
|
||||
"AVR 16-bit offset",
|
||||
0, // properties (currently 0)
|
||||
avr16_gen_expr, // gen_expr
|
||||
NULL, // calc_reference_data
|
||||
NULL, // get_format
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(avr_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void avr_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
segment_t *s = get_segm_by_name("RAM");
|
||||
if ( s != NULL )
|
||||
ram = s->start_ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi avr_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
cfh_avr16.apply = avr16_apply;
|
||||
cfh_avr16_id = register_custom_fixup(&cfh_avr16);
|
||||
ref_avr16_id = register_custom_refinfo(&ref_avr16);
|
||||
cfh_avr16.reftype = REFINFO_CUSTOM | ref_avr16_id;
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
cfh_avr16.reftype = REFINFO_CUSTOM;
|
||||
unregister_custom_refinfo(ref_avr16_id);
|
||||
unregister_custom_fixup(cfh_avr16_id);
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case avr_module_t::ev_set_machine_type: // elf-loader 'set machine type' and file type
|
||||
subarch = va_arg(va, int);
|
||||
imageFile = va_argi(va, bool);
|
||||
nonBinary = true;
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile: // new file loaded
|
||||
// remember the ROM segment
|
||||
{
|
||||
segment_t *s = get_first_seg();
|
||||
if ( s != NULL )
|
||||
{
|
||||
if ( subarch == 0 )
|
||||
set_segm_name(s, "ROM");
|
||||
helper.altset(-1, ea2node(s->start_ea));
|
||||
}
|
||||
}
|
||||
if ( subarch != 0 && set_param_by_arch() )
|
||||
break;
|
||||
setup_avr_device(/*IORESP_AREA|*/IORESP_INT); // allow the user to select the device
|
||||
if ( subarch != 0 )
|
||||
break;
|
||||
// create additional segments
|
||||
{
|
||||
ea_t start = (inf_get_max_ea() + 0xFFFFF) & ~0xFFFFF;
|
||||
if ( eepromsize != 0 )
|
||||
{
|
||||
char *file = ask_file(false, "*.bin", "Please enter the binary EEPROM image file");
|
||||
if ( file != NULL )
|
||||
{
|
||||
add_segm(start>>4, start, start+eepromsize, "EEPROM", "DATA");
|
||||
linput_t *li = open_linput(file, false);
|
||||
if ( li != NULL )
|
||||
{
|
||||
uint64 size = qlsize(li);
|
||||
if ( size > eepromsize )
|
||||
size = eepromsize;
|
||||
file2base(li, 0, start, start+size, FILEREG_NOTPATCHABLE);
|
||||
close_linput(li);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile: // old file loaded
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc: // new processor type
|
||||
break;
|
||||
|
||||
case processor_t::ev_newasm: // new assembler type
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_label: // The kernel is going to generate an instruction
|
||||
// label line or a function header
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
if ( helper.altval_ea(ctx->insn_ea) ) // if entry point
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), ctx->insn_ea);
|
||||
ctx->gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
avr_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
avr_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 *);
|
||||
avr_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
avr_segend(*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_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 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 1001 0101 0xx0 1000 ret
|
||||
// 1001 0101 0xx1 1000 reti
|
||||
static const uchar retcode_1[] = { 0x08, 0x95 }; // ret
|
||||
static const uchar retcode_2[] = { 0x18, 0x95 }; // reti
|
||||
static const uchar retcode_3[] = { 0x28, 0x95 }; // ret
|
||||
static const uchar retcode_4[] = { 0x38, 0x95 }; // reti
|
||||
static const uchar retcode_5[] = { 0x48, 0x95 }; // ret
|
||||
static const uchar retcode_6[] = { 0x58, 0x95 }; // reti
|
||||
static const uchar retcode_7[] = { 0x68, 0x95 }; // ret
|
||||
static const uchar retcode_8[] = { 0x78, 0x95 }; // reti
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ sizeof(retcode_3), retcode_3 },
|
||||
{ sizeof(retcode_4), retcode_4 },
|
||||
{ sizeof(retcode_5), retcode_5 },
|
||||
{ sizeof(retcode_6), retcode_6 },
|
||||
{ sizeof(retcode_7), retcode_7 },
|
||||
{ sizeof(retcode_8), retcode_8 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "Atmel AVR series:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"AVR",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Atmel AVR",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_AVR, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_RNAMESOK,
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
16, // 16 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
register_names, // Register names
|
||||
qnumber(register_names), // Number of registers
|
||||
|
||||
rVcs, // first
|
||||
rVds, // last
|
||||
0, // size of a segment register
|
||||
rVcs, rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
AVR_null,
|
||||
AVR_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
AVR_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
442
idasdk76/module/c39/ana.cpp
Normal file
442
idasdk76/module/c39/ana.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "c39.hpp"
|
||||
|
||||
/*
|
||||
Operand types:
|
||||
1) none
|
||||
2) Register a, x, y
|
||||
3) address $xx address may be 8 or 16 bits
|
||||
4) indirect address ($xx) address of the cell with the target address
|
||||
5) immediate #$xx constant
|
||||
6) label Label target label of the jump
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// current byte(s) is immediate data, 1 byte
|
||||
static void SetImmData(op_t &op, uchar code)
|
||||
{
|
||||
op.type = o_imm;
|
||||
// always in the second byte
|
||||
op.offb = 1;
|
||||
// element size
|
||||
op.dtype = dt_byte;
|
||||
// value
|
||||
op.addr = op.value = code;
|
||||
// it can't be an offset!
|
||||
op.flags |= OF_NUMBER; // only number
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// registres are considered byte-sized
|
||||
static void SetReg(op_t &op, uchar reg_n)
|
||||
{
|
||||
op.type = o_reg; // only register
|
||||
op.reg = reg_n; // register number
|
||||
op.dtype = dt_byte; // size is always 8 bits
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// memory cell
|
||||
static void SetMemVar(op_t &op, ushort addr)
|
||||
{
|
||||
op.type = o_mem;
|
||||
op.addr = op.value = addr;
|
||||
op.dtype = dt_word;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// memory cell with an address
|
||||
static void SetMemVarI(op_t &op, ushort addr)
|
||||
{
|
||||
op.type = o_mem;
|
||||
op.specflag1 |= URR_IND;
|
||||
op.addr = op.value = addr;
|
||||
op.dtype = dt_word;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// relative branch
|
||||
static void SetRelative(const insn_t &insn, op_t &op, signed char disp)
|
||||
{
|
||||
op.type = o_near;
|
||||
op.dtype = dt_word;
|
||||
op.offb = 1; // in fact, not always...
|
||||
// calculate indirect value
|
||||
op.addr = op.value = insn.ip + insn.size + (int32)disp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// absolute branch
|
||||
static void SetAbs(op_t &op, unsigned short disp)
|
||||
{
|
||||
op.type = o_near;
|
||||
op.dtype = dt_word;
|
||||
op.offb = 1; // in fact, not always...
|
||||
// calculate final value
|
||||
op.addr = op.value = disp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// analyzer
|
||||
int idaapi C39_ana(insn_t *_insn)
|
||||
{
|
||||
static const uchar Dt[] =
|
||||
{
|
||||
C39_brk, C39_ora, C39_mpy, C39_tip, 0, C39_ora, C39_asl, C39_rmb, // 00
|
||||
C39_php, C39_ora, C39_asl, C39_jsb, C39_jpi, C39_ora, C39_asl, C39_bbr, // 08
|
||||
|
||||
C39_bpl, C39_ora, C39_mpa, C39_lab, 0, C39_ora, C39_asl, C39_rmb, // 10
|
||||
C39_clc, C39_ora, C39_neg, C39_jsb, 0, C39_ora, C39_asl, C39_bbr, // 18
|
||||
|
||||
C39_jsr, C39_and, C39_psh, C39_phw, C39_bit, C39_and, C39_rol, C39_rmb, // 20
|
||||
C39_plp, C39_and, C39_rol, C39_jsb, C39_bit, C39_and, C39_rol, C39_bbr, // 28
|
||||
|
||||
C39_bmi, C39_and, C39_pul, C39_plw, 0, C39_and, C39_rol, C39_rmb, // 30
|
||||
C39_sec, C39_and, C39_asr, C39_jsb, 0, C39_and, C39_rol, C39_bbr, // 38
|
||||
|
||||
C39_rti, C39_eor, C39_rnd, 0, 0, C39_eor, C39_lsr, C39_rmb, // 40
|
||||
C39_pha, C39_eor, C39_lsr, C39_jsb, C39_jmp, C39_eor, C39_lsr, C39_bbr, // 48
|
||||
|
||||
C39_bvc, C39_eor, C39_clw, 0, 0, C39_eor, C39_lsr, C39_rmb, // 50
|
||||
C39_cli, C39_eor, C39_phy, C39_jsb, 0, C39_eor, C39_lsr, C39_bbr, // 58
|
||||
|
||||
C39_rts, C39_adc, C39_taw, 0, C39_add, C39_adc, C39_ror, C39_rmb, // 60
|
||||
C39_pla, C39_adc, C39_ror, C39_jsb, C39_jmp, C39_adc, C39_ror, C39_bbr, // 68
|
||||
|
||||
C39_bvs, C39_adc, C39_twa, 0, C39_add, C39_adc, C39_ror, C39_rmb, // 70
|
||||
C39_sei, C39_adc, C39_ply, C39_jsb, C39_jmp, C39_adc, C39_ror, C39_bbr, // 78
|
||||
|
||||
C39_bra, C39_sta, 0, 0, C39_sty, C39_sta, C39_stx, C39_smb, // 80
|
||||
C39_dey, C39_add, C39_txa, C39_nxt, C39_sty, C39_sta, C39_stx, C39_bbs, // 88
|
||||
|
||||
C39_bcc, C39_sta, 0, 0, C39_sty, C39_sta, C39_stx, C39_smb, // 90
|
||||
C39_tya, C39_sta, C39_txs, C39_lii, 0, C39_sta, 0, C39_bbs, // 98
|
||||
|
||||
C39_ldy, C39_lda, C39_ldx, 0, C39_ldy, C39_lda, C39_ldx, C39_smb, // A0
|
||||
C39_tay, C39_lda, C39_tax, C39_lan, C39_ldy, C39_lda, C39_ldx, C39_bbs, // A8
|
||||
|
||||
C39_bcs, C39_lda, C39_sti, 0, C39_ldy, C39_lda, C39_ldx, C39_smb, // B0
|
||||
C39_clv, C39_lda, C39_tsx, C39_ini, C39_ldy, C39_lda, C39_ldx, C39_bbs, // B8
|
||||
|
||||
|
||||
C39_cpy, C39_cmp, C39_rba, 0, C39_cpy, C39_cmp, C39_dec, C39_smb, // C0
|
||||
C39_iny, C39_cmp, C39_dex, C39_phi, C39_cpy, C39_cmp, C39_dec, C39_bbs, // C8
|
||||
|
||||
C39_bne, C39_cmp, C39_sba, 0, C39_exc, C39_cmp, C39_dec, C39_smb, // D0
|
||||
C39_cld, C39_cmp, C39_phx, C39_pli, 0, C39_cmp, C39_dec, C39_bbs, // D8
|
||||
|
||||
C39_cpx, C39_sbc, C39_bar, 0, C39_cpx, C39_sbc, C39_inc, C39_smb, // E0
|
||||
C39_inx, C39_sbc, C39_nop, C39_lai, C39_cpx, C39_sbc, C39_inc, C39_bbs, // E8
|
||||
|
||||
C39_beq, C39_sbc, C39_bas, 0, 0, C39_sbc, C39_inc, C39_smb, // F0
|
||||
C39_sed, C39_sbc, C39_plx, C39_pia, 0, C39_sbc, C39_inc, C39_bbs // F8
|
||||
};
|
||||
|
||||
// get instruction byte
|
||||
insn_t &insn = *_insn;
|
||||
uchar code = insn.get_next_byte();
|
||||
// get instruction code
|
||||
insn.itype = Dt[code];
|
||||
// analyze instruction type
|
||||
switch ( insn.itype )
|
||||
{
|
||||
// unknown instruction
|
||||
case 0:
|
||||
return 0;
|
||||
// smb/rmb
|
||||
case C39_smb:
|
||||
case C39_rmb:
|
||||
SetImmData(insn.Op1, (code>>4) & 7);
|
||||
SetMemVar(insn.Op2, insn.get_next_byte());
|
||||
break;
|
||||
// bbs/bbr
|
||||
case C39_bbs:
|
||||
case C39_bbr:
|
||||
SetImmData(insn.Op1, (code>>4)&7);
|
||||
SetMemVar(insn.Op2, insn.get_next_byte());
|
||||
SetRelative(insn, insn.Op3, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
// bpl/bmi/bvc/bvs/bra/bcc/bcs/bne/beq
|
||||
case C39_beq:
|
||||
case C39_bne:
|
||||
case C39_bcs:
|
||||
case C39_bcc:
|
||||
case C39_bra:
|
||||
case C39_bvs:
|
||||
case C39_bvc:
|
||||
case C39_bmi:
|
||||
case C39_bpl:
|
||||
SetRelative(insn, insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
// jsb
|
||||
case C39_jsb:
|
||||
SetMemVar(insn.Op1,0xFFE0+((code>>4) & 7)*2);
|
||||
break;
|
||||
|
||||
// ora, and, eor, adc, sta, lda, cmp, sbc
|
||||
case C39_sbc:
|
||||
case C39_cmp:
|
||||
case C39_lda:
|
||||
case C39_sta:
|
||||
case C39_adc:
|
||||
case C39_eor:
|
||||
case C39_and:
|
||||
case C39_ora:
|
||||
switch ( code&0x1E )
|
||||
{
|
||||
// 01 - xxx ($b)
|
||||
case 0x00:
|
||||
SetMemVarI(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// 05 - xxx $b
|
||||
case 0x04:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// 09 - xxx #$b
|
||||
case 0x08:
|
||||
SetImmData(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// 0D - xxx $w
|
||||
case 0x0C:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
// 11 - xxx ($b), x
|
||||
case 0x10:
|
||||
SetMemVarI(insn.Op1, insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
// 15 - xxx $b, x
|
||||
case 0x14:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
// 19 - xxx $w, y
|
||||
case 0x18:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
SetReg(insn.Op2,rY);
|
||||
break;
|
||||
// 1d - xxx $w, x
|
||||
case 0x1C:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// asl, rol, lsr, ror, asr
|
||||
case C39_asr: // this one has a single variant (asr a)
|
||||
case C39_ror:
|
||||
case C39_lsr:
|
||||
case C39_rol:
|
||||
case C39_asl:
|
||||
switch ( code & 0x1C )
|
||||
{
|
||||
// 6 - xxx $b
|
||||
case 0x04:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// A - xxx a
|
||||
case 0x08:
|
||||
SetReg(insn.Op1,rA);
|
||||
break;
|
||||
// E - xxx $w
|
||||
case 0x0C:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
// 16 - xxx $b, x
|
||||
case 0x14:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
// 1E - xxx $w, x
|
||||
case 0x1C:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// inc, dec
|
||||
case C39_dec:
|
||||
case C39_inc:
|
||||
switch ( code&0x18 )
|
||||
{
|
||||
// e6 - xxx $b
|
||||
case 0x00:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// ee - xxx $w
|
||||
case 0x08:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
// f6 - xxx $b, x
|
||||
case 0x10:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
// fe - xxx $w, x
|
||||
case 0x18:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// rba/sba $b, $w
|
||||
case C39_rba:
|
||||
case C39_sba:
|
||||
SetImmData(insn.Op1, insn.get_next_byte());
|
||||
SetMemVar(insn.Op2, insn.get_next_word());
|
||||
break;
|
||||
|
||||
// cpy/cpx
|
||||
case C39_cpx:
|
||||
case C39_cpy:
|
||||
switch ( code & 0x1C )
|
||||
{
|
||||
// a0 - xxx #$b
|
||||
case 0x00:
|
||||
SetImmData(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// a4 - xxx $b
|
||||
case 0x04:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
break;
|
||||
// ac - xxx $w
|
||||
case 0x0C:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
// 14 - xxx $b, x
|
||||
case 0x14:
|
||||
SetMemVar(insn.Op1, insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
// 1C - xxx $w, x
|
||||
case 0x1C:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// lab/neg
|
||||
case C39_neg:
|
||||
case C39_lab:
|
||||
SetReg(insn.Op1,rA);
|
||||
break;
|
||||
|
||||
// jpi ($w)
|
||||
case C39_jpi:
|
||||
SetMemVarI(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
|
||||
// jsr $w
|
||||
case C39_jsr:
|
||||
SetAbs(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
|
||||
// bar/bas $w, $b ,$rel
|
||||
case C39_bar:
|
||||
case C39_bas:
|
||||
SetMemVar(insn.Op1, insn.get_next_word());
|
||||
SetImmData(insn.Op2, insn.get_next_byte());
|
||||
SetRelative(insn, insn.Op3, insn.get_next_byte());
|
||||
break;
|
||||
|
||||
// bit
|
||||
case C39_bit:
|
||||
if ( code & 8 )
|
||||
SetMemVar(insn.Op1, insn.get_next_word()); // bit $w
|
||||
else
|
||||
SetMemVar(insn.Op1, insn.get_next_byte()); // bit $b
|
||||
break;
|
||||
|
||||
// jmp
|
||||
case C39_jmp:
|
||||
switch ( code )
|
||||
{
|
||||
case 0x4C:
|
||||
SetAbs(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
case 0x6C:
|
||||
SetMemVarI(insn.Op1, insn.get_next_word());
|
||||
break;
|
||||
case 0x7C:
|
||||
SetMemVarI(insn.Op1, insn.get_next_word());
|
||||
SetReg(insn.Op2, rX);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// sti
|
||||
case C39_sti:
|
||||
SetImmData(insn.Op1,insn.get_next_byte());
|
||||
SetMemVar(insn.Op2,insn.get_next_byte());
|
||||
break;
|
||||
|
||||
// exc
|
||||
case C39_exc:
|
||||
SetMemVar(insn.Op1,insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
|
||||
// add
|
||||
case C39_add:
|
||||
switch ( code )
|
||||
{
|
||||
case 0x64:
|
||||
SetMemVar(insn.Op1,insn.get_next_byte());
|
||||
break;
|
||||
case 0x74:
|
||||
SetMemVar(insn.Op1,insn.get_next_byte());
|
||||
SetReg(insn.Op2,rX);
|
||||
break;
|
||||
case 0x89:
|
||||
SetImmData(insn.Op1,insn.get_next_byte());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// sty
|
||||
case C39_stx:
|
||||
case C39_ldx:
|
||||
case C39_ldy:
|
||||
case C39_sty:
|
||||
switch ( code & 0x1C )
|
||||
{
|
||||
// A0 xxx #$b
|
||||
case 0x00:
|
||||
SetImmData(insn.Op1,insn.get_next_byte());
|
||||
break;
|
||||
// A4 xxx $b
|
||||
case 0x04:
|
||||
SetMemVar(insn.Op1,insn.get_next_byte());
|
||||
break;
|
||||
// AC xxx $w
|
||||
case 0x0C:
|
||||
SetMemVar(insn.Op1,insn.get_next_word());
|
||||
break;
|
||||
// B4 xxx $b, x
|
||||
case 0x14:
|
||||
SetMemVar(insn.Op1,insn.get_next_byte());
|
||||
SetReg(insn.Op2,
|
||||
insn.itype == C39_sty || insn.itype == C39_ldy ? rX : rY);
|
||||
break;
|
||||
// BC xxx $w, x
|
||||
case 0x1C:
|
||||
SetMemVar(insn.Op1,insn.get_next_word());
|
||||
SetReg(insn.Op2,
|
||||
insn.itype == C39_sty || insn.itype == C39_ldy ? rX : rY);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
277
idasdk76/module/c39/c39.cfg
Normal file
277
idasdk76/module/c39/c39.cfg
Normal file
@@ -0,0 +1,277 @@
|
||||
; The format of the input file:
|
||||
; each device definition begins with a line like this:
|
||||
;
|
||||
; .devicename
|
||||
;
|
||||
; after it go the port definitions in this format:
|
||||
;
|
||||
; portname address
|
||||
;
|
||||
; the bit definitions (optional) are represented like this:
|
||||
;
|
||||
; portname.bitname bitnumber
|
||||
;
|
||||
; lines beginning with a space are ignored.
|
||||
; comment lines should be started with ';' character.
|
||||
;
|
||||
; the default device is specified at the start of the file
|
||||
;
|
||||
; .default device_name
|
||||
;
|
||||
; all lines non conforming to the format are passed to the callback function
|
||||
;
|
||||
; Rockwell C39 SPECIFIC LINES
|
||||
;------------------------
|
||||
;
|
||||
; the processor definition may include the memory configuration.
|
||||
; the line format is:
|
||||
|
||||
; area CLASS AREA-NAME START:END
|
||||
;
|
||||
; where CLASS is anything, but please use one of CODE, DATA, BSS
|
||||
; START and END are addresses, the end address is not included
|
||||
|
||||
; Interrupt vectors are declared in the following way:
|
||||
|
||||
; entry NAME ADDRESS COMMENT
|
||||
|
||||
.default C39
|
||||
|
||||
|
||||
.C39
|
||||
|
||||
; MEMORY MAP
|
||||
area DATA SFR 0x0000:0x0040 Special Function Register
|
||||
area DATA IRAMS 0x0040:0x0080 Page 1 Segment Address
|
||||
area DATA IRAM0 0x0080:0x0100 Page 0 Internal RAM
|
||||
area DATA IRAM1 0x0100:0x0200 Page 1 Internal RAM
|
||||
area DATA IRAM2 0x0200:0x0300 Page 2 Internal RAM
|
||||
area DATA IRAM3 0x0300:0x0400 Page 3 Internal RAM
|
||||
area DATA IRAM4 0x0400:0x0480 Page 4 Internal RAM
|
||||
area DATA ICRC 0x0480:0x0500 CRC buffer Area
|
||||
area DATA IRAM5 0x0500:0x0600 Page 5 Internal RAM (UNAVAIL)
|
||||
area DATA IES4 0x0600:0x0800 Part of ES4 RAM
|
||||
|
||||
; Interrupt and reset vector assignments
|
||||
interrupt JSB0_ 0xFFE0 JBS0 Vector
|
||||
interrupt JSB1_ 0xFFE2 JBS1 Vector
|
||||
interrupt JSB2_ 0xFFE4 JBS2 Vector
|
||||
interrupt JSB3_ 0xFFE6 JBS3 Vector
|
||||
interrupt JSB4_ 0xFFE8 JBS4 Vector
|
||||
interrupt JSB5_ 0xFFEA JBS5 Vector
|
||||
interrupt JSB6_ 0xFFEC JBS6 Vector
|
||||
interrupt JSB7_ 0xFFEE JBS7 Vector
|
||||
interrupt INT0_ 0xFFF0 INT0 Vector
|
||||
interrupt TIMERA_ 0xFFF2 TIMER A Vector
|
||||
interrupt INT2_ 0xFFF4 INT2 Vector
|
||||
interrupt TIMERB_ 0xFFF6 TIMER B Vector
|
||||
interrupt INT4_ 0xFFF8 INT4 Vector
|
||||
interrupt NMI_ 0xFFFA NMI Vector
|
||||
interrupt RESET_ 0xFFFC Reset Vector
|
||||
interrupt PWR_INT 0xFFFE Start Vector
|
||||
|
||||
|
||||
; INPUT/OUTPUT
|
||||
P_A 0x00 Port A (bidir)
|
||||
P_B 0x01 Port B (W)
|
||||
P_C 0x02 Port C (Bidir)
|
||||
P_AD 0x03 Port A Direction (R/O)
|
||||
P_DD 0x04 Port D Direction Controll
|
||||
P_BS 0x05 Port B Select (R/W)
|
||||
P_CD 0x06 Port C Direction (W)
|
||||
P_E 0x07 Port E (R/W)
|
||||
P_ED 0x08 Port E Direction/Mask option
|
||||
P_LPR 0x09 Low Power Register
|
||||
P_EI 0x0A External Interrupt Register
|
||||
P_CEI 0x0B Clear External Interrupt
|
||||
P_PTGBMODE 0x0C PTG B Mode (R/W)
|
||||
P_PBB 0x0D PBB (R/W)
|
||||
P_PBUL 0x0E PBUL, PBB to PBLL
|
||||
P_PBULC 0x0F PBUL PBB-PBLL Clear Download
|
||||
P_TAMODE 0x10 Timer A Mode
|
||||
P_TALC 0x11 Timer A LC, Timer A UC - Timer A S, Timer A LL
|
||||
P_TAS 0x12 Timer A S (R), Timer A UL (W)
|
||||
P_TASC 0x13 Timer A S, Timer A UL, Clear, Download
|
||||
P_TBMODE 0x14 Timer B Mode
|
||||
P_TBLC 0x15 Timer B LC, Timer B UC - Timer B S, Timer B LL
|
||||
P_TBS 0x16 Timer B S (R), Timer B UL (W)
|
||||
P_TBSC 0x17 Timer B S, Timer B UL, Clear, Download
|
||||
P_BANK0000 0x18 Bank switch register 0000-1FFF (R/W)
|
||||
P_BANK2000 0x19 Bank switch register 2000-3FFF (R/W)
|
||||
P_BANK4000 0x1A Bank switch register 4000-5FFF (R/W)
|
||||
P_BANK6000 0x1B Bank switch register 6000-7FFF (R/W)
|
||||
P_BANK8000 0x1C Bank switch register 8000-9FFF (R/W)
|
||||
P_BANKA000 0x1D Bank switch register A000-BFFF (R/W)
|
||||
P_BANKC000 0x1E Bank switch register C000-DFFF (R/W)
|
||||
P_BANKE000 0x1F Bank switch register E000-FFFF (R/W)
|
||||
P_TXRX 0x20 Tx/Rx FIFO buf
|
||||
P_LSR 0x21 LSR
|
||||
P_MSR 0x22 MSR
|
||||
P_LCR 0x23 line control register
|
||||
P_MCR 0x24 modem control register
|
||||
P_FIFOC 0x25 FIFO control
|
||||
P_SPRAM6 0x26 SP RAM 6
|
||||
P_SCRR 0x27 scratch reg
|
||||
P_DLSB 0x28 divisor latch LSB
|
||||
P_DMSB 0x29 divisor latch MSB
|
||||
P_SPRAMA 0x2A SP RAM A
|
||||
P_SPRAMB 0x2B SP RAM B
|
||||
P_SPRAMC 0x2C SP RAM C
|
||||
P_SPRAMD 0x2D SP RAM D
|
||||
P_GPFE 0x2E GPFS
|
||||
P_HHR 0x2F host handshake register
|
||||
P_FSR 0x30 FSR
|
||||
P_FIER 0x31 FIER
|
||||
P_HCR 0x32 host control register
|
||||
P_CSF 0x33 chip select fast/slow
|
||||
P_PTGAMODE 0x34 PTG A mode
|
||||
P_PAB 0x35 PAB
|
||||
P_PAUL 0x36 PAUL, PAB-PALL
|
||||
P_PAULC 0x37 PAUL PAB-PALL clear download
|
||||
P_SIOBUF 0x38 serial I/O buffers
|
||||
P_SIE 0x39 serial interrupt enable
|
||||
P_SMR 0x3A serial mode register
|
||||
P_SLCR 0x3B serial line control register
|
||||
P_SSR 0x3C serial status register
|
||||
P_SFR 0x3D serial form register
|
||||
P_SOUTD 0x3E SOUT (RxD) divider latch (R)
|
||||
P_SIND 0x3F SIN (TxD) divider latch (R)
|
||||
|
||||
|
||||
.C29
|
||||
|
||||
; MEMORY MAP
|
||||
area DATA SFR 0x0000:0x0040 Special Function Register
|
||||
area DATA IRAMS 0x0040:0x0080 Page 1 Segment Address
|
||||
area DATA IRAM0 0x0080:0x0100 Page 0 Internal RAM
|
||||
area DATA IRAM1 0x0100:0x0200 Page 1 Internal RAM
|
||||
area DATA IRAM2 0x0200:0x0300 Page 2 Internal RAM
|
||||
area DATA IRAM3 0x0300:0x0400 Page 3 Internal RAM
|
||||
area DATA IRAM4 0x0400:0x0480 Page 4 Internal RAM
|
||||
area DATA ICRC 0x0480:0x0500 CRC buffer Area
|
||||
area DATA IRAM5 0x0500:0x0600 Page 5 Internal RAM (UNAVAIL)
|
||||
area DATA IES4 0x0600:0x0800 Part of ES4 RAM
|
||||
|
||||
; Interrupt and reset vector assignments
|
||||
interrupt JSB0_ 0xFFE0 JBS0 Vector
|
||||
interrupt JSB1_ 0xFFE2 JBS1 Vector
|
||||
interrupt JSB2_ 0xFFE4 JBS2 Vector
|
||||
interrupt JSB3_ 0xFFE6 JBS3 Vector
|
||||
interrupt JSB4_ 0xFFE8 JBS4 Vector
|
||||
interrupt JSB5_ 0xFFEA JBS5 Vector
|
||||
interrupt JSB6_ 0xFFEC JBS6 Vector
|
||||
interrupt JSB7_ 0xFFEE JBS7 Vector
|
||||
interrupt INT0_ 0xFFF0 INT0 Vector
|
||||
interrupt TIMERA_ 0xFFF2 TIMER A Vector
|
||||
interrupt INT2_ 0xFFF4 INT2 Vector
|
||||
interrupt TIMERB_ 0xFFF6 TIMER B Vector
|
||||
interrupt INT4_ 0xFFF8 INT4 Vector
|
||||
interrupt NMI_ 0xFFFA NMI Vector
|
||||
interrupt RESET_ 0xFFFC Reset Vector
|
||||
interrupt PWR_INT 0xFFFE Start Vector
|
||||
|
||||
|
||||
; INPUT/OUTPUT
|
||||
P_A 0x00 Port A (bidir)
|
||||
P_B 0x01 Port B (W)
|
||||
P_C 0x02 Port C (Bidir)
|
||||
P_AD 0x03 Port A Direction (R/O)
|
||||
P_DD 0x04 Port D Direction Controll
|
||||
P_BS 0x05 Port B Select (R/W)
|
||||
P_CD 0x06 Port C Direction (W)
|
||||
P_E 0x07 Port E (R/W)
|
||||
P_ED 0x08 Port E Direction/Mask option
|
||||
P_LPR 0x09 Low Power Register
|
||||
P_EI 0x0A External Interrupt Register
|
||||
P_CEI 0x0B Clear External Interrupt
|
||||
P_PTGBMODE 0x0C PTG B Mode (R/W)
|
||||
P_PBB 0x0D PBB (R/W)
|
||||
P_PBUL 0x0E PBUL, PBB to PBLL
|
||||
P_PBULC 0x0F PBUL PBB-PBLL Clear Download
|
||||
P_TAMODE 0x10 Timer A Mode
|
||||
P_TALC 0x11 Timer A LC, Timer A UC - Timer A S, Timer A LL
|
||||
P_TAS 0x12 Timer A S (R), Timer A UL (W)
|
||||
P_TASC 0x13 Timer A S, Timer A UL, Clear, Download
|
||||
P_TBMODE 0x14 Timer B Mode
|
||||
P_TBLC 0x15 Timer B LC, Timer B UC - Timer B S, Timer B LL
|
||||
P_TBS 0x16 Timer B S (R), Timer B UL (W)
|
||||
P_TBSC 0x17 Timer B S, Timer B UL, Clear, Download
|
||||
P_BANK0000 0x18 Bank switch register 0000-1FFF (R/W)
|
||||
P_BANK2000 0x19 Bank switch register 2000-3FFF (R/W)
|
||||
P_BANK4000 0x1A Bank switch register 4000-5FFF (R/W)
|
||||
P_BANK6000 0x1B Bank switch register 6000-7FFF (R/W)
|
||||
P_BANK8000 0x1C Bank switch register 8000-9FFF (R/W)
|
||||
P_BANKA000 0x1D Bank switch register A000-BFFF (R/W)
|
||||
P_BANKC000 0x1E Bank switch register C000-DFFF (R/W)
|
||||
P_BANKE000 0x1F Bank switch register E000-FFFF (R/W)
|
||||
P_TXRX 0x20 Tx/Rx
|
||||
P_TXBUF 0x21 Tx buffer
|
||||
P_SPRAM2 0x22 SP RAM 2
|
||||
P_LCR 0x23 line control register
|
||||
P_MCR 0x24 modem control register
|
||||
P_SPRAM5 0x25 SP RAM 5
|
||||
P_SPRAM6 0x26 SP RAM 6
|
||||
P_SPRAM7 0x27 SP RAM 7
|
||||
P_DLSB 0x28 divisor latch LSB
|
||||
P_DMSB 0x29 divisor latch MSB
|
||||
P_SPRAMA 0x2A SP RAM A
|
||||
P_SPRAMB 0x2B SP RAM B
|
||||
P_SPRAMC 0x2C SP RAM C
|
||||
P_SPRAMD 0x2D SP RAM D
|
||||
P_SPRAME 0x2E SP RAM E
|
||||
P_HHR 0x2F host handshake register
|
||||
P_LSR 0x30 LSR
|
||||
P_MSR 0x31 MSR
|
||||
P_HCR 0x32 host control register
|
||||
P_CSF 0x33 chip select fast/slow
|
||||
P_PTGAMODE 0x34 PTG A mode
|
||||
P_PAB 0x35 PAB
|
||||
P_PAUL 0x36 PAUL, PAB-PALL
|
||||
P_PAULC 0x37 PAUL PAB-PALL clear download
|
||||
P_SIOBUF 0x38 serial I/O buffers
|
||||
P_SIE 0x39 serial interrupt enable
|
||||
P_SMR 0x3A serial mode register
|
||||
P_SLCR 0x3B serial line control register
|
||||
P_SSR 0x3C serial status register
|
||||
P_SFR 0x3D serial form register
|
||||
P_SOUTD 0x3E SOUT (RxD) divider latch (R)
|
||||
P_SIND 0x3F SIN (TxD) divider latch (R)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
; Some Datapump register's - RC(V)288DPi
|
||||
;DPi Rx/voice Rx buf (RBUFFER/VBUFR)
|
||||
;DPi VOLUME/VPAUSE/CELULR/xXHF/RXP
|
||||
;DPi TDE/SQDIS/V54/S511/DCD/CODBITS
|
||||
;DPi EPT/SEPT/SRCEN/RLSDE/ARC/SDIS
|
||||
;DPi RB/EQT2/V32BS/FIFOEN/EQFZ/NRZIEN
|
||||
;DPi ECFZ/ECSQ/FECSQ/TXSQ/CEQ/TTDIS
|
||||
;DPi RTDIS/EXOS/CF17/HDLC/PEN/STB
|
||||
;DPi RDLE/RDL/L2ACT/DDIS/L3ACT/RA
|
||||
;DPi ASYN/TPDM/V21S/V54T/V54A/V54P
|
||||
;DPi NV25/CC/DTMF/ORG/LL/DATA/RRTSE
|
||||
;DPi PNSUC/FLAGDT/PE/FE/OE/CRCS/VSYNC
|
||||
;DPi TONEx/ATV25/ATBEL/DISDET/EQMAT
|
||||
;DPi AADET/ACDET/CADET/CCDET/SDET
|
||||
;DPi P2DET/PNDET/S1DET/SCR1/U1DET
|
||||
;DPi RTDET/BRKD/RREDT/V32BDT/SPEED
|
||||
;DPi RLSD/FED/CTS/DSR/RI/TM/RTSDT
|
||||
;DPi Tx/voice Tx buf (TBUFFER/VBUFT)
|
||||
;DPi BRKS/PARSL/TXV/RXV/V23HDX/TEOF
|
||||
;DPi configuration (CONF)
|
||||
;DPi TLVL/RTH/TXCLK
|
||||
;DPi handshake abort code (ABCODE)
|
||||
;DPi SLEEP/RDWK/HWRWK/AUTO/RREN/EXL3
|
||||
;DPi sec Rx/V.34 Rx status (SECRXB)
|
||||
;DPi sec Tx/V.34 Tx status (SECTXB)
|
||||
;DPi memory access data LSB (MEDAL)
|
||||
;DPi memory access data MSB (MEDAM)
|
||||
;DPi SFRES/RIEN/RION/DMAE/SCOBF
|
||||
;DPi EDET/DTDET/OTS/DTMFD/DTMF code
|
||||
;DPi memory access addr LSB (MEADDL)
|
||||
;DPi MEACC/MEMW/MEMCR/addr bits 8-11
|
||||
;DPi TDBIA/RDBIA/TDBIE/TDBE/RDBIE
|
||||
;DPi NSIA/NCIA/NSIE/NEWS/NCIE/NEWC
|
||||
;
|
||||
72
idasdk76/module/c39/c39.hpp
Normal file
72
idasdk76/module/c39/c39.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#ifndef _C39_HPP
|
||||
#define _C39_HPP
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#define near
|
||||
#define far
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
// ============================================================
|
||||
// aditional bits for specflags1 (specflag2 not used)
|
||||
//-----------------------------------------------
|
||||
// additional bits for memory access
|
||||
#define URR_IND (0x01) // indirect via a register
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// list of processor registers
|
||||
#ifdef _MSC_VER
|
||||
#define ENUM8BIT : uint8
|
||||
#else
|
||||
#define ENUM8BIT
|
||||
#endif
|
||||
enum C39_registers ENUM8BIT
|
||||
{
|
||||
rNULLReg,
|
||||
rA,
|
||||
rX, rY,
|
||||
rVcs, rVds
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi C39_ana(insn_t *insn);
|
||||
int idaapi C39_emu(const insn_t &insn);
|
||||
void idaapi C39_data(outctx_t &ctx, bool analyze_only);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct c39_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
iohandler_t ioh = iohandler_t(helper);
|
||||
bool flow = false; // stop flag
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void C39_header(outctx_t &ctx);
|
||||
void handle_operand(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
bool is_forced,
|
||||
bool isload);
|
||||
int C39_emu(const insn_t &insn);
|
||||
|
||||
void C39_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void C39_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ C39"
|
||||
#define PROCMOD_NAME c39
|
||||
|
||||
#endif
|
||||
98
idasdk76/module/c39/emu.cpp
Normal file
98
idasdk76/module/c39/emu.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "c39.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// use/change of operands
|
||||
void c39_t::handle_operand(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
bool is_forced,
|
||||
bool isload)
|
||||
{
|
||||
ea_t ea = map_code_ea(insn, x);
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
break;
|
||||
// nothing to do here
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
if ( !isload )
|
||||
goto badTouch;
|
||||
set_immd(insn.ea);
|
||||
if ( !is_forced && is_off(get_flags(insn.ea), x.n) )
|
||||
insn.add_dref(ea, x.offb, dr_O); // offset!
|
||||
break;
|
||||
|
||||
// jump or call
|
||||
case o_near:
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
// add xref to code
|
||||
insn.add_cref(ea, x.offb, fl_CN);
|
||||
// is nonreturning function?
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.add_cref(ea, x.offb, fl_JN);
|
||||
}
|
||||
break;
|
||||
|
||||
// memory reference
|
||||
case o_mem:
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
// add xref to the target address
|
||||
if ( insn.itype == C39_jmp && x.dtype == dt_word && is_loaded(ea) )
|
||||
{
|
||||
ea_t callee = get_word(ea);
|
||||
if ( callee > 32 && is_mapped(callee) ) // is good address?
|
||||
{
|
||||
add_cref(insn.ea, callee, fl_JN);
|
||||
if ( !is_defarg0(get_flags(ea)) )
|
||||
op_plain_offset(ea, 0, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
badTouch:
|
||||
warning("%a %s,%d: bad optype %d",
|
||||
insn.ea, insn.get_canon_mnem(ph),
|
||||
x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int c39_t::C39_emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
if ( Feature & CF_USE1) handle_operand(insn, insn.Op1, flag1, true);
|
||||
if ( Feature & CF_USE2) handle_operand(insn, insn.Op2, flag2, true);
|
||||
if ( Feature & CF_USE3) handle_operand(insn, insn.Op3, flag3, true);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP,insn.ea);
|
||||
|
||||
if ( Feature & CF_CHG1) handle_operand(insn, insn.Op1, flag1, false);
|
||||
if ( Feature & CF_CHG2) handle_operand(insn, insn.Op2, flag2, false);
|
||||
if ( Feature & CF_CHG3) handle_operand(insn, insn.Op3, flag3, false);
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
128
idasdk76/module/c39/ins.cpp
Normal file
128
idasdk76/module/c39/ins.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "c39.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 },
|
||||
{ "ADC", CF_USE1 },
|
||||
{ "ADD", CF_USE1 },
|
||||
{ "ANC", CF_USE1 },
|
||||
{ "AND", CF_USE1 },
|
||||
{ "ANE", CF_USE1 },
|
||||
{ "ARR", CF_USE1 },
|
||||
{ "ASL", 0 },
|
||||
{ "ASR", CF_USE1 },
|
||||
{ "BAR", CF_USE1|CF_USE2|CF_USE3 },
|
||||
{ "BAS", CF_USE1|CF_USE2|CF_USE3 },
|
||||
{ "BBR", CF_USE1|CF_USE2|CF_USE3|CF_JUMP },
|
||||
{ "BBS", CF_USE1|CF_USE2|CF_USE3|CF_JUMP },
|
||||
{ "BCC", CF_USE1|CF_JUMP },
|
||||
{ "BCS", CF_USE1|CF_JUMP },
|
||||
{ "BEQ", CF_USE1|CF_JUMP },
|
||||
{ "BIT", CF_USE1 },
|
||||
{ "BMI", CF_USE1|CF_JUMP },
|
||||
{ "BNE", CF_USE1|CF_JUMP },
|
||||
{ "BPL", CF_USE1|CF_JUMP },
|
||||
{ "BRA", CF_USE1|CF_JUMP|CF_STOP },
|
||||
{ "BRK", CF_STOP },
|
||||
{ "BVC", CF_USE1|CF_JUMP },
|
||||
{ "BVS", CF_USE1|CF_JUMP },
|
||||
{ "CLC", 0 },
|
||||
{ "CLD", 0 },
|
||||
{ "CLI", 0 },
|
||||
{ "CLV", 0 },
|
||||
{ "CLW", 0 },
|
||||
{ "CMP", CF_USE1 },
|
||||
{ "CPX", CF_USE1 },
|
||||
{ "CPY", CF_USE1 },
|
||||
{ "DCP", CF_USE1|CF_CHG1 },
|
||||
{ "DEC", CF_USE1|CF_CHG1 },
|
||||
{ "DEX", 0 },
|
||||
{ "DEY", 0 },
|
||||
{ "EOR", CF_USE1 },
|
||||
{ "EXC", CF_USE1 },
|
||||
{ "INC", CF_USE1|CF_CHG1 },
|
||||
{ "INI", 0 },
|
||||
{ "INX", 0 },
|
||||
{ "INY", 0 },
|
||||
{ "ISB", CF_USE1|CF_CHG1 },
|
||||
{ "JMP", CF_USE1|CF_STOP|CF_JUMP },
|
||||
{ "JPI", CF_USE1|CF_STOP|CF_JUMP },
|
||||
{ "JSB", CF_USE1|CF_CALL },
|
||||
{ "JSR", CF_USE1|CF_CALL },
|
||||
{ "LAB", CF_USE1 },
|
||||
{ "LAE", CF_USE1 },
|
||||
{ "LAI", 0 },
|
||||
{ "LAN", 0 },
|
||||
{ "LAX", CF_USE1 },
|
||||
{ "LDA", CF_USE1 },
|
||||
{ "LDX", CF_USE1 },
|
||||
{ "LDY", CF_USE1 },
|
||||
{ "LII", 0 },
|
||||
{ "LSR", 0 },
|
||||
{ "LXA", CF_USE1 },
|
||||
{ "MPA", 0 },
|
||||
{ "MPY", 0 },
|
||||
{ "NEG", CF_USE1 },
|
||||
{ "NOP", 0 },
|
||||
{ "NXT", 0 },
|
||||
{ "ORA", CF_USE1 },
|
||||
{ "PHA", 0 },
|
||||
{ "PHI", 0 },
|
||||
{ "PHP", 0 },
|
||||
{ "PHW", 0 },
|
||||
{ "PHX", 0 },
|
||||
{ "PHY", 0 },
|
||||
{ "PIA", 0 },
|
||||
{ "PLA", 0 },
|
||||
{ "PLI", 0 },
|
||||
{ "PLP", 0 },
|
||||
{ "PLW", 0 },
|
||||
{ "PLX", 0 },
|
||||
{ "PLY", 0 },
|
||||
{ "PSH", 0 },
|
||||
{ "PUL", 0 },
|
||||
{ "RBA", CF_USE1|CF_USE2 },
|
||||
{ "RLA", CF_USE1|CF_CHG1 },
|
||||
{ "RMB", CF_USE1|CF_USE2 },
|
||||
{ "RND", 0 },
|
||||
{ "ROL", 0 },
|
||||
{ "ROR", 0 },
|
||||
{ "RRA", CF_USE1|CF_CHG1 },
|
||||
{ "RTI", CF_STOP },
|
||||
{ "RTS", CF_STOP },
|
||||
{ "SAX", CF_CHG1 },
|
||||
{ "SBA", CF_USE1|CF_USE2 },
|
||||
{ "SBC", CF_USE1 },
|
||||
{ "SBX", CF_USE1 },
|
||||
{ "SEC", 0 },
|
||||
{ "SED", 0 },
|
||||
{ "SEI", 0 },
|
||||
{ "SHA", CF_CHG1 },
|
||||
{ "SHS", CF_CHG1 },
|
||||
{ "SHX", CF_CHG1 },
|
||||
{ "SHY", CF_CHG1 },
|
||||
{ "SLO", CF_USE1|CF_CHG1 },
|
||||
{ "SMB", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "SRE", CF_USE1|CF_CHG1 },
|
||||
{ "STA", CF_CHG1 },
|
||||
{ "STI", CF_USE1|CF_USE2 },
|
||||
{ "STX", CF_CHG1 },
|
||||
{ "STY", CF_CHG1 },
|
||||
{ "TAX", 0 },
|
||||
{ "TAY", 0 },
|
||||
{ "TAW", 0 },
|
||||
{ "TIP", 0 },
|
||||
{ "TSX", 0 },
|
||||
{ "TWA", 0 },
|
||||
{ "TXA", 0 },
|
||||
{ "TXS", 0 },
|
||||
{ "TYA", 0 }
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == C39_last);
|
||||
134
idasdk76/module/c39/ins.hpp
Normal file
134
idasdk76/module/c39/ins.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
// List of instructions
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
//
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
C39_null = 0, // Unknown Operation
|
||||
C39_adc,
|
||||
C39_add,
|
||||
C39_anc,
|
||||
C39_and,
|
||||
C39_ane,
|
||||
C39_arr,
|
||||
C39_asl,
|
||||
C39_asr,
|
||||
C39_bar,
|
||||
C39_bas,
|
||||
C39_bbr,
|
||||
C39_bbs,
|
||||
C39_bcc,
|
||||
C39_bcs,
|
||||
C39_beq,
|
||||
C39_bit,
|
||||
C39_bmi,
|
||||
C39_bne,
|
||||
C39_bpl,
|
||||
C39_bra,
|
||||
C39_brk,
|
||||
C39_bvc,
|
||||
C39_bvs,
|
||||
C39_clc,
|
||||
C39_cld,
|
||||
C39_cli,
|
||||
C39_clv,
|
||||
C39_clw,
|
||||
C39_cmp,
|
||||
C39_cpx,
|
||||
C39_cpy,
|
||||
C39_dcp,
|
||||
C39_dec,
|
||||
C39_dex,
|
||||
C39_dey,
|
||||
C39_eor,
|
||||
C39_exc,
|
||||
C39_inc,
|
||||
C39_ini,
|
||||
C39_inx,
|
||||
C39_iny,
|
||||
C39_isb,
|
||||
C39_jmp,
|
||||
C39_jpi,
|
||||
C39_jsb,
|
||||
C39_jsr,
|
||||
C39_lab,
|
||||
C39_lae,
|
||||
C39_lai,
|
||||
C39_lan,
|
||||
C39_lax,
|
||||
C39_lda,
|
||||
C39_ldx,
|
||||
C39_ldy,
|
||||
C39_lii,
|
||||
C39_lsr,
|
||||
C39_lxa,
|
||||
C39_mpa,
|
||||
C39_mpy,
|
||||
C39_neg,
|
||||
C39_nop,
|
||||
C39_nxt,
|
||||
C39_ora,
|
||||
C39_pha,
|
||||
C39_phi,
|
||||
C39_php,
|
||||
C39_phw,
|
||||
C39_phx,
|
||||
C39_phy,
|
||||
C39_pia,
|
||||
C39_pla,
|
||||
C39_pli,
|
||||
C39_plp,
|
||||
C39_plw,
|
||||
C39_plx,
|
||||
C39_ply,
|
||||
C39_psh,
|
||||
C39_pul,
|
||||
C39_rba,
|
||||
C39_rla,
|
||||
C39_rmb,
|
||||
C39_rnd,
|
||||
C39_rol,
|
||||
C39_ror,
|
||||
C39_rra,
|
||||
C39_rti,
|
||||
C39_rts,
|
||||
C39_sax,
|
||||
C39_sba,
|
||||
C39_sbc,
|
||||
C39_sbx,
|
||||
C39_sec,
|
||||
C39_sed,
|
||||
C39_sei,
|
||||
C39_sha,
|
||||
C39_shs,
|
||||
C39_shx,
|
||||
C39_shy,
|
||||
C39_slo,
|
||||
C39_smb,
|
||||
C39_sre,
|
||||
C39_sta,
|
||||
C39_sti,
|
||||
C39_stx,
|
||||
C39_sty,
|
||||
C39_tax,
|
||||
C39_tay,
|
||||
C39_taw,
|
||||
C39_tip,
|
||||
C39_tsx,
|
||||
C39_twa,
|
||||
C39_txa,
|
||||
C39_txs,
|
||||
C39_tya,
|
||||
C39_last
|
||||
};
|
||||
|
||||
#endif
|
||||
57
idasdk76/module/c39/makefile
Normal file
57
idasdk76/module/c39/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=c39
|
||||
CONFIGS=c39.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)ieee.h $(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 c39.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
c39.hpp emu.cpp 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)ieee.h $(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 \
|
||||
c39.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)ieee.h $(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 \
|
||||
c39.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)ieee.h $(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 c39.hpp ins.hpp reg.cpp
|
||||
171
idasdk76/module/c39/out.cpp
Normal file
171
idasdk76/module/c39/out.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "c39.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_C39_t : public outctx_t
|
||||
{
|
||||
out_C39_t(void) = delete; // not used
|
||||
public:
|
||||
void OutVarName(const op_t &x);
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_C39_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_C39_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_C39_t::OutVarName(const op_t &x)
|
||||
{
|
||||
ea_t toea = map_code_ea(insn, x);
|
||||
if ( !out_name_expr(x, toea, x.addr) )
|
||||
{
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_C39_t::out_operand(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
refinfo_t ri;
|
||||
// micro bug-fix
|
||||
if ( get_refinfo(&ri, insn.ea, x.n) )
|
||||
{
|
||||
if ( ri.flags == REF_OFF16 )
|
||||
{
|
||||
set_refinfo(insn.ea, x.n,
|
||||
REF_OFF32, ri.target, ri.base, ri.tdelta);
|
||||
// msg("Exec OFF16_Op Fix AT:%a Flags=%x, Target=%a, Base=%a, Delta=%a\n",
|
||||
// insn.ea,
|
||||
// ri.flags,ri.target,ri.base,ri.tdelta);
|
||||
}
|
||||
}
|
||||
out_value(x, /*OOFS_NOSIGN | */ OOF_SIGNED | OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
OutVarName(x);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
if ( x.specflag1&URR_IND )
|
||||
out_symbol('(');
|
||||
out_value(x, OOFS_NOSIGN | OOFW_IMM);
|
||||
if ( x.specflag1&URR_IND )
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
INTERR(10133);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_C39_t::out_insn(void)
|
||||
{
|
||||
out_mnemonic();
|
||||
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_one_operand(0);
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2);
|
||||
}
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void c39_t::C39_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, Sarea) could be made const
|
||||
void c39_t::C39_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
const char *SegType = Sarea->type == SEG_CODE ? "CSEG"
|
||||
: Sarea->type == SEG_DATA ? "DSEG"
|
||||
: "RSEG";
|
||||
// RSEG <NAME>
|
||||
qstring sn;
|
||||
get_visible_segm_name(&sn, Sarea);
|
||||
ctx.gen_printf(-1,"%s %s ",SegType, sn.c_str());
|
||||
// if non-zero offset (ORG XXXX)
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
if ( org != 0 )
|
||||
{
|
||||
char bufn[MAX_NUMBUF];
|
||||
btoa(bufn, sizeof(bufn), org);
|
||||
ctx.gen_printf(-1, "%s %s", ash.origin, bufn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void c39_t::C39_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 )
|
||||
{
|
||||
size_t i = strlen(ash.end);
|
||||
do
|
||||
ctx.out_char(' ');
|
||||
while ( ++i < 8 );
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi C39_data(outctx_t &ctx, bool analyze_only)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
// micro bug-fix
|
||||
refinfo_t ri;
|
||||
if ( get_refinfo(&ri, ea, 0) && ri.flags == REF_OFF16 )
|
||||
set_refinfo(ea, 0, REF_OFF32, ri.target, ri.base, ri.tdelta);
|
||||
|
||||
ctx.out_data(analyze_only);
|
||||
}
|
||||
242
idasdk76/module/c39/reg.cpp
Normal file
242
idasdk76/module/c39/reg.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Rockwell C39 processor module for IDA.
|
||||
* Copyright (c) 2000-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "c39.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <segregs.hpp>
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
// empty place
|
||||
"",
|
||||
// general registers
|
||||
"A","X","Y",
|
||||
// pseudo-segment registers
|
||||
"cs","ds"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void c39_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(c39_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi c39_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_gen_lzero(true);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgfile, &cb) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
{
|
||||
segment_t *s = va_arg(va, segment_t *);
|
||||
// Set default value of DS register for all segments
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
C39_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
C39_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 *);
|
||||
C39_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return C39_ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return C39_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);
|
||||
C39_data(*ctx, analyze_only);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// PseudoSam
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t pseudosam =
|
||||
{
|
||||
AS_COLON | AS_UDATA | ASH_HEXF3 | ASD_DECF0,
|
||||
0,
|
||||
"Generic C39 assembler", // Assembler name
|
||||
0, // Help screen number, 0 - no help
|
||||
NULL, // array of automatically generated header lines
|
||||
"org", // ORG
|
||||
"end", // end
|
||||
|
||||
";", // comment
|
||||
'"', // string literal delimiter
|
||||
'\'', // char constant delimiter
|
||||
"\\\"'", // special chars that cannot appear
|
||||
|
||||
"db", // ascii string directive
|
||||
".DATA.B", // byte directive
|
||||
".DATA.W", // word directive
|
||||
".DATA.L", // 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
|
||||
"#d dup(#v)", // arrays (#h,#d,#v,#s(...)
|
||||
"db ?", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // seg prefix
|
||||
"$", // current IP
|
||||
NULL, // Generate function header lines
|
||||
NULL, // Generate function footer lines
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // Get name of type of item at ea or id
|
||||
".ALIGN", // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &pseudosam, NULL };
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "Rockwell C39:"
|
||||
static const char *const shnames[] = { "C39", NULL };
|
||||
static const char *const lnames[] = { FAMILY"Rockwell C39", NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const uchar retcode_1[] = { 0x00, 0x0B }; // RTS
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_C39, // processor's id
|
||||
// flag
|
||||
PR_USE32
|
||||
| PR_BINMEM
|
||||
| PR_SEGTRANS,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte
|
||||
|
||||
shnames, // short processor names
|
||||
lnames, // long processor names
|
||||
|
||||
asms, // assembler definitions
|
||||
|
||||
notify, // Event notification handler
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs,rVds,
|
||||
2, // size of a segment register
|
||||
rVcs,rVds,
|
||||
NULL, // typical code start sequences
|
||||
retcodes, // 'return' instruction opcodes
|
||||
0,C39_last, // icode of the first and the last instruction
|
||||
Instructions, // instruc
|
||||
3, // Size of long double (tbyte) - 24 bits
|
||||
{0,0,0,0}, // Number of digits in floating numbers after the decimal point
|
||||
0, // Icode of return instruction
|
||||
NULL, // Reserved, currently equals to NULL
|
||||
};
|
||||
127
idasdk76/module/cfh_ha16.cpp
Normal file
127
idasdk76/module/cfh_ha16.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
|
||||
// This file contains a custom fixup handler for the HA16 fixup type.
|
||||
// It is used by PPC, MIPS, and similar processors.
|
||||
// Also thie file contains a custom refinfo handler for the HA16 type.
|
||||
|
||||
#include <fixup.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 'apply' a fixup: take it into account while analyzing the file
|
||||
// usually it consists of converting the operand into an offset expression
|
||||
static bool idaapi ha16_apply(
|
||||
const fixup_handler_t *fh,
|
||||
ea_t item_ea,
|
||||
ea_t fixup_ea,
|
||||
int opnum,
|
||||
bool is_macro,
|
||||
const fixup_data_t &fd)
|
||||
{
|
||||
if ( is_unknown(get_flags(item_ea)) )
|
||||
create_16bit_data(fixup_ea, 2);
|
||||
|
||||
refinfo_t ri;
|
||||
ri.flags = fh->reftype;
|
||||
ri.base = fd.get_base();
|
||||
ri.target = ri.base + fd.off;
|
||||
ri.tdelta = fd.displacement;
|
||||
|
||||
// check for the second fixup within a macro instruction
|
||||
if ( is_macro )
|
||||
handle_fixups_in_macro(&ri, item_ea, FIXUP_LOW16, REF_OFF32);
|
||||
if ( processor_t::adjust_refinfo(&ri, fixup_ea, opnum, fd) < 0 )
|
||||
return false;
|
||||
op_offset_ex(item_ea, opnum, &ri);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static uval_t idaapi ha16_get_value(const fixup_handler_t * /*fh*/, ea_t ea)
|
||||
{
|
||||
// we can't get the exact value of this fixup as it depends on the low
|
||||
// part
|
||||
return get_word(ea) << 16;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool idaapi ha16_patch_value(
|
||||
const fixup_handler_t * /*fh*/,
|
||||
ea_t ea,
|
||||
const fixup_data_t &fd)
|
||||
{
|
||||
// compensate signed low part
|
||||
ea_t expr = fd.off + fd.displacement + 0x8000;
|
||||
#ifdef __EA64__
|
||||
// in the case of 32-bit reloc we have to check overflow,
|
||||
// for simplicity we don't do.
|
||||
// overflow = is32bit_reloc && expr > UINT_MAX;
|
||||
#endif
|
||||
put_word(ea, expr >> 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const fixup_handler_t cfh_ha16 =
|
||||
{
|
||||
sizeof(fixup_handler_t),
|
||||
"HIGHA16", /* name */
|
||||
0, /* props */
|
||||
2, 0, 0, 0, /* size, width, shift */
|
||||
REFINFO_CUSTOM, /* reftype */
|
||||
ha16_apply, /* apply */
|
||||
ha16_get_value, /* get_value */
|
||||
ha16_patch_value, /* patch_value */
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool was_displacement_generated(const char *buf)
|
||||
{
|
||||
const char *ptr = strchr(buf, COLOR_SYMBOL); // is there a displacement?
|
||||
return ptr != NULL && (ptr[1] == '+' || ptr[1] == '-');
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// get reference data from ri,
|
||||
// check compliance of opval and the full value
|
||||
static bool idaapi ha16_calc_reference_data(
|
||||
ea_t *target,
|
||||
ea_t *base,
|
||||
ea_t /*from*/,
|
||||
const refinfo_t &ri,
|
||||
adiff_t opval)
|
||||
{
|
||||
if ( ri.target == BADADDR
|
||||
|| ri.base == BADADDR
|
||||
|| ri.is_subtract() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ea_t fullvalue = ri.target + ri.tdelta - ri.base;
|
||||
int16 calc_opval = (fullvalue >> 16) & 0xFFFF;
|
||||
if ( (fullvalue & 0x8000) != 0 )
|
||||
calc_opval += 1;
|
||||
if ( calc_opval != int16(opval) )
|
||||
return false;
|
||||
|
||||
*target = ri.target;
|
||||
*base = ri.base;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// simple format
|
||||
static void idaapi ha16_get_format(qstring *format)
|
||||
{
|
||||
*format = COLSTR("%s@ha", SCOLOR_KEYWORD);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const custom_refinfo_handler_t ref_ha16 =
|
||||
{
|
||||
sizeof(custom_refinfo_handler_t),
|
||||
"HIGHA16",
|
||||
"high adjusted 16 bits of 32-bit offset",
|
||||
0, // properties (currently 0)
|
||||
NULL, // gen_expr
|
||||
ha16_calc_reference_data, // calc_reference_data
|
||||
ha16_get_format, // get_format
|
||||
};
|
||||
539
idasdk76/module/cr16/ana.cpp
Normal file
539
idasdk76/module/cr16/ana.cpp
Normal file
@@ -0,0 +1,539 @@
|
||||
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "cr16.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static uchar Rproc(uchar code)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case 0x1:
|
||||
return rPSR;
|
||||
case 0x3:
|
||||
return rINTBASE;
|
||||
case 0x4:
|
||||
return rINTBASEH;
|
||||
case 0x5:
|
||||
return rCFG;
|
||||
case 0x7:
|
||||
return rDSR;
|
||||
case 0x9:
|
||||
return rDCR;
|
||||
case 0xB:
|
||||
return rISP;
|
||||
case 0xD:
|
||||
return rCARL;
|
||||
case 0xE:
|
||||
return rCARH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// immediate operands
|
||||
static void SetImmData(op_t &op, int32 code, int bits)
|
||||
{
|
||||
// extend sign
|
||||
if ( code & (1 << bits) )
|
||||
code -= 1L << (bits + 1);
|
||||
op.type = o_imm;
|
||||
// always in the second byte
|
||||
op.offb = 1;
|
||||
// data size
|
||||
op.dtype = bits > 8 ? (bits > 16 ? dt_dword : dt_word) : dt_byte;
|
||||
// value
|
||||
op.addr = op.value = code;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// register operand
|
||||
static void SetReg(op_t &op, uchar reg_n)
|
||||
{
|
||||
op.type = o_reg;
|
||||
op.reg = reg_n;
|
||||
op.dtype = dt_word;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// relative jump
|
||||
static void SetRelative(op_t &op, int32 disp, int bits, const insn_t &insn)
|
||||
{
|
||||
op.type = o_near;
|
||||
op.dtype = dt_word;
|
||||
op.offb = 0;
|
||||
// sign extend
|
||||
if ( disp & (1 << bits) )
|
||||
disp -= 1L << (bits + 1);
|
||||
op.addr = insn.ip + disp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static ushort GetWord(insn_t &insn)
|
||||
{
|
||||
ushort wrd = insn.get_next_byte();
|
||||
wrd |= ((ushort) insn.get_next_byte()) << 8;
|
||||
return wrd;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// store/load operands
|
||||
static void SetSL(insn_t &insn, op_t &op, ushort code)
|
||||
{
|
||||
op.reg = rR0 + ((code >> 1) & 0x0F);
|
||||
op.dtype = (code & 0x2000) ? dt_word : dt_byte;
|
||||
if ( code & 1 )
|
||||
{
|
||||
if ( code & 0x1000 )
|
||||
{
|
||||
if ( code & 0x800 )
|
||||
{
|
||||
if ( (code & 0x1F) == 0x1F )
|
||||
{
|
||||
// absolute addr
|
||||
op.type = o_mem;
|
||||
op.addr = op.value = GetWord(insn) | (((uint32) code & 0x600) << 11);
|
||||
}
|
||||
else
|
||||
{ // reg pair
|
||||
op.type = o_displ;
|
||||
op.addr = op.value = GetWord(insn) | (((uint32) code & 0x600) << 11);
|
||||
op.specflag1 |= URR_PAIR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // reg base
|
||||
op.type = o_displ;
|
||||
op.addr = op.value = GetWord(insn) | (((uint32) code & 0x600) << 11);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Offset
|
||||
op.type = o_displ;
|
||||
op.addr = op.value = ((code >> 8) & 0x1E) | 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
op.type = o_displ;
|
||||
op.addr = op.value = (code >> 8) & 0x1E;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
#define EXTOPS uint16(-2)
|
||||
static const uint16 Ops[16] =
|
||||
{
|
||||
CR16_addb, CR16_addub, EXTOPS, CR16_mulb,
|
||||
CR16_ashub, CR16_lshb, CR16_xorb, CR16_cmpb,
|
||||
CR16_andb, CR16_addcb, CR16_br, CR16_tbit,
|
||||
CR16_movb, CR16_subcb, CR16_orb, CR16_subb,
|
||||
};
|
||||
|
||||
static const uint16 ExtOps[16] =
|
||||
{
|
||||
CR16_cbitb, CR16_sbitb, CR16_tbitb, CR16_storb,
|
||||
};
|
||||
|
||||
// extended instructions
|
||||
// register-relative with no displacement:
|
||||
// 54 3 2109 8 76 5 4321 d
|
||||
// 01 i 0010 bs1 ex-op bs0 bit-num/Imm 1
|
||||
// register-relative with 16-bit displacement:
|
||||
// 54 3 2109 8 76 5 4321 d
|
||||
// 00 i 0010 bs1 ex-op bs0 bit-num/Imm 1
|
||||
// 18-bit absolute memory:
|
||||
// 54 3 2109 8 76 5 4321 d
|
||||
// 00 i 0010 bs1 ex-op bs0 bit-num/Imm 0
|
||||
static void SetExtOp(insn_t &insn, ushort code)
|
||||
{
|
||||
if ( code & 1 )
|
||||
{
|
||||
// Register-relative
|
||||
insn.Op2.reg = rR0 + ((code >> 5) & 9);
|
||||
insn.Op2.type = o_displ;
|
||||
insn.Op2.dtype = (code & 0x2000) ? dt_word : dt_byte;
|
||||
if ( (code >> 14) & 1 )
|
||||
{
|
||||
// no displacement
|
||||
insn.Op2.addr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.Op2.addr = GetWord(insn);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 18-bit absolute memory
|
||||
insn.Op2.type = o_mem;
|
||||
insn.Op2.dtype = (code & 0x2000) ? dt_word : dt_byte;
|
||||
int adext = ((code >> 7) & 2) | ((code >> 5) & 1);
|
||||
insn.Op2.addr = GetWord(insn) | (adext<<16);
|
||||
}
|
||||
insn.Op1.type = o_imm;
|
||||
insn.Op1.value = (code >> 1) & 0xF;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// analyzer
|
||||
int idaapi CR16_ana(insn_t *_insn)
|
||||
{
|
||||
if ( _insn == NULL )
|
||||
return 0;
|
||||
insn_t &insn = *_insn;
|
||||
if ( insn.ip & 1 )
|
||||
return 0;
|
||||
|
||||
// get instruction word
|
||||
ushort code = GetWord(insn);
|
||||
|
||||
uchar WordFlg = (code >> 13) & 1;
|
||||
uchar OpCode = (code >> 9) & 0x0F;
|
||||
uchar Oper1 = (code >> 5) & 0x0F;
|
||||
uchar Oper2 = (code >> 1) & 0x0F;
|
||||
|
||||
|
||||
switch ( (code >> 14) & 3 )
|
||||
{
|
||||
// register-register op and special OP
|
||||
case 0x01:
|
||||
if ( code & 1 )
|
||||
{
|
||||
// 01xxxxxxxxxxxxx1
|
||||
insn.itype = Ops[OpCode];
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case EXTOPS:
|
||||
{
|
||||
int exop = (Oper1 >> 1) & 3;
|
||||
insn.itype = ExtOps[exop] + WordFlg;
|
||||
SetExtOp(insn, code);
|
||||
}
|
||||
break;
|
||||
// branch's
|
||||
case CR16_br:
|
||||
if ( WordFlg )
|
||||
{
|
||||
insn.itype = CR16_jal;
|
||||
SetReg(insn.Op1, rR0 + Oper1);
|
||||
SetReg(insn.Op2, rR0 + Oper2);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = CR16_jeq + Oper1;
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
}
|
||||
break;
|
||||
// Special tbit
|
||||
case CR16_tbit:
|
||||
if ( WordFlg == 0 )
|
||||
return 0;
|
||||
insn.itype--;
|
||||
// fallthrough
|
||||
// all other cmds
|
||||
default: // fix word operations
|
||||
if ( WordFlg )
|
||||
insn.itype++;
|
||||
// Setup register OP
|
||||
SetReg(insn.Op2, rR0 + Oper1);
|
||||
// Setup register OP
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // 01xxxxxxxxxxxxx0
|
||||
if ( WordFlg )
|
||||
{
|
||||
// 011xxxxxxxxxxxx0
|
||||
static const uchar SCmd[16] =
|
||||
{
|
||||
CR16_mulsb, CR16_mulsw, CR16_movd, CR16_movd,
|
||||
CR16_movxb, CR16_movzb, CR16_push, CR16_seq,
|
||||
CR16_lpr, CR16_spr, CR16_beq, CR16_bal,
|
||||
CR16_retx, CR16_excp, CR16_di, CR16_wait
|
||||
};
|
||||
insn.itype = SCmd[OpCode];
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
|
||||
case CR16_beq:
|
||||
{
|
||||
// 01 1 1010 cond d16,d19-d17 0
|
||||
insn.itype = CR16_beq + Oper1;
|
||||
int disp = GetWord(insn);
|
||||
disp |= (Oper2 & 8) << (16-3);
|
||||
disp |= (Oper2 & 7) << 17;
|
||||
SetRelative(insn.Op1, disp, 20, insn);
|
||||
}
|
||||
break;
|
||||
|
||||
case CR16_push:
|
||||
{
|
||||
static const uchar PQ[4] =
|
||||
{
|
||||
CR16_push, CR16_pop,
|
||||
CR16_popret, CR16_popret
|
||||
};
|
||||
insn.itype = PQ[Oper1 >> 2];
|
||||
SetReg(insn.Op2, rR0 + Oper2);
|
||||
SetImmData(insn.Op1, (Oper1 & 3) + 1, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case CR16_mulsw:
|
||||
SetReg(insn.Op2, rR0 + Oper1);
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
insn.Op2.specflag1 |= URR_PAIR;
|
||||
break;
|
||||
|
||||
case CR16_movd:
|
||||
SetReg(insn.Op2, rR0 + Oper2);
|
||||
insn.Op2.specflag1 |= URR_PAIR;
|
||||
// !!!! ADD HIIIII ?!?!?!?
|
||||
SetImmData(insn.Op1, GetWord(insn), 20);
|
||||
break;
|
||||
case CR16_excp:
|
||||
if ( Oper1 != 0x0F )
|
||||
return 0;
|
||||
SetImmData(insn.Op1, Oper2, 4);
|
||||
break;
|
||||
|
||||
case CR16_retx:
|
||||
if ( Oper1 != 0x0F )
|
||||
return 0;
|
||||
if ( Oper2 != 0x0F )
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case CR16_wait:
|
||||
if ( Oper1 == 0x0F )
|
||||
{
|
||||
if ( Oper2 == 0x0F )
|
||||
break;
|
||||
if ( Oper2 == 0x03 )
|
||||
{
|
||||
insn.itype = CR16_eiwait;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( (code & 0x19E) == 0x84 )
|
||||
{
|
||||
insn.itype = CR16_storm;
|
||||
SetImmData(insn.Op1, (Oper2 & 3) + 1, 8);
|
||||
break;
|
||||
}
|
||||
if ( (code & 0x19E) == 0x04 )
|
||||
{
|
||||
insn.itype = CR16_loadm;
|
||||
SetImmData(insn.Op1, (Oper2 & 3) + 1, 8);
|
||||
break;
|
||||
}
|
||||
if ( (Oper2 & 0x6) == 0 )
|
||||
{
|
||||
insn.itype = CR16_muluw;
|
||||
SetReg(insn.Op2, rR0 + Oper1);
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
insn.Op2.specflag1 |= URR_PAIR;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case CR16_di:
|
||||
if ( Oper2 != 0x0F )
|
||||
return 0;
|
||||
switch ( Oper1 )
|
||||
{
|
||||
case 0x0F:
|
||||
insn.itype = CR16_ei;
|
||||
case 0x0E:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case CR16_seq:
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
if ( Oper1 > 0x0D )
|
||||
return 0;
|
||||
insn.itype = CR16_seq + Oper1;
|
||||
break;
|
||||
|
||||
case CR16_lpr:
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
Oper1 = Rproc(Oper1);
|
||||
if ( Oper1 == 0 )
|
||||
return 0;
|
||||
SetReg(insn.Op2, Oper1);
|
||||
break;
|
||||
|
||||
case CR16_spr:
|
||||
SetReg(insn.Op2, rR0 + Oper2);
|
||||
Oper1 = Rproc(Oper1);
|
||||
if ( Oper1 == 0 )
|
||||
return 0;
|
||||
SetReg(insn.Op1, Oper1);
|
||||
break;
|
||||
|
||||
case CR16_bal:
|
||||
{
|
||||
// 01 1 1011 lnk-pair d16,d19-d17 0
|
||||
SetReg(insn.Op1, rR0 + Oper1);
|
||||
insn.Op1.specflag1 |= URR_PAIR;
|
||||
int disp = GetWord(insn);
|
||||
disp |= (Oper2 & 8) << (16-3);
|
||||
disp |= (Oper2 & 7) << 17;
|
||||
SetRelative(insn.Op2, disp, 20, insn);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
SetReg(insn.Op2, rR0 + Oper1);
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // jump's
|
||||
// 010xxxxxxxxxxxx0
|
||||
insn.itype = CR16_beq + Oper1;
|
||||
SetRelative(insn.Op1, (code & 0x1E) | (OpCode << 5), 8, insn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// short immediate-register (two word)
|
||||
case 0x00:
|
||||
insn.itype = Ops[OpCode];
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
// branch's
|
||||
case CR16_br:
|
||||
if ( code & 1 )
|
||||
{
|
||||
static const uchar BQ[4] =
|
||||
{
|
||||
CR16_beq0b, CR16_beq1b,
|
||||
CR16_bne0b, CR16_bne1b
|
||||
};
|
||||
insn.itype = BQ[(Oper1 >> 1) & 3];
|
||||
if ( WordFlg )
|
||||
insn.itype++;
|
||||
SetReg(insn.Op1, rR0 + (Oper1 & 0x9));
|
||||
SetRelative(insn.Op1, code & 0x1E, 5, insn);
|
||||
}
|
||||
else if ( WordFlg )
|
||||
{
|
||||
insn.itype = CR16_bal;
|
||||
SetReg(insn.Op1, rR0 + Oper1);
|
||||
if ( (code & 0x0F) == 0x0E )
|
||||
{
|
||||
SetRelative(insn.Op2,
|
||||
GetWord(insn) | (((uint32) code & 0x10) << 12), 16, insn);
|
||||
insn.Op2.addr = insn.Op2.value = insn.Op2.addr & 0x1FFFF;
|
||||
}
|
||||
else
|
||||
SetRelative(insn.Op2, code & 0x1F, 4, insn);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = CR16_beq + Oper1;
|
||||
if ( (code & 0x0F) == 0x0E )
|
||||
{
|
||||
SetRelative(insn.Op1,
|
||||
GetWord(insn) | (((uint32) code & 0x10) << 12), 16, insn);
|
||||
insn.Op1.addr = insn.Op1.value = insn.Op2.addr & 0x1FFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRelative(insn.Op1, code & 0x1F, 4, insn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EXTOPS:
|
||||
{
|
||||
// 54 3 2109 8 76 5 4321 d
|
||||
// 00 i 0010 bs1 ex-op bs0 bit-num/Imm d
|
||||
int exop = (Oper1 >> 1) & 3;
|
||||
insn.itype = ExtOps[exop] + WordFlg;
|
||||
SetExtOp(insn, code);
|
||||
}
|
||||
break;
|
||||
|
||||
// Special tbit
|
||||
case CR16_tbit:
|
||||
if ( WordFlg == 0 )
|
||||
{
|
||||
// jcond large format
|
||||
// 00 0 1011 cond target-pair 1
|
||||
// jal large format
|
||||
// 00 0 1011 link-pair target-pair 0
|
||||
if ( code & 1 )
|
||||
{
|
||||
insn.itype = CR16_jeq + Oper1;
|
||||
SetReg(insn.Op1, rR0 + Oper2);
|
||||
insn.Op1.specflag1 |= URR_PAIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = CR16_jal;
|
||||
SetReg(insn.Op1, rR0 + Oper1);
|
||||
insn.Op1.specflag1 |= URR_PAIR;
|
||||
SetReg(insn.Op2, rR0 + Oper2);
|
||||
insn.Op2.specflag1 |= URR_PAIR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
insn.itype--;
|
||||
// fallthrough
|
||||
|
||||
// all other cmds
|
||||
default:
|
||||
if ( code == 0x200 )
|
||||
{
|
||||
insn.itype = CR16_nop;
|
||||
break;
|
||||
}
|
||||
if ( WordFlg ) // fix word operations
|
||||
insn.itype++;
|
||||
// Setup register OP
|
||||
SetReg(insn.Op2, rR0 + Oper1);
|
||||
// Setup immediate
|
||||
if ( (code & 0x1F) == 0x11 )
|
||||
SetImmData(insn.Op1, GetWord(insn), 15);
|
||||
else
|
||||
SetImmData(insn.Op1, code & 0x1F, 4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// LOADi
|
||||
case 0x02:
|
||||
insn.itype = WordFlg ? CR16_loadw : CR16_loadb;
|
||||
SetReg(insn.Op2, rR0 + Oper1);
|
||||
SetSL(insn, insn.Op1, code);
|
||||
break;
|
||||
// STORi
|
||||
case 0x3:
|
||||
insn.itype = WordFlg ? CR16_storw : CR16_storb;
|
||||
SetReg(insn.Op1, rR0 + Oper1);
|
||||
SetSL(insn, insn.Op2, code);
|
||||
break;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
357
idasdk76/module/cr16/cr16.cfg
Normal file
357
idasdk76/module/cr16/cr16.cfg
Normal file
@@ -0,0 +1,357 @@
|
||||
; The format of the input file:
|
||||
; each device definition begins with a line like this:
|
||||
;
|
||||
; .devicename
|
||||
;
|
||||
; after it go the port definitions in this format:
|
||||
;
|
||||
; portname address
|
||||
;
|
||||
; the bit definitions (optional) are represented like this:
|
||||
;
|
||||
; portname.bitname bitnumber
|
||||
;
|
||||
; lines beginning with a space are ignored.
|
||||
; comment lines should be started with ';' character.
|
||||
;
|
||||
; the default device is specified at the start of the file
|
||||
;
|
||||
; .default device_name
|
||||
;
|
||||
; all lines non conforming to the format are passed to the callback function
|
||||
;
|
||||
; NSC CompactRISC CR16 SPECIFIC LINES
|
||||
;------------------------
|
||||
;
|
||||
; the processor definition may include the memory configuration.
|
||||
; the line format is:
|
||||
|
||||
; area CLASS AREA-NAME START:END
|
||||
;
|
||||
; where CLASS is anything, but please use one of CODE, DATA, BSS
|
||||
; START and END are addresses, the end address is not included
|
||||
|
||||
; Interrupt vectors are declared in the following way:
|
||||
|
||||
; entry NAME ADDRESS COMMENT
|
||||
|
||||
.default SC14402
|
||||
|
||||
|
||||
.SC14402
|
||||
|
||||
; MEMORY MAP
|
||||
area DATA SRAM 0xEA00:0xEC00 Sequencer RAM
|
||||
area DATA IRAM 0xEC00:0xF400 Internal RAM
|
||||
area DATA DRAM 0xF400:0xFBFE Data RAM
|
||||
area DATA FSR 0xFBFE:0x10000 Special Function Register
|
||||
|
||||
; Interrupt and reset vector assignments
|
||||
interrupt RESET_ 0x0000 RESET
|
||||
interrupt NMI_ 0x0004 NMI
|
||||
interrupt TRAP_SVC_ 0x000A Trap SVC
|
||||
interrupt TRAP_DVZ_ 0x000C Trap DVZ
|
||||
interrupt TRAP_FLG_ 0x000E Trap FLG
|
||||
interrupt TRAP_BPT_ 0x0010 Trap BPT
|
||||
interrupt TRAP_TRC_ 0x0012 Trap TRC
|
||||
interrupt TRAP_UND_ 0x0014 Trap UND
|
||||
interrupt ISE_ 0x001E ISE
|
||||
interrupt IRQ0_ 0x0020 SW INT
|
||||
interrupt IRQ1_ 0x0022 Keyboard IRQ
|
||||
interrupt IRQ2_ 0x0024 UART IRQ
|
||||
interrupt IRQ3_ 0x0026 Timer 0 IRQ
|
||||
interrupt IRQ4_ 0x0028 Timer 1 IRQ
|
||||
interrupt IRQ5_ 0x002A Clk 100 IRQ
|
||||
interrupt IRQ6_ 0x002C DIP IRQ
|
||||
|
||||
; INPUT/OUTPUT
|
||||
DIPPC 0xFBFE DIP Programm Counter
|
||||
DIPCTRL 0xFBFF DIP Controll
|
||||
INTRESET 0xFF02 Reset Interrupt
|
||||
INTSET 0xFF03 Set Interrupt
|
||||
SWINTPRI 0xFF04 SW INT Priority
|
||||
KBINTPRI 0xFF05 KB INT Priority
|
||||
UARTINTPRI 0xFF06 UART INT Priority
|
||||
T0INTPRI 0xFF07 T0 INT Priority
|
||||
T1INTPRI 0xFF08 T1 INT Priority
|
||||
CLKINTPRI 0xFF09 CLK100 INT Priority
|
||||
DIPINTPRI 0xFF0A DIP INT Priority
|
||||
P0DATA 0xFF10 Port 0
|
||||
P0SET 0xFF11 Port 0 Set Bit
|
||||
P0RESET 0xFF12 Port 0 Reset Bit
|
||||
P0DIR 0xFF13 Port 0 Direction
|
||||
P0UARTCTL 0xFF14 Port 0 UART Controll
|
||||
P0UARTDATA 0xFF15 Port 0 UART Data Register
|
||||
P0ENV 0xFF16 Port 0 Environ
|
||||
P0TEST 0xFF17 Port 0 ADPCM/CODEC Testpoints
|
||||
P1DATA 0xFF20 Port 1
|
||||
P1SET 0xFF21 Port 1 Set Bit
|
||||
P1RESET 0xFF22 Port 1 Reset Bit
|
||||
P1DIR 0xFF23 Port 1 Direction
|
||||
P1INTENABLE 0xFF24 Port 1 Interrupt Enable
|
||||
P1FILTER 0xFF25 Port 1 debounce filter
|
||||
P2DATA 0xFF30 Port 2
|
||||
P2DIR 0xFF33 Port 2 Direction
|
||||
P2MODE 0xFF34 Port 2 Mode
|
||||
P2ADCCONTROLL 0xFF35 Port 2 ADC Controll
|
||||
P2ADCVALUE 0xFF36 Port 2 ADC Value
|
||||
P2DACVALUE 0xFF37 Port 2 DAC Value
|
||||
WTDG_RELOAD 0xFF40 Watchdog Reload
|
||||
T0RELOADMLO 0xFF42 Timer 0 Reload M Low
|
||||
T0RELOADMHI 0xFF43 Timer 0 Reload M Low
|
||||
T0RELOADNLO 0xFF44 Timer 0 Reload N Low
|
||||
T0RELOADNHI 0xFF45 Timer 0 Reload N Low
|
||||
T1RELOADMLO 0xFF46 Timer 1 Reload M Low
|
||||
T1RELOADMHI 0xFF47 Timer 1 Reload M Low
|
||||
T1RELOADNLO 0xFF48 Timer 1 Reload N Low
|
||||
T1RELOADNHI 0xFF49 Timer 1 Reload N Low
|
||||
TIMERCONTROLL 0xFF4A Timer Controll
|
||||
SBICLK 0xFF50 SBI Clock
|
||||
SBIBANK 0xFF51 SBI Bank
|
||||
SBIAUXCSLOW 0xFF52 SBI Aux chipselect controll low
|
||||
SBIAUXCSHIGH 0xFF53 SBI Aux chipselect controll high
|
||||
SBIAUXWAIT 0xFF54 SBI AUX Wait
|
||||
SBISETFREEZE 0xFF55 SBI Set Freeze
|
||||
SBIRESETFREEZE 0xFF56 SBI Reset Freeze
|
||||
DEBUGSFR 0xFF57 DEBUG Register
|
||||
|
||||
.CR16MCS9
|
||||
|
||||
; MEMORY MAP
|
||||
area CODE FLASH 0x0000:0xC000 Flash Program Memory
|
||||
area DATA SRAM 0xC000:0xCC00 Static RAM
|
||||
area DATA ISP 0xE000:0xE600 ISP Memory
|
||||
area DATA EEPROM 0xE800:0xF000 EEPROM
|
||||
area DATA EEPROM 0xF000:0xF080 EEPROM
|
||||
area DATA FSR 0xF400:0x10000 Peripherals
|
||||
|
||||
; Interrupt and reset vector assignments
|
||||
interrupt RESET_ 0x0000 RESET
|
||||
;interrupt NMI_ 0x0004 NMI
|
||||
;interrupt TRAP_SVC_ 0x000A Trap SVC
|
||||
;interrupt TRAP_DVZ_ 0x000C Trap DVZ
|
||||
;interrupt TRAP_FLG_ 0x000E Trap FLG
|
||||
;interrupt TRAP_BPT_ 0x0010 Trap BPT
|
||||
;interrupt TRAP_TRC_ 0x0012 Trap TRC
|
||||
;interrupt TRAP_UND_ 0x0014 Trap UND
|
||||
;interrupt ISE_ 0x001E ISE
|
||||
;interrupt IRQ0_ 0x0020 SW INT
|
||||
;interrupt IRQ1_ 0x0022 Keyboard IRQ
|
||||
;interrupt IRQ2_ 0x0024 UART IRQ
|
||||
;interrupt IRQ3_ 0x0026 Timer 0 IRQ
|
||||
;interrupt IRQ4_ 0x0028 Timer 1 IRQ
|
||||
;interrupt IRQ5_ 0x002A Clk 100 IRQ
|
||||
;interrupt IRQ6_ 0x002C DIP IRQ
|
||||
|
||||
; INPUT/OUTPUT
|
||||
BCFG 0xf900
|
||||
IOCFG 0xf902
|
||||
SZCFG0 0xf904
|
||||
SZCFG1 0xf906
|
||||
SZCFG2 0xf908
|
||||
MCFG 0xf910
|
||||
DBGCFG 0xf912
|
||||
MSTAT 0xf914
|
||||
TMODE 0xf920
|
||||
FLCTRL1 0xf930
|
||||
FLSEC 0xf932
|
||||
ISPKEY 0xf934
|
||||
FLCTRL2 0xf936
|
||||
DMCSR 0xf940
|
||||
DMPSLR 0xf942
|
||||
DMSTART 0xf944
|
||||
DMTRAN 0xf946
|
||||
DMPROG 0xf948
|
||||
DMERASE 0xf94a
|
||||
DMEND 0xf94c
|
||||
DMPCNT 0xf94e
|
||||
DMCNT 0xf950
|
||||
DMISTAT 0xf952
|
||||
DMKEY 0xf954
|
||||
FLCSR 0xf960
|
||||
FLPSLR 0xf962
|
||||
FLSTART 0xf964
|
||||
FLTRAN 0xf966
|
||||
FLPROG 0xf968
|
||||
FLERASE 0xf96a
|
||||
FLEND 0xf96c
|
||||
FLPCNT 0xf96e
|
||||
FLCNT1 0xf970
|
||||
FLCNT2 0xf972
|
||||
PGMKEY 0xf974
|
||||
PBDIR 0xfb00
|
||||
PBDIN 0xfb02
|
||||
PBDOUT 0xfb04
|
||||
PBWKPU 0xfb06
|
||||
PCDIR 0xfb10
|
||||
PCDIN 0xfb12
|
||||
PCDOUT 0xfb14
|
||||
PCWKPU 0xfb16
|
||||
PFALT 0xfd20
|
||||
PFDIR 0xfd22
|
||||
PFDIN 0xfd24
|
||||
PFDOUT 0xfd26
|
||||
PFWKPU 0xfd28
|
||||
PFSCHEN 0xfd2a
|
||||
PGALT 0xfca0
|
||||
PGDIR 0xfca2
|
||||
PGDIN 0xfca4
|
||||
PGDOUT 0xfca6
|
||||
PGWKPU 0xfca8
|
||||
PGSCHEN 0xfcaa
|
||||
PHALT 0xfcc0
|
||||
PHDIR 0xfcc2
|
||||
PHDIN 0xfcc4
|
||||
PHDOUT 0xfcc6
|
||||
PHWKPU 0xfcc8
|
||||
PIALT 0xfee0
|
||||
PIDIR 0xfee2
|
||||
PIDIN 0xfee4
|
||||
PIDOUT 0xfee6
|
||||
PIWKPU 0xfee8
|
||||
PISCHEN 0xfeea
|
||||
PLALT 0xff00
|
||||
PLDIR 0xff02
|
||||
PLDIN 0xff04
|
||||
PLDOUT 0xff06
|
||||
PLWKPU 0xff08
|
||||
PLSCHEN 0xff0a
|
||||
CRCTRL 0xfc40
|
||||
PRSSC 0xfc42
|
||||
PRSSC1 0xfc44
|
||||
PMCSR 0xfc60
|
||||
WKEDG 0xfc80
|
||||
WKENA 0xfc82
|
||||
WKICTL 0xfc84
|
||||
WKICTL2 0xfc86
|
||||
WKPND 0xfc88
|
||||
WKPCL 0xfc8a
|
||||
IVCT 0xfe00
|
||||
NMISTAT 0xfe02
|
||||
EXNMI 0xfe04
|
||||
NMIIMNTR 0xfe06
|
||||
ISTAT0 0xfe0a
|
||||
ISTAT1 0xfe0c
|
||||
IENAM0 0xfe0e
|
||||
IENAM1 0xfe10
|
||||
IDBG 0xfe1a
|
||||
ITEST0 0xfe1c
|
||||
ITEST1 0xfe1e
|
||||
U1TBUF 0xfe40
|
||||
U1RBUF 0xfe42
|
||||
U1ICTRL 0xfe44
|
||||
U1STAT 0xfe46
|
||||
U1FRS 0xfe48
|
||||
U1MDSL 0xfe4a
|
||||
U1BAUD 0xfe4c
|
||||
U1PSR 0xfe4e
|
||||
U2TBUF 0xfe80
|
||||
U2RBUF 0xfe82
|
||||
U2ICTRL 0xfe84
|
||||
U2STAT 0xfe86
|
||||
U2FRS 0xfe88
|
||||
U2MDSL 0xfe8a
|
||||
U2BAUD 0xfe8c
|
||||
U2PSR 0xfe8e
|
||||
ACBSDA 0xfec0
|
||||
ACBST 0xfec2
|
||||
ACBCST 0xfec4
|
||||
ACBCTL1 0xfec6
|
||||
ACBADDR 0xfec8
|
||||
ACBCTL2 0xfeca
|
||||
MWDAT 0xfe60
|
||||
MWCTL 0xfe62
|
||||
MWSTAT 0xfe64
|
||||
MWTEST 0xfe66
|
||||
TWCFG 0xff20
|
||||
TWCP 0xff22
|
||||
TWMT0 0xff24
|
||||
T0CSR 0xff26
|
||||
WDCNT 0xff28
|
||||
WDSDM 0xff2a
|
||||
T1CNT1 0xff40
|
||||
T1CRA 0xff42
|
||||
T1CRB 0xff44
|
||||
T1CNT2 0xff46
|
||||
T1PRSC 0xff48
|
||||
T1CKC 0xff4A
|
||||
T1CTRL 0xff4C
|
||||
T1ICTL 0xff4E
|
||||
T1ICLR 0xff50
|
||||
T2CNT1 0xff60
|
||||
T2CRA 0xff62
|
||||
T2CRB 0xff64
|
||||
T2CNT2 0xff66
|
||||
T2PRSC 0xff68
|
||||
T2CKC 0xff6A
|
||||
T2CTRL 0xff6C
|
||||
T2ICTL 0xff6E
|
||||
T2ICLR 0xff70
|
||||
MODE 0xff80
|
||||
IO1CTL 0xff82
|
||||
IO2CTL 0xff84
|
||||
INTCTL 0xff86
|
||||
INTPND 0xff88
|
||||
CLK1PS 0xff8a
|
||||
COUNT1 0xff8c
|
||||
PERCAP1 0xff8e
|
||||
DTYCAP1 0xff90
|
||||
COUNT2 0xff92
|
||||
PERCAP2 0xff94
|
||||
DTYCAP2 0xff96
|
||||
CLK2PS 0xff98
|
||||
COUNT3 0xff9a
|
||||
PERCAP3 0xff9c
|
||||
DTYCAP3 0xff9e
|
||||
COUNT4 0xffa0
|
||||
PERCAP4 0xffa2
|
||||
DTYCAP4 0xffa4
|
||||
ADCST 0xffC0
|
||||
ADCCNT1 0xffC2
|
||||
ADCCNT2 0xffC4
|
||||
ADCCNT3 0xffC6
|
||||
ADCENG 0xffC8
|
||||
ADDATA0 0xffCA
|
||||
ADDATA1 0xffCC
|
||||
ADDATA2 0xffCE
|
||||
ADDATA3 0xffD0
|
||||
ACMP 0xffe0
|
||||
CMB0_CNTSTAT 0xf400
|
||||
CMB0_TSTP 0xf402
|
||||
CMB0_DATA3 0xf404
|
||||
CMB0_DATA2 0xf406
|
||||
CMB0_DATA1 0xf408
|
||||
CMB0_DATA0 0xf40a
|
||||
CMB0_ID0 0xf40c
|
||||
CMB0_ID1 0xf40e
|
||||
CMB1 0xf410
|
||||
CMB2 0xf420
|
||||
CMB3 0xf430
|
||||
CMB4 0xf440
|
||||
CMB5 0xf450
|
||||
CMB6 0xf460
|
||||
CMB7 0xf470
|
||||
CMB8 0xf480
|
||||
CMB9 0xf490
|
||||
CMB10 0xf4a0
|
||||
CMB11 0xf4b0
|
||||
CMB12 0xf4c0
|
||||
CMB13 0xf4d0
|
||||
CMB14 0xf4e0
|
||||
CMB15 0xf4f0
|
||||
CGCR 0xf500
|
||||
CTIM 0xf502
|
||||
GMSKX 0xf504
|
||||
GMSKB 0xf506
|
||||
BMSKX 0xf508
|
||||
BMSKB 0xf50a
|
||||
CIEN 0xf50c
|
||||
CIPND 0xf50e
|
||||
CICLR 0xf510
|
||||
CICEN 0xf512
|
||||
CSTPND 0xf514
|
||||
CANEC 0xf516
|
||||
CEDIAG 0xf518
|
||||
CTMR 0xf51a
|
||||
BSPD 0xf51c
|
||||
RTDIAG 0xf51e
|
||||
64
idasdk76/module/cr16/cr16.hpp
Normal file
64
idasdk76/module/cr16/cr16.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#ifndef _CR16_HPP
|
||||
#define _CR16_HPP
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#define near
|
||||
#define far
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
// ============================================================
|
||||
// specflags1 bits
|
||||
//-----------------------------------------------
|
||||
#define URR_PAIR (0x01) // indirect reference via reg pair
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// processor registers
|
||||
enum CR16_registers
|
||||
{
|
||||
rNULLReg,
|
||||
rR0, rR1, rR2, rR3, rR4, rR5, rR6, rR7,
|
||||
rR8, rR9, rR10, rR11, rR12, rR13, rRA, rSP,
|
||||
// special registers
|
||||
rPC, rISP, rINTBASE, rPSR, rCFG, rDSR, rDCR,
|
||||
rCARL, rCARH, rINTBASEL, rINTBASEH,
|
||||
rVcs, rVds
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi CR16_ana(insn_t *_insn);
|
||||
int idaapi CR16_emu(const insn_t &insn);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct cr16_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
iohandler_t ioh = iohandler_t(helper);
|
||||
bool flow = false; // flow stop flag
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void CR16_header(outctx_t &ctx);
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload);
|
||||
int CR16_emu(const insn_t &insn);
|
||||
|
||||
void CR16_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void CR16_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ CR16"
|
||||
#define PROCMOD_NAME cr16
|
||||
|
||||
#endif
|
||||
100
idasdk76/module/cr16/emu.cpp
Normal file
100
idasdk76/module/cr16/emu.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "cr16.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// handle using/changing of operands
|
||||
void cr16_t::handle_operand(const insn_t &insn, const op_t &x, bool is_forced, bool isload)
|
||||
{
|
||||
ea_t ea;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
if ( !isload )
|
||||
goto badTouch;
|
||||
set_immd(insn.ea);
|
||||
// no break
|
||||
case o_displ:
|
||||
if ( !is_forced && op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
{
|
||||
int outf = (x.type == o_displ ? OOF_ADDR : 0)
|
||||
| OOF_SIGNED
|
||||
| (x.dtype == dt_word ? OOFW_16 : OOFW_8);
|
||||
dref_t dt = x.type == o_imm ? dr_O : isload ? dr_R : dr_W;
|
||||
ea = insn.add_off_drefs(x, dt, outf);
|
||||
if ( ea != BADADDR )
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
|
||||
// jump or call
|
||||
case o_near:
|
||||
ea = map_code_ea(insn, x);
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
// add cross-reference
|
||||
insn.add_cref(ea, x.offb, fl_CN);
|
||||
// doesn't return?
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.add_cref(ea, x.offb, fl_JN);
|
||||
}
|
||||
break;
|
||||
|
||||
// memory reference
|
||||
case o_mem:
|
||||
ea = map_data_ea(insn, x);
|
||||
insn.create_op_data(ea, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
break;
|
||||
|
||||
// other - report error
|
||||
default:
|
||||
badTouch:
|
||||
warning("%a %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// emulator
|
||||
int cr16_t::CR16_emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
|
||||
// get operand types
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
// handle reads
|
||||
if ( Feature & CF_USE1 )
|
||||
handle_operand(insn, insn.Op1, flag1, true);
|
||||
if ( Feature & CF_USE2 )
|
||||
handle_operand(insn, insn.Op2, flag2, true);
|
||||
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
// handle writes
|
||||
if ( Feature & CF_CHG1 )
|
||||
handle_operand(insn, insn.Op1, flag1, false);
|
||||
if ( Feature & CF_CHG2 )
|
||||
handle_operand(insn, insn.Op2, flag2, false);
|
||||
// if not stopping, add flow xref
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
128
idasdk76/module/cr16/ins.cpp
Normal file
128
idasdk76/module/cr16/ins.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "cr16.hpp"
|
||||
|
||||
// NB! word versions must follow byte versions
|
||||
// this is done to simplify decoding in ana.c
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 },
|
||||
{ "addb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "addw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "addub", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "adduw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "addcb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "addcw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "andb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "andw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "ashub", CF_USE1|CF_USE2|CF_CHG2|CF_SHFT },
|
||||
{ "ashuw", CF_USE1|CF_USE2|CF_CHG2|CF_SHFT },
|
||||
{ "beq", CF_USE1|CF_JUMP },
|
||||
{ "bne", CF_USE1|CF_JUMP },
|
||||
{ "bcs", CF_USE1|CF_JUMP },
|
||||
{ "bcc", CF_USE1|CF_JUMP },
|
||||
{ "bhi", CF_USE1|CF_JUMP },
|
||||
{ "bls", CF_USE1|CF_JUMP },
|
||||
{ "bgt", CF_USE1|CF_JUMP },
|
||||
{ "ble", CF_USE1|CF_JUMP },
|
||||
{ "bfs", CF_USE1|CF_JUMP },
|
||||
{ "bfc", CF_USE1|CF_JUMP },
|
||||
{ "blo", CF_USE1|CF_JUMP },
|
||||
{ "bhs", CF_USE1|CF_JUMP },
|
||||
{ "blt", CF_USE1|CF_JUMP },
|
||||
{ "bge", CF_USE1|CF_JUMP },
|
||||
{ "br", CF_USE1|CF_JUMP|CF_STOP },
|
||||
{ "bal", CF_USE1|CF_CHG1|CF_USE2|CF_CALL },
|
||||
{ "cmpb", CF_USE1|CF_USE2 },
|
||||
{ "cmpw", CF_USE1|CF_USE2 },
|
||||
{ "beq1b", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "beq1w", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "beq0b", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "beq0w", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "bne1b", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "bne1w", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "bne0b", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "bne0w", CF_USE1|CF_USE2|CF_JUMP },
|
||||
{ "di", 0 },
|
||||
{ "ei", 0 },
|
||||
{ "excp", CF_USE1 },
|
||||
{ "jeq", CF_USE1|CF_JUMP },
|
||||
{ "jne", CF_USE1|CF_JUMP },
|
||||
{ "jcs", CF_USE1|CF_JUMP },
|
||||
{ "jcc", CF_USE1|CF_JUMP },
|
||||
{ "jhi", CF_USE1|CF_JUMP },
|
||||
{ "jls", CF_USE1|CF_JUMP },
|
||||
{ "jgt", CF_USE1|CF_JUMP },
|
||||
{ "jle", CF_USE1|CF_JUMP },
|
||||
{ "jfs", CF_USE1|CF_JUMP },
|
||||
{ "jfc", CF_USE1|CF_JUMP },
|
||||
{ "jlo", CF_USE1|CF_JUMP },
|
||||
{ "jhs", CF_USE1|CF_JUMP },
|
||||
{ "jlt", CF_USE1|CF_JUMP },
|
||||
{ "jge", CF_USE1|CF_JUMP },
|
||||
{ "jump", CF_USE1|CF_JUMP|CF_STOP },
|
||||
{ "jal", CF_USE1|CF_CHG1|CF_USE2|CF_CALL },
|
||||
{ "loadb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "loadw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "loadm", CF_USE1 },
|
||||
{ "lpr", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "lshb", CF_USE1|CF_USE2|CF_CHG2|CF_SHFT },
|
||||
{ "lshw", CF_USE1|CF_USE2|CF_CHG2|CF_SHFT },
|
||||
{ "movb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "movw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "movxb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "movzb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "movd", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "mulb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "mulw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "mulsb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "mulsw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "muluw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "nop", 0 },
|
||||
{ "orb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "orw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "push", CF_USE1|CF_USE2 },
|
||||
{ "pop", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "popret", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "retx", CF_STOP },
|
||||
{ "seq", CF_USE1|CF_CHG1 },
|
||||
{ "sne", CF_USE1|CF_CHG1 },
|
||||
{ "scs", CF_USE1|CF_CHG1 },
|
||||
{ "scc", CF_USE1|CF_CHG1 },
|
||||
{ "shi", CF_USE1|CF_CHG1 },
|
||||
{ "sls", CF_USE1|CF_CHG1 },
|
||||
{ "sgt", CF_USE1|CF_CHG1 },
|
||||
{ "sle", CF_USE1|CF_CHG1 },
|
||||
{ "sfs", CF_USE1|CF_CHG1 },
|
||||
{ "sfc", CF_USE1|CF_CHG1 },
|
||||
{ "slo", CF_USE1|CF_CHG1 },
|
||||
{ "shs", CF_USE1|CF_CHG1 },
|
||||
{ "slt", CF_USE1|CF_CHG1 },
|
||||
{ "sge", CF_USE1|CF_CHG1 },
|
||||
{ "spr", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "storb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "storw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "storm", CF_USE1 },
|
||||
{ "subb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "subw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "subcb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "subcw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "tbit", CF_USE1|CF_USE2 },
|
||||
{ "tbitb", CF_USE1|CF_USE2 },
|
||||
{ "tbitw", CF_USE1|CF_USE2 },
|
||||
{ "sbitb", CF_USE1|CF_USE2 },
|
||||
{ "sbitw", CF_USE1|CF_USE2 },
|
||||
{ "cbitb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "cbitw", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "wait", 0 },
|
||||
{ "eiwait", 0 },
|
||||
{ "xorb", CF_USE1|CF_USE2|CF_CHG2 },
|
||||
{ "xorw", CF_USE1|CF_USE2|CF_CHG2 }
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == CR16_last);
|
||||
136
idasdk76/module/cr16/ins.hpp
Normal file
136
idasdk76/module/cr16/ins.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
// list of instructions
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
CR16_null = 0, // Unknown Operation
|
||||
CR16_addb,
|
||||
CR16_addw,
|
||||
CR16_addub,
|
||||
CR16_adduw,
|
||||
CR16_addcb,
|
||||
CR16_addcw,
|
||||
CR16_andb,
|
||||
CR16_andw,
|
||||
CR16_ashub,
|
||||
CR16_ashuw,
|
||||
// !!! don't change sequence !!!
|
||||
CR16_beq,
|
||||
CR16_bne,
|
||||
CR16_bcs,
|
||||
CR16_bcc,
|
||||
CR16_bhi,
|
||||
CR16_bls,
|
||||
CR16_bgt,
|
||||
CR16_ble,
|
||||
CR16_bfs,
|
||||
CR16_bfc,
|
||||
CR16_blo,
|
||||
CR16_bhs,
|
||||
CR16_blt,
|
||||
CR16_bge,
|
||||
CR16_br,
|
||||
//----------------------------
|
||||
CR16_bal,
|
||||
CR16_cmpb,
|
||||
CR16_cmpw,
|
||||
CR16_beq1b,
|
||||
CR16_beq1w,
|
||||
CR16_beq0b,
|
||||
CR16_beq0w,
|
||||
CR16_bne1b,
|
||||
CR16_bne1w,
|
||||
CR16_bne0b,
|
||||
CR16_bne0w,
|
||||
CR16_di,
|
||||
CR16_ei,
|
||||
CR16_excp,
|
||||
// !!! don't change sequence !!!
|
||||
CR16_jeq,
|
||||
CR16_jne,
|
||||
CR16_jcs,
|
||||
CR16_jcc,
|
||||
CR16_jhi,
|
||||
CR16_jls,
|
||||
CR16_jgt,
|
||||
CR16_jle,
|
||||
CR16_jfs,
|
||||
CR16_jfc,
|
||||
CR16_jlo,
|
||||
CR16_jhs,
|
||||
CR16_jlt,
|
||||
CR16_jge,
|
||||
CR16_jump,
|
||||
//----------------------------
|
||||
CR16_jal,
|
||||
CR16_loadb,
|
||||
CR16_loadw,
|
||||
CR16_loadm,
|
||||
CR16_lpr,
|
||||
CR16_lshb,
|
||||
CR16_lshw,
|
||||
CR16_movb,
|
||||
CR16_movw,
|
||||
CR16_movxb,
|
||||
CR16_movzb,
|
||||
CR16_movd,
|
||||
CR16_mulb,
|
||||
CR16_mulw,
|
||||
CR16_mulsb,
|
||||
CR16_mulsw,
|
||||
CR16_muluw,
|
||||
CR16_nop,
|
||||
CR16_orb,
|
||||
CR16_orw,
|
||||
CR16_push,
|
||||
CR16_pop,
|
||||
CR16_popret,
|
||||
CR16_retx,
|
||||
// !!! don't change sequence !!!
|
||||
CR16_seq,
|
||||
CR16_sne,
|
||||
CR16_scs,
|
||||
CR16_scc,
|
||||
CR16_shi,
|
||||
CR16_sls,
|
||||
CR16_sgt,
|
||||
CR16_sle,
|
||||
CR16_sfs,
|
||||
CR16_sfc,
|
||||
CR16_slo,
|
||||
CR16_shs,
|
||||
CR16_slt,
|
||||
CR16_sge,
|
||||
//----------------------------
|
||||
CR16_spr,
|
||||
CR16_storb,
|
||||
CR16_storw,
|
||||
CR16_storm,
|
||||
CR16_subb,
|
||||
CR16_subw,
|
||||
CR16_subcb,
|
||||
CR16_subcw,
|
||||
CR16_tbit,
|
||||
CR16_tbitb,
|
||||
CR16_tbitw,
|
||||
CR16_sbitb,
|
||||
CR16_sbitw,
|
||||
CR16_cbitb,
|
||||
CR16_cbitw,
|
||||
CR16_wait,
|
||||
CR16_eiwait,
|
||||
CR16_xorb,
|
||||
CR16_xorw,
|
||||
CR16_last
|
||||
};
|
||||
|
||||
#endif
|
||||
57
idasdk76/module/cr16/makefile
Normal file
57
idasdk76/module/cr16/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=cr16
|
||||
CONFIGS=cr16.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)ieee.h $(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 cr16.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)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(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 \
|
||||
cr16.hpp emu.cpp 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)ieee.h $(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 \
|
||||
cr16.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)ieee.h $(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 \
|
||||
cr16.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)ieee.h $(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 cr16.hpp ins.hpp reg.cpp
|
||||
195
idasdk76/module/cr16/out.cpp
Normal file
195
idasdk76/module/cr16/out.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "cr16.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_CR16_t : public outctx_t
|
||||
{
|
||||
out_CR16_t(void) = delete; // not used
|
||||
public:
|
||||
void OutVarName(const op_t &x);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_CR16_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_CR16_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_CR16_t::OutVarName(const op_t &x)
|
||||
{
|
||||
ea_t toea = map_code_ea(insn, x);
|
||||
|
||||
if ( !out_name_expr(x, toea, x.addr) )
|
||||
{
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// output one operand
|
||||
bool out_CR16_t::out_operand(const op_t &x)
|
||||
{
|
||||
int flags;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_displ:
|
||||
flags = OOF_ADDR | OOF_SIGNED | (x.dtype == dt_word ? OOFW_16 : OOFW_8);
|
||||
out_value(x, flags);
|
||||
out_symbol('(');
|
||||
if ( x.specflag1 & URR_PAIR )
|
||||
{
|
||||
out_register(ph.reg_names[x.reg + 1]);
|
||||
out_symbol(',');
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
}
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
case o_reg:
|
||||
if ( x.specflag1 & URR_PAIR )
|
||||
{
|
||||
out_symbol('(');
|
||||
out_register(ph.reg_names[x.reg + 1]);
|
||||
out_symbol(',');
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
out_symbol(')');
|
||||
}
|
||||
else
|
||||
{
|
||||
out_register(ph.reg_names[x.reg]);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('$');
|
||||
flags = /*OOFS_NOSIGN | OOF_SIGNED | */OOFW_IMM;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case CR16_addb:
|
||||
case CR16_addw:
|
||||
case CR16_addub:
|
||||
case CR16_adduw:
|
||||
case CR16_addcb:
|
||||
case CR16_addcw:
|
||||
case CR16_ashub:
|
||||
case CR16_ashuw:
|
||||
case CR16_lshb:
|
||||
case CR16_lshw:
|
||||
flags |= OOF_SIGNED;
|
||||
break;
|
||||
}
|
||||
out_value(x, flags);
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
OutVarName(x);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
OutVarName(x);
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// main output function
|
||||
void out_CR16_t::out_insn(void)
|
||||
{
|
||||
// print mnemonic
|
||||
out_mnemonic();
|
||||
|
||||
// print first operand
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_one_operand(0);
|
||||
|
||||
// print second operand
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// header of the listing
|
||||
void cr16_t::CR16_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, ioh.device.c_str(), ioh.deviceparams.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// segment start
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void cr16_t::CR16_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
const char *SegType = Sarea->type == SEG_CODE ? "CSEG"
|
||||
: Sarea->type == SEG_DATA ? "DSEG"
|
||||
: "RSEG";
|
||||
// print RSEG <NAME>
|
||||
qstring sn;
|
||||
|
||||
get_visible_segm_name(&sn, Sarea);
|
||||
ctx.gen_printf(-1, "%s %s ", SegType, sn.c_str());
|
||||
// if offset not zero, print it (ORG XXXX)
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
ea_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
|
||||
if ( org != 0 )
|
||||
{
|
||||
char bufn[MAX_NUMBUF];
|
||||
btoa(bufn, sizeof(bufn), org);
|
||||
ctx.gen_printf(-1, "%s %s", ash.origin, bufn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// end of listing
|
||||
void cr16_t::CR16_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 )
|
||||
{
|
||||
size_t i = strlen(ash.end);
|
||||
do
|
||||
ctx.out_char(' ');
|
||||
while ( ++i < 8 );
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
254
idasdk76/module/cr16/reg.cpp
Normal file
254
idasdk76/module/cr16/reg.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
|
||||
/*
|
||||
* National Semiconductor Corporation CR16 processor module for IDA.
|
||||
* Copyright (c) 2002-2006 Konstantin Norvatoff, <konnor@bk.ru>
|
||||
* Freeware.
|
||||
*/
|
||||
|
||||
#include "cr16.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <segregs.hpp>
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// list of registers
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
// empty
|
||||
"",
|
||||
// general purpose
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "ra", "sp",
|
||||
// special
|
||||
"pc", "isp", "intbase", "psr", "cfg", "dsr", "dcr", "carl", "carh",
|
||||
"intbaseh", "intbasel",
|
||||
|
||||
// pseudo segments
|
||||
"cs", "ds"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void cr16_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(cr16_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ssize_t idaapi cr16_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_be(false);
|
||||
inf_set_gen_lzero(true);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
// ask for a processor from the config file
|
||||
// use it to handle ports and registers
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgfile, &cb) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
{
|
||||
segment_t *s = va_arg(va, segment_t *);
|
||||
// Set default value of DS register for all segments
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
CR16_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
CR16_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 *);
|
||||
CR16_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return CR16_ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return CR16_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;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// PseudoSam
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t pseudosam =
|
||||
{
|
||||
AS_COLON | AS_UDATA | ASH_HEXF3 | ASD_DECF0,
|
||||
// user flags
|
||||
0,
|
||||
"Generic CR16 assembler", // title
|
||||
0, // help id
|
||||
NULL, // header
|
||||
"org", // ORG directive
|
||||
"end", // end directive
|
||||
|
||||
";", // comment
|
||||
'"', // string delimiter
|
||||
'\'', // character constant
|
||||
"\\\"'", // special characters
|
||||
|
||||
"db", // 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
|
||||
"#d dup(#v)", // arrays (#h,#d,#v,#s(...)
|
||||
"db ?", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // seg prefix
|
||||
"$", // current IP (instruction pointer) symbol in assembler
|
||||
NULL, // Generate function header lines
|
||||
NULL, // Generate function footer lines
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // Get name of type of item at ea or id
|
||||
".ALIGN", // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
// list of assemblers
|
||||
static const asm_t *const asms[] = { &pseudosam, NULL };
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "NSC CR16:"
|
||||
|
||||
// short names
|
||||
static const char *const shnames[] = { "CR16", NULL };
|
||||
|
||||
// long names
|
||||
static const char *const lnames[] = { FAMILY"NSC CR16", NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// return instructions
|
||||
static const uchar retcode_1[] = { 0x00, 0x0B }; // RTS
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_CR16, // processor ID
|
||||
// flag
|
||||
PR_USE32
|
||||
| PR_BINMEM
|
||||
| PR_SEGTRANS,
|
||||
// flag2
|
||||
0,
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for data segments
|
||||
|
||||
shnames, // short processor names (NULL terminated)
|
||||
lnames, // long processor names (NULL terminated)
|
||||
|
||||
asms, // assemblers
|
||||
|
||||
notify, // Event notification handler
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs, rVds,
|
||||
2, // size of a segment register
|
||||
rVcs, rVds,
|
||||
NULL, // Array of typical code start sequences
|
||||
retcodes, // Array of 'return' instruction opcodes
|
||||
0, CR16_last, // icode of the first and the last instruction
|
||||
Instructions, // instruc
|
||||
3, // Size of long double (tbyte) for this processor - 24 bits
|
||||
{0, 0, 0, 0}, // Number of digits in floating numbers after the decimal point
|
||||
0, // Icode of return instruction
|
||||
NULL, // micro virtual mashine
|
||||
};
|
||||
2945
idasdk76/module/dsp56k/ana.cpp
Normal file
2945
idasdk76/module/dsp56k/ana.cpp
Normal file
File diff suppressed because it is too large
Load Diff
64
idasdk76/module/dsp56k/dsp561xx.cfg
Normal file
64
idasdk76/module/dsp56k/dsp561xx.cfg
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
; This file describes the standard addresses for Motorola DSP561xx
|
||||
|
||||
.default 561xx
|
||||
|
||||
entry HRESET 0x0000 Hardware RESET
|
||||
entry ILLEGAL 0x0002 Illegal Instruction
|
||||
entry STACKERROR 0x0004 Stack Error
|
||||
entry SWI 0x0008 Software Interrupt
|
||||
entry IRQA 0x000A IRQA
|
||||
entry IRQB 0x000C IRQB
|
||||
entry SSI0RxwExcept 0x0010 SSI0 Receive Data with Exception
|
||||
entry SSI0Rx 0x0012 SSI0 Receive Data
|
||||
entry SSI0TxwExcept 0x0014 SSI0 Transmit Data with Exception
|
||||
entry SSI0Tx 0x0016 SSI0 Transmit Data
|
||||
entry SSI1RxwExcept 0x0018 SSI1 Receive Data with Exception
|
||||
entry SSI1Rx 0x001A SSI1 Receive Data
|
||||
entry SSI1TxwExcept 0x001C SSI1 Transmit Data with Exception
|
||||
entry SSI1Tx 0x001E SSI1 Transmit Data
|
||||
entry TimerOVF 0x0020 Timer Overflow
|
||||
entry TimerCMP 0x0022 Timer Compare
|
||||
entry HostDMARx 0x0024 Host DMA Receive Data
|
||||
entry HostDMATx 0x0026 Host DMA Transmit Data
|
||||
entry HostRx 0x0028 Host Receive Data
|
||||
entry HostTx 0x002A Host Transmit Data
|
||||
entry HostCMD 0x002C Host Command (default)
|
||||
entry CodecTxRx 0x002E Codec Receive/Transmit
|
||||
|
||||
.561xx
|
||||
PBC 0xFFC0
|
||||
PCC 0xFFC1
|
||||
PBDD 0xFFC2
|
||||
PCDD 0xFFC3
|
||||
HCR 0xFFC4
|
||||
COCR 0xFFC8
|
||||
CRASSI0 0xFFD0
|
||||
CRBSSI0 0xFFD1
|
||||
CRASSI1 0xFFD8
|
||||
CRBSSI1 0xFFD9
|
||||
PLCR 0xFFDC
|
||||
BCR 0xFFDE
|
||||
IPR 0xFFDF
|
||||
PBD 0xFFE2
|
||||
PCD 0xFFE3
|
||||
HSR 0xFFE4
|
||||
HTXRX 0xFFE5
|
||||
COSR 0xFFE9
|
||||
CRXTX 0xFFEA
|
||||
TCR 0xFFEC
|
||||
TCTR 0xFFED
|
||||
TCPR 0xFFEE
|
||||
TPR 0xFFEF
|
||||
SRSSI0 0xFFF0
|
||||
TXRXSSI0 0xFFF1
|
||||
RSMA0 0xFFF2
|
||||
RSMB0 0xFFF3
|
||||
TSMA0 0xFFF4
|
||||
TSMB0 0xFFF5
|
||||
SRSSI1 0xFFF8
|
||||
TXRXSSI1 0xFFF9
|
||||
RSMA1 0xFFFA
|
||||
RSMB1 0xFFFB
|
||||
TSMA1 0xFFFC
|
||||
TSMB1 0xFFFD
|
||||
169
idasdk76/module/dsp56k/dsp563xx.cfg
Normal file
169
idasdk76/module/dsp56k/dsp563xx.cfg
Normal file
@@ -0,0 +1,169 @@
|
||||
|
||||
; This file describes the standard addresses for Motorola DSP563xx
|
||||
|
||||
.default 56301
|
||||
|
||||
entry HRESET 0x0000 Hardware RESET
|
||||
entry STKERR 0x0002 Stack Error
|
||||
entry ILLEGAL 0x0004 Illegal Instruction
|
||||
entry DEBUG 0x0006 Debug Request Interrupt
|
||||
entry TRAP 0x0008 Trap
|
||||
entry NMI 0x000A Non-Maskable Interrupt
|
||||
entry IRQA 0x0010 IRQA
|
||||
entry IRQB 0x0012 IRQB
|
||||
entry IRQC 0x0014 IRQC
|
||||
entry IRQD 0x0016 IRQD
|
||||
entry DMA0 0x0018 DMA Channel 0
|
||||
entry DMA1 0x001A DMA Channel 1
|
||||
entry DMA2 0x001C DMA Channel 2
|
||||
entry DMA3 0x001E DMA Channel 3
|
||||
entry DMA4 0x0020 DMA Channel 4
|
||||
entry DMA5 0x0022 DMA Channel 5
|
||||
entry TIMER0CMP 0x0024 TIMER 0 compare
|
||||
entry TIMER0OWL 0x0026 TIMER 0 overflow
|
||||
entry TIMER1CMP 0x0028 TIMER 1 compare
|
||||
entry TIMER1OWL 0x002A TIMER 1 overflow
|
||||
entry TIMER2CMP 0x002C TIMER 2 compare
|
||||
entry TIMER2OWL 0x002E TIMER 2 overflow
|
||||
entry ESSI0Rxd 0x0030 ESSI0 receive data
|
||||
entry ESSI0RxdwExcept 0x0032 ESSI0 receive data with exception status
|
||||
entry ESSI0RxdLL 0x0034 ESSI0 receive last slot
|
||||
entry ESSI0Txd 0x0036 ESSI0 transmit data
|
||||
entry ESSI0TxdwExcept 0x0038 ESSI0 transmit data with exception status
|
||||
entry ESSI0TxdLL 0x003A ESSI0 transmit last slot
|
||||
entry ESSI1Rxd 0x0040 ESSI1 receive data
|
||||
entry ESSI1RxdwExcept 0x0042 ESSI1 receive data with exception status
|
||||
entry ESSI1RxdLL 0x0044 ESSI1 receive last slot
|
||||
entry ESSI1Txd 0x0046 ESSI1 transmit data
|
||||
entry ESSI1TxdwExcept 0x0048 ESSI1 transmit data with exception status
|
||||
entry ESSI1TxdLL 0x004A ESSI1 transmit last slot
|
||||
entry SCIRxData 0x0050 SCI receive data
|
||||
entry SCIRxDatawExcept 0x0052 SCI receive data with exception status
|
||||
entry SCITxData 0x0054 SCI transmit data
|
||||
entry SCIidle 0x0056 SCI idle line
|
||||
entry SCItimer 0x0058 SCI timer
|
||||
entry HostPCITransTerm 0x0060 Host PCI transaction termination
|
||||
entry HostPCITransAbort 0x0062 Host PCI transaction abort
|
||||
entry HostPCIP_error 0x0064 Host PCI parity error
|
||||
entry HostPCITransCompl 0x0066 Host PCI transfer complete
|
||||
entry HostPCIMasterRcvReq 0x0068 Host PCI master receive request
|
||||
entry HostSlaveRcvReq 0x006A Host slave receive request
|
||||
entry HostPCIMasterTrxReq 0x006C Host PCI master transmit request
|
||||
entry HostSlaveTrxReq 0x006E Host slave transmit request
|
||||
entry HostPCIMasterAddrReq 0x0070 Host PCI master address request
|
||||
entry HostCommand 0x0072 Host command
|
||||
|
||||
IPRC 0xFFFFFF
|
||||
IPRP 0xFFFFFE
|
||||
PLLCTL 0xFFFFFD
|
||||
OGDB 0xFFFFFC
|
||||
BCR 0xFFFFFB
|
||||
DCR 0xFFFFFA
|
||||
AAR0 0xFFFFF9
|
||||
AAR1 0xFFFFF8
|
||||
AAR2 0xFFFFF7
|
||||
AAR3 0xFFFFF6
|
||||
IDR 0xFFFFF5
|
||||
DSTR 0xFFFFF4
|
||||
DOR0 0xFFFFF3
|
||||
DOR1 0xFFFFF2
|
||||
DOR2 0xFFFFF1
|
||||
DOR3 0xFFFFF0
|
||||
DSR0 0xFFFFEF
|
||||
DDR0 0xFFFFEE
|
||||
DCO0 0xFFFFED
|
||||
DCR0 0xFFFFEC
|
||||
DSR1 0xFFFFEB
|
||||
DDR1 0xFFFFEA
|
||||
DCO1 0xFFFFE9
|
||||
DCR1 0xFFFFE8
|
||||
DSR2 0xFFFFE7
|
||||
DDR2 0xFFFFE6
|
||||
DCO2 0xFFFFE5
|
||||
DCR2 0xFFFFE4
|
||||
DSR3 0xFFFFE3
|
||||
DDR3 0xFFFFE2
|
||||
DCO3 0xFFFFE1
|
||||
DCR3 0xFFFFE0
|
||||
DSR4 0xFFFFDF
|
||||
DDR4 0xFFFFDE
|
||||
DCO4 0xFFFFDD
|
||||
DCR4 0xFFFFDC
|
||||
DSR5 0xFFFFDB
|
||||
DDR5 0xFFFFDA
|
||||
DCO5 0xFFFFD9
|
||||
DCR5 0xFFFFD8
|
||||
DATH 0xFFFFCF
|
||||
DIRH 0xFFFFCE
|
||||
DTXS 0xFFFFCD
|
||||
DTXM 0xFFFFCC
|
||||
DRXR 0xFFFFCB
|
||||
DPSR 0xFFFFCA
|
||||
DSR 0xFFFFC9
|
||||
DPAR 0xFFFFC8
|
||||
DPMC 0xFFFFC7
|
||||
DPCR 0xFFFFC6
|
||||
DCTR 0xFFFFC5
|
||||
PCRC 0xFFFFBF
|
||||
PRRC 0xFFFFBE
|
||||
PDRC 0xFFFFBD
|
||||
TX00 0xFFFFBC
|
||||
TX01 0xFFFFBB
|
||||
TX02 0xFFFFBA
|
||||
TSR0 0xFFFFB9
|
||||
RX0 0xFFFFB8
|
||||
SSISR0 0xFFFFB7
|
||||
CRB0 0xFFFFB6
|
||||
CRA0 0xFFFFB5
|
||||
TSMA0 0xFFFFB4
|
||||
TSMB0 0xFFFFB3
|
||||
RSMA0 0xFFFFB2
|
||||
RSMB0 0xFFFFB1
|
||||
PCRD 0xFFFFAF
|
||||
PRRD 0xFFFFAE
|
||||
PDRD 0xFFFFAD
|
||||
TX10 0xFFFFAC
|
||||
TX11 0xFFFFAB
|
||||
TX12 0xFFFFAA
|
||||
TSR1 0xFFFFA9
|
||||
RX1 0xFFFFA8
|
||||
SSISR1 0xFFFFA7
|
||||
CRB1 0xFFFFA6
|
||||
CRA1 0xFFFFA5
|
||||
TSMA1 0xFFFFA4
|
||||
TSMB1 0xFFFFA3
|
||||
RSMA1 0xFFFFA2
|
||||
RSMB1 0xFFFFA1
|
||||
PCRE 0xFFFF9F
|
||||
PRRE 0xFFFF9E
|
||||
PDRE 0xFFFF9D
|
||||
SCR 0xFFFF9C
|
||||
SCCR 0xFFFF9B
|
||||
SRXH 0xFFFF9A
|
||||
SRXM 0xFFFF99
|
||||
SRXL 0xFFFF98
|
||||
STXH 0xFFFF97
|
||||
STXM 0xFFFF96
|
||||
STXL 0xFFFF95
|
||||
STXA 0xFFFF94
|
||||
SSR 0xFFFF93
|
||||
TCSR0 0xFFFF8F
|
||||
TLR0 0xFFFF8E
|
||||
TCPR0 0xFFFF8D
|
||||
TCR0 0xFFFF8C
|
||||
TCSR1 0xFFFF8B
|
||||
TLR1 0xFFFF8A
|
||||
TCPR1 0xFFFF89
|
||||
TCR1 0xFFFF88
|
||||
TCSR2 0xFFFF87
|
||||
TLR2 0xFFFF86
|
||||
TCPR2 0xFFFF85
|
||||
TCR2 0xFFFF84
|
||||
TPLR 0xFFFF83
|
||||
TPCR 0xFFFF82
|
||||
|
||||
.56301
|
||||
|
||||
XMEMSIZE = 0x20000
|
||||
YMEMSIZE = 0x20000
|
||||
|
||||
45
idasdk76/module/dsp56k/dsp566xx.cfg
Normal file
45
idasdk76/module/dsp56k/dsp566xx.cfg
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
; This file describes the standard addresses for Motorola DSP566xx
|
||||
|
||||
.default 56600
|
||||
|
||||
entry HRESET 0x0000 Hardware RESET
|
||||
entry STKERR 0x0002 Stack Error
|
||||
entry ILLEGAL 0x0004 Illegal Instruction
|
||||
entry DEBUG 0x0006 Debug Request Interrupt
|
||||
entry TRAP 0x0008 Trap
|
||||
entry NMI 0x000A Non-Maskable Interrupt
|
||||
entry IRQA 0x0010 IRQA
|
||||
entry IRQB 0x0012 IRQB
|
||||
entry IRQC 0x0014 IRQC
|
||||
entry IRQD 0x0016 IRQD
|
||||
entry DMA0 0x0018 DMA Channel 0
|
||||
entry DMA1 0x001A DMA Channel 1
|
||||
entry DMA2 0x001C DMA Channel 2
|
||||
entry DMA3 0x001E DMA Channel 3
|
||||
entry DMA4 0x0020 DMA Channel 4
|
||||
entry DMA5 0x0022 DMA Channel 5
|
||||
|
||||
IPRC 0xFFFF Interrupt Priority Register-Core
|
||||
IPRP 0xFFFE Interrupt Priority Register Peripheral
|
||||
PCTL0 0xFFFD PLL Control Register 0
|
||||
PCTL1 0xFFFC PLL Control Register 1
|
||||
OGDB 0xFFFB ONCE GDB Register
|
||||
BCR 0xFFFA Bus Control Register
|
||||
IDR 0xFFF9 ID Register
|
||||
PAR0 0xFFF8 Patch 0 Register
|
||||
PAR1 0xFFF7 Patch 1 Register
|
||||
PAR2 0xFFF6 Patch 2 Register
|
||||
PAR3 0xFFF5 Patch 3 Register
|
||||
BPMRG 0xFFF4 BPMRG (24 bits)
|
||||
BPMRL 0xFFF3 BPMRL (16 bits)
|
||||
BPMRH 0xFFF2 BPMRH (16 bits)
|
||||
|
||||
XMEMSIZE = 0x10000
|
||||
YMEMSIZE = 0x10000
|
||||
|
||||
.56600
|
||||
|
||||
; no .56600 specific parameters are specified yet
|
||||
|
||||
|
||||
58
idasdk76/module/dsp56k/dsp56k.cfg
Normal file
58
idasdk76/module/dsp56k/dsp56k.cfg
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
; This file describes the standard addresses for Motorola DSP56K
|
||||
|
||||
.default 56000x
|
||||
|
||||
entry HRESET 0x0000 Hardware RESET
|
||||
entry STKERR 0x0002 Stack Error
|
||||
entry TRACE 0x0004 Trace
|
||||
entry SWI 0x0006 SWI
|
||||
entry IRQA 0x0008 IRQA
|
||||
entry IRQB 0x000A IRQB
|
||||
entry SSIRD 0x000C SSI Receive Data
|
||||
entry SSIRDEXP 0x000E SSI Receive Data with Exception Status
|
||||
entry SSITD 0x0010 SSI Transmit Data
|
||||
entry SSITDEXP 0x0012 SSI Transmit Data with Exception Status
|
||||
entry SCIRD 0x0014 SCI Receive Data
|
||||
entry SCIRDEXP 0x0016 SCI Receive Data with Exception Status
|
||||
entry SCITD 0x0018 SCI Transmit Data
|
||||
entry SCIIDLE 0x001A SCI Idle Line
|
||||
entry SCITIMER 0x001C SCI Timer
|
||||
entry NMI 0x001E NMI
|
||||
entry HRDATA 0x0020 Host Receive Data
|
||||
entry HTDATA 0x0022 Host Transmit Data
|
||||
entry HCMD 0x0024 Host Command (default)
|
||||
entry TIMER 0x003C Timer
|
||||
entry ILLINST 0x003E Illegal Instruction
|
||||
|
||||
IPR 0xFFFF
|
||||
BCR 0xFFFE
|
||||
PLLCTL 0xFFFD
|
||||
GDB 0xFFFC
|
||||
SCI_HI 0xFFF6
|
||||
SCI_MID 0xFFF5
|
||||
SCI_LOW 0xFFF4
|
||||
STXA 0xFFF3
|
||||
SCCR 0xFFF2
|
||||
SSR 0xFFF1
|
||||
SCR 0xFFF0
|
||||
SSI_RXTX 0xFFEF
|
||||
SSISR 0xFFEE
|
||||
CRB 0xFFED
|
||||
CRA 0xFFEC
|
||||
HRTX 0xFFEB
|
||||
HSR 0xFFE9
|
||||
HCR 0xFFE8
|
||||
PCD 0xFFE5
|
||||
PBD 0xFFE4
|
||||
PCDDR 0xFFE3
|
||||
PBDDR 0xFFE2
|
||||
PCC 0xFFE1
|
||||
PBC 0xFFE0
|
||||
TCR 0xFFDF
|
||||
TCSR 0xFFDE
|
||||
|
||||
.56000x
|
||||
|
||||
XMEMSIZE = 0x10000
|
||||
YMEMSIZE = 0x10000
|
||||
348
idasdk76/module/dsp56k/dsp56k.hpp
Normal file
348
idasdk76/module/dsp56k/dsp56k.hpp
Normal file
@@ -0,0 +1,348 @@
|
||||
|
||||
#ifndef _DSP56K_HPP
|
||||
#define _DSP56K_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
#define PROCMOD_NAME dsp56k
|
||||
#define PROCMOD_NODE_NAME "$ " QSTRINGIZE(PROCMOD_NAME)
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// DSP56K instruction may have many operands. We keep them separately
|
||||
// in the following structure.
|
||||
|
||||
struct addargs_t
|
||||
{
|
||||
ea_t ea;
|
||||
int nargs;
|
||||
op_t args[4][2];
|
||||
|
||||
addargs_t() : ea(BADADDR), nargs(0) { memset(args, 0, sizeof(args)); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct dsp56k_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct dsp56k_t ±
|
||||
dsp56k_iohandler_t(dsp56k_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line) override;
|
||||
};
|
||||
|
||||
struct dsp56k_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
dsp56k_iohandler_t ioh = dsp56k_iohandler_t(*this, helper);
|
||||
ea_t xmem = BADADDR;
|
||||
ea_t ymem = BADADDR;
|
||||
op_t *op = nullptr; // current operand
|
||||
addargs_t aa;
|
||||
int xmemsize = 0x10000;
|
||||
int ymemsize = 0x10000;
|
||||
int procnum = -1; // 0 - dsp56k, 1 - dsp561xx, 2 - dsp563xx, 3 - dsp566xx
|
||||
bool flow = false;
|
||||
|
||||
inline bool is561xx(void) const { return procnum == 1; }
|
||||
inline bool is563xx(void) const { return procnum == 2; }
|
||||
inline bool is566xx(void) const { return procnum == 3; }
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
const ioport_t *find_port(ea_t address);
|
||||
void create_xmem_ymem(void);
|
||||
void select_device(const char *dname, int resp_info);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/);
|
||||
ea_t calc_mem(const insn_t &insn, const op_t &x) const;
|
||||
ea_t AdditionalSegment(asize_t size, int offset, const char *name) const;
|
||||
void handle_operand(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
flags_t F,
|
||||
bool is_forced,
|
||||
bool isload);
|
||||
int emu(const insn_t &insn);
|
||||
void header(outctx_t &ctx);
|
||||
void set_cpu(int procno);
|
||||
bool D_EE(insn_t &insn, int value);
|
||||
bool D_DDDDD(insn_t &insn, int value);
|
||||
bool D_ff(const insn_t &insn, int value, int reg_bank);
|
||||
bool D_df(insn_t &insn, int value, int reg_bank);
|
||||
bool S_xi(insn_t &, int value);
|
||||
bool D_ximm(insn_t &insn, int /*value*/);
|
||||
bool S_ximm(insn_t &insn, int value);
|
||||
bool S_sssss(insn_t &, int value);
|
||||
bool S_ssss(insn_t &, int value);
|
||||
bool D_xih(insn_t &, int value);
|
||||
bool S_xih(insn_t &insn, int value);
|
||||
bool SD_d(insn_t &insn, int value);
|
||||
bool SS_JJJd(insn_t &insn, int value);
|
||||
bool SD_JJJd(insn_t &insn, int value);
|
||||
bool SD_Jd(insn_t &insn, int value);
|
||||
bool D_d(insn_t &insn, int value);
|
||||
bool S_S(insn_t &insn, int value);
|
||||
bool SD_JJd(insn_t &insn, int value);
|
||||
bool D_dddd(insn_t &insn, int value);
|
||||
bool D_ddddd(insn_t &insn, int value);
|
||||
bool S_ddddd(insn_t &insn, int value);
|
||||
bool D_LLL(insn_t &insn, int value);
|
||||
bool D_sss(insn_t &insn, int value);
|
||||
bool S_sss(insn_t &insn, int value);
|
||||
bool D_qqq(insn_t &insn, int value);
|
||||
bool S_qqq(insn_t &insn, int value);
|
||||
bool S_qq(insn_t &insn, int value);
|
||||
bool S_QQ(insn_t &insn, int value);
|
||||
bool S_gggd(insn_t &insn, int value);
|
||||
bool D_MMRRR(insn_t &, int value);
|
||||
bool S_MMRRR(insn_t &insn, int value);
|
||||
bool D_MMRRR_XY(insn_t &, int value);
|
||||
bool D_pppppp(insn_t &, int value);
|
||||
bool S_pppppp(insn_t &insn, int value);
|
||||
bool D_qqqqqq(insn_t &, int value);
|
||||
bool S_qqqqqq(insn_t &insn, int value);
|
||||
bool D_qXqqqqq(insn_t &insn, int value);
|
||||
bool D_DDDDDD(insn_t &insn, int value);
|
||||
bool S_DDDDDD(insn_t &insn, int value);
|
||||
bool D_DDDD(insn_t &insn, int value);
|
||||
bool D_RRR(insn_t &insn, int value);
|
||||
bool S_RRR(insn_t &insn, int value);
|
||||
void make_o_mem(insn_t &insn);
|
||||
bool D_mMMMRRR(insn_t &insn, int value);
|
||||
bool S_mMMMRRR(insn_t &insn, int value);
|
||||
bool D_aaaaaa(insn_t &insn, int value);
|
||||
bool S_aaaaaa(insn_t &insn, int value);
|
||||
bool D_MMMRRR(insn_t &insn, int value);
|
||||
bool S_MMMRRR(insn_t &insn, int value);
|
||||
bool P_type(insn_t &, int);
|
||||
bool AAE(insn_t &insn, int);
|
||||
bool D_PC_dispL(insn_t &insn, int value);
|
||||
bool S_PC_dispL(insn_t &insn, int value);
|
||||
bool D_PC_dispS(insn_t &insn, int value);
|
||||
bool D_PC_RRR(insn_t &, int value);
|
||||
bool D_RRR_dispL(insn_t &insn, int value);
|
||||
bool D_RRR_dispS(insn_t &, int value);
|
||||
bool S_RR_dispS(insn_t &, int value);
|
||||
bool AA(insn_t &, int value);
|
||||
bool D_F(insn_t &insn, int value);
|
||||
bool S_F(insn_t &insn, int value);
|
||||
bool CCCC(insn_t &insn, int value);
|
||||
bool s(insn_t &insn, int value);
|
||||
bool ss(insn_t &insn, int value);
|
||||
bool SD_IIII(insn_t &insn, int value);
|
||||
bool D_zRR(insn_t &, int value);
|
||||
bool D_mRR(insn_t &, int value);
|
||||
bool D_RRm(insn_t &insn, int value);
|
||||
bool D_RR11m(insn_t &insn, int value);
|
||||
bool D_MMRR(insn_t &, int value);
|
||||
bool S_MMRR(insn_t &insn, int value);
|
||||
bool D_RR0MM(insn_t &insn, int value);
|
||||
bool D_qRR(insn_t &, int value);
|
||||
bool D_HHH(insn_t &, int value);
|
||||
bool D_HH(insn_t &, int value);
|
||||
bool SD_mWRRHHH(insn_t &insn, int value);
|
||||
bool S_FJJJ(insn_t &insn, int value);
|
||||
bool S_QQQ(insn_t &, int value);
|
||||
bool S_QQ2(insn_t &, int value);
|
||||
bool S_QQQQ(insn_t &, int value);
|
||||
bool S_Fh0h(insn_t &insn, int value);
|
||||
bool S_uFuuu_add(insn_t &insn, int value);
|
||||
bool S_uFuuu_sub(insn_t &insn, int value);
|
||||
bool D_RR(insn_t &insn, int value);
|
||||
bool D_NN(insn_t &insn, int value);
|
||||
bool DB_RR(insn_t &, int value);
|
||||
bool D_PC_RR(insn_t &, int value);
|
||||
bool DX_RR(insn_t &insn, int value);
|
||||
bool S_RR(insn_t &insn, int value);
|
||||
bool m_A_B(insn_t &, int /*value*/);
|
||||
bool IF(insn_t &, int /*value*/);
|
||||
bool IFU(insn_t &, int /*value*/);
|
||||
bool S_i(insn_t &insn, int value);
|
||||
bool SD_TT(insn_t &insn, int value);
|
||||
bool S_BBBiiiiiiii(insn_t &, int value);
|
||||
bool D_Pppppp(insn_t &insn, int value);
|
||||
bool D_ppppp(insn_t &insn, int value);
|
||||
bool D_aaaaa(insn_t &insn, int value);
|
||||
bool S_DDDDD(insn_t &insn, int value);
|
||||
bool D_xi(insn_t &, int value);
|
||||
bool D_xi16(insn_t &, int value);
|
||||
bool D_xi_adr_16(insn_t &insn, int value);
|
||||
bool D_DD(insn_t &insn, int value);
|
||||
bool S_DD(insn_t &insn, int value);
|
||||
bool D_Z(insn_t &, int value);
|
||||
bool D_t(insn_t &insn, int value);
|
||||
bool SD_F00J(insn_t &insn, int value);
|
||||
bool D_PC_eeeeee(insn_t &insn, int value);
|
||||
bool D_PC_aaaaaaaa(insn_t &insn, int value);
|
||||
bool D_BBBBBBBB(insn_t &, int value);
|
||||
bool is_valid_insn(ushort proc);
|
||||
bool disassemble_parallel_move(insn_t &insn, int i, int value);
|
||||
bool decode_XY_R_mem(insn_t &insn, int value);
|
||||
bool recognize_parallel_move_class1(insn_t &insn, int value);
|
||||
bool recognize_parallel_move_class1_3(insn_t &insn, int value);
|
||||
bool recognize_parallel_move_class2(insn_t &insn, int value);
|
||||
bool recognize_parallel_move_class3(insn_t &insn, int value);
|
||||
bool is_parallel_move(insn_t &insn, int value);
|
||||
bool use_table(
|
||||
insn_t &insn,
|
||||
const struct opcode_t *table,
|
||||
uint32 code,
|
||||
int entry,
|
||||
int start,
|
||||
int end);
|
||||
int ana_61(insn_t &insn);
|
||||
int ana_6x(insn_t &insn);
|
||||
int ana(insn_t *_insn);
|
||||
bool X_type(insn_t &, int);
|
||||
bool Y_type(insn_t &, int);
|
||||
bool mem_type(insn_t &, int value);
|
||||
bool space(insn_t &insn, int);
|
||||
bool sign(insn_t &, int value);
|
||||
int is_sane_insn(const insn_t &insn, int /*nocrefs*/) const;
|
||||
void fill_additional_args(const insn_t &insn) const;
|
||||
void switch_to_additional_args(insn_t &);
|
||||
inline void opreg(insn_t &, int reg);
|
||||
void reset_ops(insn_t &insn);
|
||||
void add_near_ref(const insn_t &insn, const op_t &x, ea_t ea);
|
||||
|
||||
void segstart(outctx_t &ctx, segment_t *seg) const;
|
||||
void segend(outctx_t &ctx, segment_t *seg) const;
|
||||
void footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
#define aux_cc 0x000F // condition code
|
||||
#define aux_su 0x0003 // sign/unsing code
|
||||
|
||||
#define phtype specflag1 // o_phrase: phrase type
|
||||
// 0 (Rn)-n
|
||||
// 1 (Rn)+Nn
|
||||
// 2 (Rn)-
|
||||
// 3 (Rn)+
|
||||
// 4 (Rn)
|
||||
// 5 (Rn+Nn)
|
||||
// 7 -(Rn)
|
||||
// 8 $+Rn
|
||||
// 9 (a1)
|
||||
// 10 (b1)
|
||||
|
||||
#define amode specflag2 // addressing mode
|
||||
#define amode_ioshort 0x01 // <<
|
||||
#define amode_short 0x02 // <
|
||||
#define amode_long 0x04 // >
|
||||
#define amode_neg 0x08 // -
|
||||
#define amode_x 0x10 // X:
|
||||
#define amode_y 0x20 // Y:
|
||||
#define amode_p 0x40 // P:
|
||||
#define amode_l 0x80 // L:
|
||||
|
||||
#define imode specflag3 // IF mode
|
||||
#define imode_if 0x01 // IFcc
|
||||
#define imode_ifu 0x02 // IFUcc
|
||||
|
||||
#define o_iftype o_idpspec0 // IF type
|
||||
|
||||
#define o_vsltype o_idpspec1 // VSL 2-nd operand type
|
||||
|
||||
//------------------------------------------------------------------
|
||||
#define UAS_GNU 0x0001 // GNU assembler
|
||||
//------------------------------------------------------------------
|
||||
enum RegNo ENUM_SIZE(uint16)
|
||||
{
|
||||
// data arithmetic logic unit
|
||||
X, X0, X1,
|
||||
Y, Y0, Y1,
|
||||
// accumulator registers
|
||||
A, A0, A1, A2,
|
||||
B, B0, B1, B2,
|
||||
AB, // a1:b1
|
||||
BA, // b1:a1
|
||||
A10, // a1:a0
|
||||
B10, // b1:b0
|
||||
// address generation unit (AGU)
|
||||
R0, R1, R2, R3, R4, R5, R6, R7, // pointers
|
||||
N0, N1, N2, N3, N4, N5, N6, N7, // offsets
|
||||
M0, M1, M2, M3, M4, M5, M6, M7, // modifiers
|
||||
// Program Control Unit
|
||||
PC, // Program Counter (16 Bits)
|
||||
MR, // Mode Register (8 Bits)
|
||||
CCR, // Condition Code Register (8 Bits)
|
||||
SR, // Status Register (MR:CCR, 16 Bits)
|
||||
OMR, // Operating Mode Register (8 Bits)
|
||||
LA, // Hardware Loop Address Register (16 Bits)
|
||||
LC, // Hardware Loop Counter (16 Bits)
|
||||
SP, // System Stack Pointer (6 Bits)
|
||||
SS, // System Stack RAM (15X32 Bits)
|
||||
SSH, // Upper 16 Bits of the Contents of the Current Top of Stack
|
||||
SSL, // Lower 16 Bits of the Contents of the Current Top of Stack
|
||||
SZ, // Stack Size register
|
||||
SC, // Stack Counter register
|
||||
EP, // Extension Pointer register
|
||||
VBA, // Vector Base Address Register
|
||||
|
||||
vCS, vDS, // virtual registers for code and data segments
|
||||
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// condition codes
|
||||
enum cc_t
|
||||
{
|
||||
cc_CC, // carry clear (higher or same) C=0
|
||||
cc_GE, // greater than or equal N xor V=0
|
||||
cc_NE, // not equal Z=0
|
||||
cc_PL, // plus N=0
|
||||
cc_NN, // not normalized Z+(^U&^E)=0
|
||||
cc_EC, // extension clear E=0
|
||||
cc_LC, // limit clear L=0
|
||||
cc_GT, // greater than Z+(N xor V)=0
|
||||
cc_CS, // carry set (lower) C=1
|
||||
cc_LT, // less than N xor V=1
|
||||
cc_EQ, // equal Z=1
|
||||
cc_MI, // minus N=1
|
||||
cc_NR, // normalized Z+(^U&^E)=1
|
||||
cc_ES, // extension set E=1
|
||||
cc_LS, // limit set L=1
|
||||
cc_LE, // less than or equal Z+(N xor V)=1
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
enum PMoveClass
|
||||
{
|
||||
cl_0 = 0, // No Parallel move
|
||||
cl_1, // X Memory Data Move (common)
|
||||
cl_1_3, // X Memory Data Move with short displacement
|
||||
cl_2, // Dual X Memory Data Read
|
||||
cl_3, // X Memory Data Write and Register Data Move
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// signed/unsigned codes
|
||||
enum su_t
|
||||
{
|
||||
s_SS, // signed * signed
|
||||
s_SU, // signed * unsigned
|
||||
s_UU, // unsigned * unsigned
|
||||
};
|
||||
|
||||
// Make sure that the 'aa' structure is up to date.
|
||||
void fill_additional_args(const insn_t &insn);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void interr(const insn_t *insn, const char *module);
|
||||
|
||||
int idaapi ana(insn_t *insn);
|
||||
int idaapi emu(const insn_t &insn);
|
||||
|
||||
int idaapi is_align_insn(ea_t ea);
|
||||
int idaapi is_sp_based(const insn_t &insn, const op_t &x);
|
||||
|
||||
#endif // _DSP56K_HPP
|
||||
222
idasdk76/module/dsp56k/emu.cpp
Normal file
222
idasdk76/module/dsp56k/emu.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
|
||||
#include "dsp56k.hpp"
|
||||
#include <frame.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t dsp56k_t::calc_mem(const insn_t &insn, const op_t &x) const
|
||||
{
|
||||
if ( x.amode & (amode_x|amode_l) )
|
||||
return xmem == BADADDR ? BADADDR : xmem+x.addr;
|
||||
if ( x.amode & amode_y )
|
||||
return ymem == BADADDR ? BADADDR : ymem+x.addr;
|
||||
return to_ea(insn.cs, x.addr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline bool is_stkreg(int r)
|
||||
{
|
||||
return r == SP;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &x)
|
||||
{
|
||||
return OP_SP_ADD | (x.phrase == SP ? OP_SP_BASED : OP_FP_BASED);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void process_immediate_number(const insn_t &insn, int n, flags_t F)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(F, n) )
|
||||
return;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
// case DSP56_asl:
|
||||
// case DSP56_asr:
|
||||
case DSP56_bchg:
|
||||
case DSP56_bclr:
|
||||
case DSP56_brclr:
|
||||
case DSP56_brset:
|
||||
case DSP56_bsclr:
|
||||
case DSP56_bset:
|
||||
case DSP56_bsset:
|
||||
case DSP56_btst:
|
||||
case DSP56_jclr:
|
||||
case DSP56_jset:
|
||||
case DSP56_jsclr:
|
||||
case DSP56_jsset:
|
||||
// case DSP56_lsl:
|
||||
// case DSP56_lsr:
|
||||
|
||||
op_dec(insn.ea, n);
|
||||
break;
|
||||
|
||||
|
||||
case DSP56_add:
|
||||
case DSP56_and:
|
||||
case DSP56_andi:
|
||||
case DSP56_cmp:
|
||||
case DSP56_eor:
|
||||
case DSP56_extract:
|
||||
case DSP56_extractu:
|
||||
case DSP56_insert:
|
||||
case DSP56_mac:
|
||||
case DSP56_maci:
|
||||
case DSP56_macr:
|
||||
case DSP56_macri:
|
||||
case DSP56_mpy:
|
||||
case DSP56_mpyi:
|
||||
case DSP56_mpyr:
|
||||
case DSP56_mpyri:
|
||||
case DSP56_or:
|
||||
case DSP56_ori:
|
||||
case DSP56_sub:
|
||||
case DSP56_do:
|
||||
case DSP56_dor:
|
||||
case DSP56_rep:
|
||||
|
||||
op_num(insn.ea, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void dsp56k_t::add_near_ref(const insn_t &insn, const op_t &x, ea_t ea)
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void dsp56k_t::handle_operand(
|
||||
const insn_t &insn,
|
||||
const op_t &x,
|
||||
flags_t F,
|
||||
bool is_forced,
|
||||
bool isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case o_imm:
|
||||
process_immediate_number(insn, x.n, F);
|
||||
if ( op_adds_xrefs(F, x.n) )
|
||||
insn.add_off_drefs(x, dr_O, OOFS_IFSIGN);
|
||||
break;
|
||||
case o_phrase:
|
||||
if ( !is_forced && op_adds_xrefs(F, x.n) )
|
||||
{
|
||||
ea_t ea = insn.add_off_drefs(x, isload ? dr_R : dr_W, OOF_ADDR);
|
||||
if ( ea != BADADDR )
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = calc_mem(insn, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
if ( x.amode & amode_l )
|
||||
{
|
||||
ea = ymem + x.addr;
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case o_near:
|
||||
add_near_ref(insn, x, calc_mem(insn, x));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int dsp56k_t::emu(const insn_t &insn)
|
||||
{
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
return 1;
|
||||
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
flags_t F = get_flags(insn.ea);
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, F, flag1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, F, flag2, true);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, F, flag3, true);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, F, flag1, false);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, F, flag2, false);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, F, flag3, false);
|
||||
|
||||
insn_t copy = insn;
|
||||
fill_additional_args(copy);
|
||||
for ( int i=0; i < aa.nargs; i++ )
|
||||
{
|
||||
op_t *x = aa.args[i];
|
||||
for ( int j=0; j < 2; j++,x++ )
|
||||
{
|
||||
if ( x->type == o_void )
|
||||
break;
|
||||
handle_operand(insn, *x, F, 0, j == 0);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Determine if the next instruction should be executed
|
||||
//
|
||||
if ( Feature & CF_STOP )
|
||||
flow = false;
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int dsp56k_t::is_sane_insn(const insn_t &insn, int /*nocrefs*/) const
|
||||
{
|
||||
// disallow jumps to nowhere
|
||||
if ( insn.Op1.type == o_near && !is_mapped(calc_mem(insn, insn.Op1)) )
|
||||
return 0;
|
||||
|
||||
// disallow many nops in a now
|
||||
int i = 0;
|
||||
for ( ea_t ea=insn.ea; i < 32; i++,ea++ )
|
||||
if ( get_byte(ea) != 0 )
|
||||
break;
|
||||
if ( i == 32 )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
if ( decode_insn(&insn, ea) < 1 )
|
||||
return 0;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case DSP56_nop:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
144
idasdk76/module/dsp56k/ins.cpp
Normal file
144
idasdk76/module/dsp56k/ins.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
|
||||
#include "dsp56k.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
{ "abs", CF_USE1|CF_CHG1 }, // Absolute Value
|
||||
{ "adc", CF_USE1|CF_USE2|CF_CHG2 }, // Add Long with Carry
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG2 }, // Addition
|
||||
{ "addl", CF_USE1|CF_USE2|CF_CHG2 }, // Shift Left and Add
|
||||
{ "addr", CF_USE1|CF_USE2|CF_CHG2 }, // Shift Right and Add
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG2 }, // Logical AND
|
||||
{ "andi", CF_USE1|CF_USE2|CF_CHG2 }, // AND Immediate to Control Register
|
||||
{ "asl", CF_USE1|CF_CHG1 }, // Arithmetic Shift Left
|
||||
{ "asl4", CF_USE1|CF_CHG1 }, // Arithmetic Shift Left
|
||||
{ "asr", CF_USE1|CF_CHG1 }, // Arithmetic Shift Right
|
||||
{ "asr4", CF_USE1|CF_CHG1 }, // Arithmetic Shift Right
|
||||
{ "asr16", CF_USE1|CF_CHG1 }, // Arithmetic Shift Right
|
||||
{ "bfchg", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test and Change
|
||||
{ "bfclr", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test and Clear
|
||||
{ "bfset", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test and Set
|
||||
{ "bftsth", CF_USE1|CF_USE2|CF_CHG2 }, // Test Bit Field High
|
||||
{ "bftstl", CF_USE1|CF_USE2|CF_CHG2 }, // Test Bit Field Low
|
||||
{ "b", CF_USE1|CF_JUMP }, // Branch Conditionally
|
||||
{ "bchg", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test and Change
|
||||
{ "bclr", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test and Clear
|
||||
{ "bra", CF_USE1|CF_STOP|CF_JUMP }, // Branch Always
|
||||
{ "brclr", CF_USE1|CF_USE2|CF_USE3|CF_JUMP }, // Branch if Bit Clear
|
||||
{ "brk", CF_USE1 }, // Exit Current DO Loop Conditionally
|
||||
{ "brset", CF_USE1|CF_USE2|CF_USE3|CF_JUMP }, // Branch if Bit Set
|
||||
{ "bs", CF_USE1|CF_CALL }, // Branch to Subroutine Conditionally
|
||||
{ "bsclr", CF_USE1|CF_USE2|CF_USE3|CF_CALL }, // Branch to Subroutine if Bit Clear
|
||||
{ "bset", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test and Set
|
||||
{ "bsr", CF_USE1|CF_CALL }, // Branch to Subroutine
|
||||
{ "bsset", CF_USE1|CF_USE2|CF_USE3|CF_CALL }, // Branch to Subroutine if Bit Set
|
||||
{ "btst", CF_USE1|CF_USE2|CF_CHG2 }, // Bit Test on Memory and Registers
|
||||
{ "chkaau", 0 }, // Check address ALU result
|
||||
{ "clb", CF_USE1|CF_CHG2 }, // Count Leading Bits
|
||||
{ "clr", CF_USE1|CF_CHG1 }, // Clear an Operand
|
||||
{ "clr24", CF_USE1|CF_CHG1 }, // Clear 24 MS-bits of Accumulator
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // Compare
|
||||
{ "cmpm", CF_USE1|CF_USE2 }, // Compare Magnitude
|
||||
{ "cmpu", CF_USE1|CF_USE2 }, // Compare Unsigned
|
||||
{ "debug", 0 }, // Enter Debug Mode
|
||||
{ "debug", 0 }, // Enter Debug Mode Conditionally
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // Decrement by One
|
||||
{ "dec24", CF_USE1|CF_CHG1 }, // Decrement 24 MS-bit of Accumulator
|
||||
{ "div", CF_USE1|CF_USE2|CF_CHG2 }, // Divide Iteration
|
||||
{ "dmac", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Double-Precision Multiply-Accumulate With Right Shift
|
||||
{ "do", CF_USE1|CF_USE2|CF_JUMP }, // Start Hardware Loop
|
||||
{ "do forever,", CF_USE1|CF_JUMP }, // Start Infinite Loop
|
||||
{ "dor", CF_USE1|CF_USE2|CF_JUMP }, // Start PC-Relative Hardware Loop
|
||||
{ "dor forever,", CF_USE1|CF_JUMP }, // Start PC-Relative Infinite Loop
|
||||
{ "enddo", 0 }, // Exit from Hardware Loop
|
||||
{ "eor", CF_USE1|CF_USE2|CF_CHG2 }, // Logical Exclusive OR
|
||||
{ "extract", CF_USE1|CF_USE2|CF_CHG3 }, // Extract Bit Field
|
||||
{ "extractu", CF_USE1|CF_USE2|CF_CHG3 }, // Extract Unsigned Bit Field
|
||||
{ "ext", CF_USE1|CF_CHG1 }, // Sign Extend Accumulator
|
||||
{ "illegal", 0 }, // Illegal Instruction
|
||||
{ "imac", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Integer Multiply-Accumulate
|
||||
{ "impy", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Integer Multiply
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // Increment by One
|
||||
{ "inc24", CF_USE1|CF_CHG1 }, // Increment 24 MS-bit of Accumulator
|
||||
{ "insert", CF_USE1|CF_USE2|CF_CHG3 }, // Insert Bit Field
|
||||
{ "j", CF_USE1|CF_JUMP }, // Jump Conditionally
|
||||
{ "jclr", CF_USE1|CF_USE2|CF_USE3|CF_JUMP }, // Jump if Bit Clear
|
||||
{ "jmp", CF_USE1|CF_STOP|CF_JUMP }, // Jump
|
||||
{ "js", CF_USE1|CF_CALL }, // Jump to Subroutine Conditionally
|
||||
{ "jsclr", CF_USE1|CF_USE2|CF_USE3|CF_CALL }, // Jump to Subroutine if Bit Clear
|
||||
{ "jset", CF_USE1|CF_USE2|CF_USE3|CF_JUMP }, // Jump if Bit Set
|
||||
{ "jsr", CF_USE1|CF_CALL }, // Jump to Subroutine
|
||||
{ "jsset", CF_USE1|CF_USE2|CF_USE3|CF_CALL }, // Jump to Subroutine if Bit Set
|
||||
{ "lra", CF_USE1|CF_CHG2 }, // Load PC-Reliative Address
|
||||
{ "lsl", CF_USE1|CF_CHG1 }, // Logical Shift Left
|
||||
{ "lsr", CF_USE1|CF_CHG1 }, // Logical Shift Right
|
||||
{ "lua", CF_USE1|CF_CHG2 }, // Load Updated Address
|
||||
{ "lea", CF_USE1|CF_CHG2 }, // Load Updated Address
|
||||
{ "mac", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply-Accumulate
|
||||
{ "maci", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply-Accumulate With Immediate Operand
|
||||
{ "mac", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Mixed Multiply-Accumulate
|
||||
{ "macr", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply-Accumulate and Round
|
||||
{ "macri", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply-Accumulate and Round With Immediate Operand
|
||||
{ "max", CF_USE1|CF_USE2|CF_CHG2 }, // Transfer by Signed Value
|
||||
{ "maxm", CF_USE1|CF_USE2|CF_CHG2 }, // Transfer by Magnitude
|
||||
{ "merge", CF_USE1|CF_USE2|CF_CHG2 }, // Merge Two Half Words
|
||||
{ "move", CF_USE1|CF_CHG2 }, // Move Data Register
|
||||
{ "movec", CF_USE1|CF_CHG2 }, // Move Control Register
|
||||
{ "movei", CF_USE1|CF_CHG2 }, // Move Immediate Short
|
||||
{ "movem", CF_USE1|CF_CHG2 }, // Move Program Memory
|
||||
{ "movep", CF_USE1|CF_CHG2 }, // Move Peripheral Data
|
||||
{ "moves", CF_USE1|CF_CHG2 }, // Move Absolute Short
|
||||
{ "mpy", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply
|
||||
{ "mpyi", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply With Immediate Operand
|
||||
{ "mpy", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Mixed Multiply
|
||||
{ "mpyr", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply and Round
|
||||
{ "mpyri", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // Signed Multiply and Round With Immediate Operand
|
||||
{ "neg", CF_USE1|CF_CHG1 }, // Negate Accumulator
|
||||
{ "negc", CF_USE1|CF_CHG1 }, // Negate Accumulator
|
||||
{ "nop", 0 }, // No Operation
|
||||
{ "norm", CF_USE1|CF_USE2|CF_CHG2 }, // Norm Accumulator Iteration
|
||||
{ "normf", CF_USE1|CF_USE2|CF_CHG2 }, // Fast Accumulator Normalization
|
||||
{ "not", CF_USE1|CF_CHG1 }, // Logical Complement
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG2 }, // Logical Inclusive OR
|
||||
{ "ori", CF_USE1|CF_USE2|CF_CHG2 }, // OR Immediate to Control Register
|
||||
{ "pflush", 0 }, // Program Cache Flush
|
||||
{ "pflushun", 0 }, // Program Cache Flush Unlocked Sectors
|
||||
{ "pfree", 0 }, // Program Cache Global Unlock
|
||||
{ "plock", 0 }, // Lock Instruction Cache Sector
|
||||
{ "plockr", 0 }, // Lock Instruction Cache Relative Sector
|
||||
{ "punlock", 0 }, // Unlock Instruction Cache Sector
|
||||
{ "punlockr", 0 }, // Unlock Instruction Cache Relative Sector
|
||||
{ "rep", CF_USE1 }, // Repeat Next Instruction
|
||||
{ "rep", CF_USE1 }, // Repeat Next Instruction
|
||||
{ "reset", 0 }, // Reset On-Chip Peripheral Devices
|
||||
{ "rnd", CF_USE1|CF_CHG1 }, // Round
|
||||
{ "rol", CF_USE1|CF_CHG1 }, // Rotate Left
|
||||
{ "ror", CF_USE1|CF_CHG1 }, // Rotate Right
|
||||
{ "rti", CF_STOP }, // Return from Interrupt
|
||||
{ "rts", CF_STOP }, // Return from Subroutine
|
||||
{ "sbc", CF_USE1|CF_USE2|CF_CHG2 }, // Subtract Long with Carry
|
||||
{ "stop", CF_STOP }, // Stop Processing (Low-Power Standby)
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG2 }, // Subtract
|
||||
{ "subl", CF_USE1|CF_USE2|CF_CHG2 }, // Shift Left and Subtract
|
||||
{ "subr", CF_USE1|CF_USE2|CF_CHG2 }, // Shift Right and Subtract
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // Swap Accumulator Words
|
||||
{ "t", CF_USE1|CF_USE2 }, // Transfer Conditionally
|
||||
{ "tfr", CF_USE1|CF_USE2 }, // Transfer Data ALU Register
|
||||
{ "tfr2", CF_USE1|CF_USE2|CF_CHG2 }, // Transfer Data ALU Register
|
||||
{ "tfr3", CF_USE1|CF_USE2|CF_CHG2 }, // Transfer Data ALU Register
|
||||
{ "trap", 0 }, // Software Interrupt
|
||||
{ "trap", 0 }, // Software Interrupt Conditionally
|
||||
{ "tst", CF_USE1 }, // Test an Operand
|
||||
{ "tst2", CF_USE1 }, // Test an Operand
|
||||
{ "vsl", CF_USE1|CF_USE2|CF_CHG3 }, // Viterbi Shift Left
|
||||
{ "wait", 0 }, // Wait for Interrupt or DMA Request (Low-Power Standby)
|
||||
{ "zero", 0 }, // Zero Extend Accumulator
|
||||
{ "swi", 0 }, // Software Interrupt
|
||||
{ "pmov", 0 }, // Pseudo insn
|
||||
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == DSP56_last);
|
||||
147
idasdk76/module/dsp56k/ins.hpp
Normal file
147
idasdk76/module/dsp56k/ins.hpp
Normal file
@@ -0,0 +1,147 @@
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum
|
||||
{
|
||||
DSP56_null = 0, // Unknown Operation
|
||||
|
||||
DSP56_abs, // Absolute Value
|
||||
DSP56_adc, // Add Long with Carry
|
||||
DSP56_add, // Addition
|
||||
DSP56_addl, // Shift Left and Add
|
||||
DSP56_addr, // Shift Right and Add
|
||||
DSP56_and, // Logical AND
|
||||
DSP56_andi, // AND Immediate to Control Register
|
||||
DSP56_asl, // Arithmetic Shift Left
|
||||
DSP56_asl4, // Arithmetic Shift Left 4
|
||||
DSP56_asr, // Arithmetic Shift Right
|
||||
DSP56_asr4, // Arithmetic Shift Right 4
|
||||
DSP56_asr16, // Arithmetic Shift Right 16
|
||||
DSP56_bfchg, // Test Bit Field and Change
|
||||
DSP56_bfclr, // Clear Bit Field
|
||||
DSP56_bfset, // Set Bit Field
|
||||
DSP56_bftsth, // Test Bit Field High
|
||||
DSP56_bftstl, // Test Bit Field Low
|
||||
DSP56_bcc, // Branch Conditionaly
|
||||
DSP56_bchg, // Bit Test and Change
|
||||
DSP56_bclr, // Bit Test and Clear
|
||||
DSP56_bra, // Branch Always
|
||||
DSP56_brclr, // Branch if Bit Clear
|
||||
DSP56_brkcc, // Exit Current DO Loop Conditionally
|
||||
DSP56_brset, // Branch if Bit Set
|
||||
DSP56_bscc, // Branch to Subroutine Conditionaly
|
||||
DSP56_bsclr, // Branch to Subroutine if Bit Clear
|
||||
DSP56_bset, // Bit Test and Set
|
||||
DSP56_bsr, // Branch to Subroutine
|
||||
DSP56_bsset, // Branch to Subroutine if Bit Set
|
||||
DSP56_btst, // Bit Test on Memory and Registers
|
||||
DSP56_chkaau, // Check address ALU result
|
||||
DSP56_clb, // Count Leading Bits
|
||||
DSP56_clr, // Clear an Operand
|
||||
DSP56_clr24, // Clear 24 MS-bits of Accumulator
|
||||
DSP56_cmp, // Compare
|
||||
DSP56_cmpm, // Compare Magnitude
|
||||
DSP56_cmpu, // Compare Unsigned
|
||||
DSP56_debug, // Enter Debug Mode
|
||||
DSP56_debugcc, // Enter Debug Mode Conditionally
|
||||
DSP56_dec, // Decrement by One
|
||||
DSP56_dec24, // Decrement 24 MS-bit of Accumulator
|
||||
DSP56_div, // Divide Iteration
|
||||
DSP56_dmac, // Double-Precision Multiply-Accumulate With Right Shift
|
||||
DSP56_do, // Start Hardware Loop
|
||||
DSP56_do_f, // Start Infinite Loop
|
||||
DSP56_dor, // Start PC-Relative Hardware Loop
|
||||
DSP56_dor_f, // Start PC-Relative Infinite Loop
|
||||
DSP56_enddo, // Exit from Hardware Loop
|
||||
DSP56_eor, // Logical Exclusive OR
|
||||
DSP56_extract, // Extract Bit Field
|
||||
DSP56_extractu, // Extract Unsigned Bit Field
|
||||
DSP56_ext, // Sign Extend Accumulator
|
||||
DSP56_ill, // Illegal Instruction
|
||||
DSP56_imac, // Integer Multiply-Accumulate
|
||||
DSP56_impy, // Integer Multiply
|
||||
DSP56_inc, // Increment by One
|
||||
DSP56_inc24, // Increment 24 MS-bit of Accumulator
|
||||
DSP56_insert, // Insert Bit Field
|
||||
DSP56_jcc, // Jump Conditionally
|
||||
DSP56_jclr, // Jump if Bit Clear
|
||||
DSP56_jmp, // Jump
|
||||
DSP56_jscc, // Jump to Subroutine Conditionally
|
||||
DSP56_jsclr, // Jump to Subroutine if Bit Clear
|
||||
DSP56_jset, // Jump if Bit Set
|
||||
DSP56_jsr, // Jump to Subroutine
|
||||
DSP56_jsset, // Jump to Subroutine if Bit Set
|
||||
DSP56_lra, // Load PC-Reliative Address
|
||||
DSP56_lsl, // Logical Shift Left
|
||||
DSP56_lsr, // Logical Shift Right
|
||||
DSP56_lua, // Load Updated Address
|
||||
DSP56_lea, // Load Updated Address
|
||||
DSP56_mac, // Signed Multiply-Accumulate
|
||||
DSP56_maci, // Signed Multiply-Accumulate With Immediate Operand
|
||||
DSP56_mac_s_u, // Mixed Multiply-Accumulate
|
||||
DSP56_macr, // Signed Multiply-Accumulate and Round
|
||||
DSP56_macri, // Signed Multiply-Accumulate and Round With Immediate Operand
|
||||
DSP56_max, // Transfer by Signed Value
|
||||
DSP56_maxm, // Transfer by Magnitude
|
||||
DSP56_merge, // Merge Two Half Words
|
||||
DSP56_move, // Move Data
|
||||
DSP56_movec, // Move Control Register
|
||||
DSP56_movei, // Move Immediate Short
|
||||
DSP56_movem, // Move Program Memory
|
||||
DSP56_movep, // Move Peripheral Data
|
||||
DSP56_moves, // Move Absolute Short
|
||||
DSP56_mpy, // Signed Multiply
|
||||
DSP56_mpyi, // Signed Multiply With Immediate Operand
|
||||
DSP56_mpy_s_u, // Mixed Multiply
|
||||
DSP56_mpyr, // Signed Multiply and Round
|
||||
DSP56_mpyri, // Signed Multiply and Round With Immediate Operand
|
||||
DSP56_neg, // Negate Accumulator
|
||||
DSP56_negc, // Negate Accumulator
|
||||
DSP56_nop, // No Operation
|
||||
DSP56_norm, // Norm Accumulator Iteration
|
||||
DSP56_normf, // Fast Accumulator Normalization
|
||||
DSP56_not, // Logical Complement
|
||||
DSP56_or, // Logical Inclusive OR
|
||||
DSP56_ori, // OR Immediate to Control Register
|
||||
DSP56_pflush, // Program Cache Flush
|
||||
DSP56_pflushun, // Program Cache Flush Unlocked Sectors
|
||||
DSP56_pfree, // Program Cache Global Unlock
|
||||
DSP56_plock, // Lock Instruction Cache Sector
|
||||
DSP56_plockr, // Lock Instruction Cache Relative Sector
|
||||
DSP56_punlock, // Unlock Instruction Cache Sector
|
||||
DSP56_punlockr, // Unlock Instruction Cache Relative Sector
|
||||
DSP56_rep, // Repeat Next Instruction
|
||||
DSP56_repcc, // Repeat Next Instruction
|
||||
DSP56_reset, // Reset On-Chip Peripheral Devices
|
||||
DSP56_rnd, // Round Accumulator
|
||||
DSP56_rol, // Rotate Left
|
||||
DSP56_ror, // Rotate Right
|
||||
DSP56_rti, // Return from Interrupt
|
||||
DSP56_rts, // Return from Subroutine
|
||||
DSP56_sbc, // Subtract Long with Carry
|
||||
DSP56_stop, // Stop Processing (Low-Power Standby)
|
||||
DSP56_sub, // Subtract
|
||||
DSP56_subl, // Shift Left and Subtract
|
||||
DSP56_subr, // Shift Right and Subtract
|
||||
DSP56_swap, // Swap Accumulator Words
|
||||
DSP56_tcc, // Transfer Conditionally
|
||||
DSP56_tfr, // Transfer Data ALU Register
|
||||
DSP56_tfr2, // Transfer Data ALU Register
|
||||
DSP56_tfr3, // Transfer Data ALU Register
|
||||
DSP56_trap, // Software Interrupt
|
||||
DSP56_trapcc, // Software Interrupt Conditionally
|
||||
DSP56_tst, // Test an Operand
|
||||
DSP56_tst2, // Test an Operand
|
||||
DSP56_vsl, // Viterbi Shift Left
|
||||
DSP56_wait, // Wait for Interrupt or DMA Request (Low-Power Standby)
|
||||
DSP56_zero, // Zero Extend Accumulator
|
||||
DSP56_swi, // Software Interrupt (only for 56000)
|
||||
DSP56_pmov, // Pseudo insn
|
||||
DSP56_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
57
idasdk76/module/dsp56k/makefile
Normal file
57
idasdk76/module/dsp56k/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=dsp56k
|
||||
CONFIGS=dsp56k.cfg dsp563xx.cfg dsp566xx.cfg dsp561xx.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)ieee.h $(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 dsp56k.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)ieee.h $(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 \
|
||||
dsp56k.hpp emu.cpp 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)ieee.h $(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 \
|
||||
dsp56k.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)ieee.h $(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 \
|
||||
dsp56k.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)ieee.h $(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 \
|
||||
dsp56k.hpp ins.hpp reg.cpp
|
||||
397
idasdk76/module/dsp56k/out.cpp
Normal file
397
idasdk76/module/dsp56k/out.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
|
||||
#include "dsp56k.hpp"
|
||||
|
||||
// simple wrapper class for syntactic sugar of member functions
|
||||
// this class may have only simple member functions.
|
||||
// virtual functions and data fields are forbidden, otherwise the class
|
||||
// layout may change
|
||||
class out_dsp56k_t : public outctx_t
|
||||
{
|
||||
out_dsp56k_t(void) = delete; // not used
|
||||
public:
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
void outreg(int r) { out_register(ph.reg_names[r]); }
|
||||
bool out_port_address(ea_t addr);
|
||||
void out_bad_address(ea_t addr);
|
||||
void out_ip_rel(int displ);
|
||||
void out_operand_group(int idx, const op_t *x);
|
||||
};
|
||||
CASSERT(sizeof(out_dsp56k_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_dsp56k_t)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const cc_text[] =
|
||||
{
|
||||
"cc", // carry clear (higher or same) C=0
|
||||
"ge", // greater than or equal N & V=0
|
||||
"ne", // not equal Z=0
|
||||
"pl", // plus N=0
|
||||
"nn", // not normalized Z+(U.E)=0
|
||||
"ec", // extension clear E=0
|
||||
"lc", // limit clear L=0
|
||||
"gt", // greater than Z+(N & V)=0
|
||||
"cs", // carry set (lower) C=1
|
||||
"lt", // less than N & V=1
|
||||
"eq", // equal Z=1
|
||||
"mi", // minus N=1
|
||||
"nr", // normalized Z+(U.E)=1
|
||||
"es", // extension set E=1
|
||||
"ls", // limit set L=1
|
||||
"le", // less than or equal Z+(N & V)=1
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const su_text[] =
|
||||
{
|
||||
"ss", // signed * signed
|
||||
"su", // signed * unsigned
|
||||
"uu", // unsigned * unsigned
|
||||
};
|
||||
|
||||
static const char *const formats[] =
|
||||
{
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")-", SCOLOR_SYMBOL) COLSTR("n%d", SCOLOR_REG),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")+", SCOLOR_SYMBOL) COLSTR("n%d", SCOLOR_REG),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")-", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")+", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR("+", SCOLOR_SYMBOL) COLSTR("n%d", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
"internal error with o_phrase",
|
||||
COLSTR("-(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
COLSTR("$+", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("a1", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("b1", SCOLOR_REG) COLSTR(")", SCOLOR_SYMBOL),
|
||||
};
|
||||
// 0 (Rn)-Nn
|
||||
// 1 (Rn)+Nn
|
||||
// 2 (Rn)-
|
||||
// 3 (Rn)+
|
||||
// 4 (Rn)
|
||||
// 5 (Rn+Nn)
|
||||
// 7 -(Rn)
|
||||
// 8 $+Rn
|
||||
// 9 (a1)
|
||||
// 10 (b1)
|
||||
|
||||
|
||||
static const char *const formats2[] =
|
||||
{
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR("+", SCOLOR_SYMBOL) COLSTR("$%X", SCOLOR_NUMBER) COLSTR(")", SCOLOR_SYMBOL),
|
||||
COLSTR("(", SCOLOR_SYMBOL) COLSTR("r%d", SCOLOR_REG) COLSTR("-", SCOLOR_SYMBOL) COLSTR("$%X", SCOLOR_NUMBER) COLSTR(")", SCOLOR_SYMBOL),
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_dsp56k_t::out_port_address(ea_t addr)
|
||||
{
|
||||
dsp56k_t &pm = *static_cast<dsp56k_t *>(procmod);
|
||||
const ioport_t *port = pm.find_port(addr);
|
||||
if ( port != NULL && !port->name.empty() )
|
||||
{
|
||||
out_line(port->name.c_str(), COLOR_IMPNAME);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_dsp56k_t::out_bad_address(ea_t addr)
|
||||
{
|
||||
if ( !out_port_address(addr) )
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(addr, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_dsp56k_t::out_ip_rel(int displ)
|
||||
{
|
||||
out_printf(COLSTR("%s+", SCOLOR_SYMBOL) COLSTR("%d", SCOLOR_NUMBER),
|
||||
ash.a_curip, displ);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool out_dsp56k_t::out_operand(const op_t &x)
|
||||
{
|
||||
dsp56k_t &pm = *static_cast<dsp56k_t *>(procmod);
|
||||
if ( x.type == o_imm )
|
||||
{
|
||||
out_symbol('#');
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( x.amode & amode_x )
|
||||
{
|
||||
out_register("x");
|
||||
out_symbol(':');
|
||||
}
|
||||
if ( x.amode & amode_y )
|
||||
{
|
||||
out_register("y");
|
||||
out_symbol(':');
|
||||
}
|
||||
if ( x.amode & amode_p )
|
||||
{
|
||||
out_register("p");
|
||||
out_symbol(':');
|
||||
}
|
||||
if ( x.amode & amode_l )
|
||||
{
|
||||
out_register("l");
|
||||
out_symbol(':');
|
||||
}
|
||||
}
|
||||
if ( x.amode & amode_ioshort )
|
||||
{
|
||||
out_symbol('<');
|
||||
out_symbol('<');
|
||||
}
|
||||
if ( x.amode & amode_short )
|
||||
out_symbol('<');
|
||||
if ( x.amode & amode_long )
|
||||
out_symbol('>');
|
||||
if ( x.amode & amode_neg )
|
||||
out_symbol('-');
|
||||
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_imm:
|
||||
out_value(x, OOFS_IFSIGN|OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_reg:
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
// no break;
|
||||
case o_near:
|
||||
{
|
||||
ea_t ea = pm.calc_mem(insn, x);
|
||||
// xmem ioports
|
||||
if ( x.amode & (amode_x|amode_l) && out_port_address(x.addr) )
|
||||
{
|
||||
const ioport_t *port = pm.find_port(x.addr);
|
||||
if ( port != NULL && !has_user_name(get_flags(ea)) )
|
||||
set_name(ea, port->name.c_str(), SN_NODUMMY);
|
||||
break;
|
||||
}
|
||||
if ( ea == insn.ea+insn.size )
|
||||
out_ip_rel(insn.size);
|
||||
else if ( !out_name_expr(x, ea, x.addr) )
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
nowarn_qsnprintf(buf, sizeof(buf), formats[uchar(x.phtype)], x.phrase, x.phrase);
|
||||
out_colored_register_line(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
nowarn_qsnprintf(buf, sizeof(buf), formats2[uchar(x.phtype)], x.phrase, x.addr);
|
||||
out_colored_register_line(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_iftype:
|
||||
{
|
||||
char postfix[4];
|
||||
qstrncpy(postfix, cc_text[insn.auxpref & aux_cc], sizeof(postfix));
|
||||
if ( x.imode == imode_if )
|
||||
out_printf(COLSTR("IF%s", SCOLOR_SYMBOL), postfix);
|
||||
else
|
||||
out_printf(COLSTR("IF%s.U", SCOLOR_SYMBOL), postfix);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_vsltype:
|
||||
out_symbol((insn.auxpref & 1) + '0');
|
||||
break;
|
||||
|
||||
default:
|
||||
interr(&insn, "out");
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_dsp56k_t::out_operand_group(int idx, const op_t *x)
|
||||
{
|
||||
for ( int i=0; i < 2; i++,x++ )
|
||||
{
|
||||
if ( x->type == o_void )
|
||||
break;
|
||||
if ( i != 0 )
|
||||
{
|
||||
out_symbol(',');
|
||||
}
|
||||
else if ( insn.itype != DSP56_move || idx != 0 )
|
||||
{
|
||||
size_t n = 16;
|
||||
if ( idx == (insn.itype == DSP56_move) )
|
||||
n = tag_strlen(outbuf.c_str());
|
||||
do
|
||||
out_char(' ');
|
||||
while ( ++n < 20 );
|
||||
}
|
||||
out_operand(*x);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_dsp56k_t::out_proc_mnem(void)
|
||||
{
|
||||
// output instruction mnemonics
|
||||
char postfix[4];
|
||||
postfix[0] = '\0';
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case DSP56_tcc:
|
||||
case DSP56_debugcc:
|
||||
case DSP56_jcc:
|
||||
case DSP56_jscc:
|
||||
case DSP56_bcc:
|
||||
case DSP56_bscc:
|
||||
case DSP56_trapcc:
|
||||
qstrncpy(postfix, cc_text[insn.auxpref & aux_cc], sizeof(postfix));
|
||||
break;
|
||||
|
||||
case DSP56_dmac:
|
||||
case DSP56_mac_s_u:
|
||||
case DSP56_mpy_s_u:
|
||||
qstrncpy(postfix, su_text[insn.auxpref & aux_su], sizeof(postfix));
|
||||
break;
|
||||
}
|
||||
|
||||
out_mnem(8, postfix);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_dsp56k_t::out_insn(void)
|
||||
{
|
||||
dsp56k_t &pm = *static_cast<dsp56k_t *>(procmod);
|
||||
out_mnemonic();
|
||||
bool comma = out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
if ( comma )
|
||||
out_symbol(',');
|
||||
out_one_operand(1);
|
||||
}
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_one_operand(2);
|
||||
}
|
||||
|
||||
pm.fill_additional_args(insn);
|
||||
for ( int i=0; i < pm.aa.nargs; i++ )
|
||||
out_operand_group(i, pm.aa.args[i]);
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{818} seg could be made const
|
||||
void dsp56k_t::segstart(outctx_t &ctx, segment_t *seg) const
|
||||
{
|
||||
if ( is_spec_segm(seg->type) )
|
||||
return;
|
||||
|
||||
qstring sname;
|
||||
qstring sclas;
|
||||
get_segm_name(&sname, seg);
|
||||
get_segm_class(&sclas, seg);
|
||||
|
||||
if ( ash.uflag & UAS_GNU )
|
||||
{
|
||||
const char *predefined[] =
|
||||
{
|
||||
".text", // Text section
|
||||
".data", // Data sections
|
||||
".rdata",
|
||||
".comm",
|
||||
};
|
||||
if ( !print_predefined_segname(ctx, &sname, predefined, qnumber(predefined)) )
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR(".section %s", SCOLOR_ASMDIR) " " COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sname.c_str(),
|
||||
ash.cmnt,
|
||||
sclas.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
validate_name(&sname, VNT_IDENT);
|
||||
if ( sname == "XMEM" || sname == "YMEM" )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), seg->start_ea-get_segm_base(seg));
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s %c:%s", SCOLOR_ASMDIR),
|
||||
ash.origin,
|
||||
qtolower(sname[0]),
|
||||
buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("section %s", SCOLOR_ASMDIR) " " COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sname.c_str(),
|
||||
ash.cmnt,
|
||||
sclas.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{818} seg could be made const
|
||||
void dsp56k_t::segend(outctx_t &ctx, segment_t *seg) const
|
||||
{
|
||||
if ( is_spec_segm(seg->type) )
|
||||
return;
|
||||
|
||||
if ( (ash.uflag & UAS_GNU) == 0 )
|
||||
{
|
||||
qstring sname;
|
||||
get_segm_name(&sname, seg);
|
||||
if ( sname != "XMEM" && sname != "YMEM" )
|
||||
ctx.gen_printf(DEFAULT_INDENT, "endsec");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void dsp56k_t::header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL, NULL, ioh.device.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void dsp56k_t::footer(outctx_t &ctx) const
|
||||
{
|
||||
qstring nbuf = get_colored_name(inf_get_start_ea());
|
||||
const char *name = nbuf.c_str();
|
||||
const char *end = ash.end;
|
||||
if ( end == NULL )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s end %s",SCOLOR_AUTOCMT), ash.cmnt, name);
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
|
||||
ash.end, ash.cmnt, name);
|
||||
}
|
||||
559
idasdk76/module/dsp56k/reg.cpp
Normal file
559
idasdk76/module/dsp56k/reg.cpp
Normal file
@@ -0,0 +1,559 @@
|
||||
|
||||
#include "dsp56k.hpp"
|
||||
#include <diskio.hpp>
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const register_names[] =
|
||||
{
|
||||
// data arithmetic logic unit
|
||||
"x", "x0", "x1",
|
||||
"y", "y0", "y1",
|
||||
// accumulator registers
|
||||
"a", "a0", "a1", "a2",
|
||||
"b", "b0", "b1", "b2",
|
||||
"ab", // a1:b1
|
||||
"ba", // b1:a1
|
||||
"a10", // a1:a0
|
||||
"b10", // b1:b0
|
||||
// address generation unit (AGU)
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", // pointers
|
||||
"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", // offsets
|
||||
"m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7", // modifiers
|
||||
// Program Control Unit
|
||||
"pc", // Program Counter (16 Bits)
|
||||
"mr", // Mode Register (8 Bits)
|
||||
"ccr", // Condition Code Register (8 Bits)
|
||||
"sr", // Status Register (MR:CCR, 16 Bits)
|
||||
"omr", // Operating Mode Register (8 Bits)
|
||||
"la", // Hardware Loop Address Register (16 Bits)
|
||||
"lc", // Hardware Loop Counter (16 Bits)
|
||||
"sp", // System Stack Pointer (6 Bits)
|
||||
"ss", // System Stack RAM (15X32 Bits)
|
||||
"ssh", // Upper 16 Bits of the Contents of the Current Top of Stack
|
||||
"ssl", // Lower 16 Bits of the Contents of the Current Top of Stack
|
||||
"sz", // Stack Size register
|
||||
"sc", // Stack Counter register
|
||||
"ep", // Extension Pointer register
|
||||
"vba", // Vector Base Address Register
|
||||
|
||||
"cs","ds", // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 6x
|
||||
static const uchar retcode_0[] = { 0x0C, 0x00, 0x00 };
|
||||
static const uchar retcode_1[] = { 0x04, 0x00, 0x00 };
|
||||
// 61
|
||||
static const uchar retcode_2[] = { 0x06, 0x00 };
|
||||
static const uchar retcode_3[] = { 0x07, 0x00 };
|
||||
|
||||
static const bytes_t retcodes6x[] =
|
||||
{
|
||||
{ sizeof(retcode_0), retcode_0 },
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const bytes_t retcodes61[] =
|
||||
{
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ sizeof(retcode_3), retcode_3 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Motorola DSP56000 Assembler
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t motasm =
|
||||
{
|
||||
// AS_ASCIIC
|
||||
ASH_HEXF4 // $34
|
||||
|ASD_DECF0 // 34
|
||||
|ASB_BINF2 // %01010
|
||||
|ASO_OCTF1 // 0123
|
||||
|AS_COLON
|
||||
|AS_N2CHR
|
||||
|AS_NCMAS
|
||||
|AS_ONEDUP,
|
||||
0,
|
||||
"Motorola DSP56K Assembler",
|
||||
0,
|
||||
NULL, // header lines
|
||||
"org", // org
|
||||
"end", // end
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\"'", // special symbols in char and string constants
|
||||
|
||||
"dc", // ascii string directive
|
||||
"dcb", // byte directive
|
||||
"dc", // word directive
|
||||
NULL, // double words
|
||||
NULL, // qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
"bs#s(c,) #d, #v", // arrays (#h,#d,#v,#s(...)
|
||||
"ds %s", // uninited arrays
|
||||
"equ", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
"*", // current IP (instruction pointer)
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
"global", // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
"xref", // "extrn" name keyword
|
||||
// .extern directive requires an explicit object size
|
||||
NULL, // "comm" (communal variable)
|
||||
NULL, // get_type_name
|
||||
NULL, // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"~", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
AS2_BYTE1CHAR,// One symbol per processor byte
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// GNU ASM
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t gas =
|
||||
{
|
||||
AS_ASCIIC
|
||||
|ASH_HEXF4 // $34
|
||||
|ASD_DECF0 // 34
|
||||
|ASB_BINF3 // 0b01010
|
||||
|ASO_OCTF1 // 0123
|
||||
|AS_COLON
|
||||
|AS_N2CHR
|
||||
|AS_NCMAS
|
||||
|AS_ONEDUP,
|
||||
UAS_GNU,
|
||||
"GNU-like hypothetical assembler",
|
||||
0,
|
||||
NULL, // header lines
|
||||
".org", // org
|
||||
NULL, // end
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\"'", // special symbols in char and string constants
|
||||
|
||||
".string", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".short", // word directive
|
||||
".long", // double words
|
||||
NULL, // qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
".ds.#s(b,w,l,d) #d, #v", // arrays (#h,#d,#v,#s(...)
|
||||
".space %s", // uninited arrays
|
||||
"=", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
".", // current IP (instruction pointer)
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
".global", // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
".extern", // "extrn" name keyword
|
||||
// .extern directive requires an explicit object size
|
||||
".comm", // "comm" (communal variable)
|
||||
NULL, // get_type_name
|
||||
".align", // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
"mod", // mod
|
||||
"and", // and
|
||||
"or", // or
|
||||
"xor", // xor
|
||||
"not", // not
|
||||
"shl", // shl
|
||||
"shr", // shr
|
||||
NULL, // sizeof
|
||||
AS2_BYTE1CHAR,// One symbol per processor byte
|
||||
NULL, // cmnt2
|
||||
NULL, // low8
|
||||
NULL, // high8
|
||||
NULL, // low16
|
||||
NULL, // high16
|
||||
"#include \"%s\"", // a_include_fmt
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &motasm, &gas, NULL };
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t dsp56k_t::AdditionalSegment(asize_t size, int offset, const char *name) const
|
||||
{
|
||||
segment_t s;
|
||||
int step = is561xx() ? 0xF : 0x1000000-1;
|
||||
s.start_ea = free_chunk(0x1000000, size, step);
|
||||
s.end_ea = s.start_ea + size;
|
||||
s.sel = allocate_selector((s.start_ea-offset) >> 4);
|
||||
s.type = SEG_DATA;
|
||||
s.bitness = ph.dnbits > 16;
|
||||
add_segm_ex(&s, name, "DATA", ADDSEG_NOSREG|ADDSEG_OR_DIE);
|
||||
return s.start_ea - offset;
|
||||
}
|
||||
|
||||
inline ea_t get_start(const segment_t *s)
|
||||
{
|
||||
return s ? s->start_ea : BADADDR;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *dsp56k_iohandler_t::iocallback(const ioports_t &iop, const char *line)
|
||||
{
|
||||
int size;
|
||||
if ( qsscanf(line, "XMEMSIZE = %i", &size) == 1 )
|
||||
{
|
||||
pm.xmemsize = size;
|
||||
RETOK:
|
||||
pm.ioh.deviceparams.sprnt("XMEM=0x%X YMEM=0x%X", pm.xmemsize, pm.ymemsize);
|
||||
return NULL;
|
||||
}
|
||||
if ( !pm.is561xx() && qsscanf(line, "YMEMSIZE = %i", &size) == 1 )
|
||||
{
|
||||
pm.ymemsize = size;
|
||||
goto RETOK;
|
||||
}
|
||||
return pm.ioh.standard_callback(iop, line);
|
||||
}
|
||||
|
||||
const ioport_t *dsp56k_t::find_port(ea_t address)
|
||||
{
|
||||
return find_ioport(ioh.ports, address);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void dsp56k_t::create_xmem_ymem(void)
|
||||
{
|
||||
if ( xmem == BADADDR )
|
||||
{
|
||||
xmem = AdditionalSegment(xmemsize, 0, "XMEM");
|
||||
|
||||
if ( !is561xx() )
|
||||
ymem = AdditionalSegment(ymemsize, 0, "YMEM");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void dsp56k_t::select_device(const char *dname, int resp_info)
|
||||
{
|
||||
ioh.set_device_name(dname, resp_info);
|
||||
|
||||
create_xmem_ymem();
|
||||
|
||||
for ( int i=0; i < ioh.ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ioh.ports[i];
|
||||
ea_t ea = xmem + p.address;
|
||||
const char *name = p.name.c_str();
|
||||
ea_t nameea = get_name_ea(BADADDR, name);
|
||||
if ( nameea != ea )
|
||||
{
|
||||
set_name(nameea, "");
|
||||
if ( !set_name(ea, name, SN_NOCHECK|SN_NOWARN|SN_NODUMMY) )
|
||||
set_cmt(ea, name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *dsp56k_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/)
|
||||
{
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
if ( choose_ioport_device(&ioh.device, cfgfile) )
|
||||
select_device(ioh.device.c_str(), IORESP_INT);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// We always return "yes" because of the messy problem that
|
||||
// there are additional operands with a wrong operand number (always 1)
|
||||
static bool idaapi can_have_type(const op_t &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void dsp56k_t::set_cpu(int procno)
|
||||
{
|
||||
procnum = procno;
|
||||
ph.cnbits = (is561xx() ) ? 16 : 24;
|
||||
ph.dnbits = (is561xx() || is566xx()) ? 16 : 24;
|
||||
ph.retcodes = (is561xx() ) ? retcodes61 : retcodes6x;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void dsp56k_t::load_from_idb()
|
||||
{
|
||||
xmem = get_start(get_segm_by_name("XMEM"));
|
||||
if ( !is561xx() )
|
||||
ymem = get_start(get_segm_by_name("YMEM"));
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(SET_MODULE_DATA(dsp56k_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi dsp56k_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile: // new file loaded
|
||||
{
|
||||
// data memory could already be present, check it
|
||||
xmem = get_start(get_segm_by_name("XMEM"));
|
||||
if ( !is561xx() )
|
||||
ymem = get_start(get_segm_by_name("YMEM"));
|
||||
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgfile, &cb) )
|
||||
select_device(ioh.device.c_str(), IORESP_AREA|IORESP_INT);
|
||||
else
|
||||
create_xmem_ymem();
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
// restore ptype
|
||||
set_cpu(ph.get_proc_index());
|
||||
//fall through
|
||||
case processor_t::ev_oldfile: // old file loaded
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc: // new processor type
|
||||
{
|
||||
int n = va_arg(va, int);
|
||||
// bool keep_cfg = va_argi(va, bool);
|
||||
if ( procnum == -1 )
|
||||
{
|
||||
set_cpu(n);
|
||||
}
|
||||
else if ( procnum != n ) // can't change the processor type
|
||||
{ // after the initial set up
|
||||
warning("Sorry, processor type cannot be changed after loading");
|
||||
code = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_is_sane_insn:
|
||||
{
|
||||
const insn_t &insn = *va_arg(va, const insn_t *);
|
||||
int nocrefs = va_arg(va, int);
|
||||
return is_sane_insn(insn, nocrefs) == 1 ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_mnem(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
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 *);
|
||||
segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
segend(*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_can_have_type:
|
||||
{
|
||||
const op_t *_op = va_arg(va, const op_t *);
|
||||
return can_have_type(*_op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_sp_based:
|
||||
{
|
||||
int *mode = va_arg(va, int *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
const op_t *_op = va_arg(va, const op_t *);
|
||||
*mode = is_sp_based(*insn, *_op);
|
||||
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;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_align_insn:
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
return is_align_insn(ea);
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "Motorola DSP 5600x:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"dsp56k",
|
||||
"dsp561xx",
|
||||
"dsp563xx",
|
||||
"dsp566xx",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Motorola DSP 5600x",
|
||||
"Motorola DSP 561xx",
|
||||
"Motorola DSP 563xx",
|
||||
"Motorola DSP 566xx",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_DSP56K, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_ALIGN
|
||||
| PR_BINMEM,
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
24, // 24 bits in a byte for code segments
|
||||
24, // 24 bits in a byte for other segments
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
register_names, // Register names
|
||||
qnumber(register_names), // Number of registers
|
||||
|
||||
vCS, // first
|
||||
vDS, // last
|
||||
0, // size of a segment register
|
||||
vCS, vDS,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes6x,
|
||||
|
||||
DSP56_null,
|
||||
DSP56_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
|
||||
DSP56_rts, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
4
idasdk76/module/exports.def
Normal file
4
idasdk76/module/exports.def
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
global: LPH;
|
||||
local: *;
|
||||
};
|
||||
1217
idasdk76/module/f2mc/ana.cpp
Normal file
1217
idasdk76/module/f2mc/ana.cpp
Normal file
File diff suppressed because it is too large
Load Diff
297
idasdk76/module/f2mc/emu.cpp
Normal file
297
idasdk76/module/f2mc/emu.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "f2mc.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <frame.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static int get_reglist_size(ushort reglist)
|
||||
{
|
||||
int size = 0;
|
||||
for ( int i = 0; i < 8; i++ )
|
||||
if ( (reglist >> i) & 1 )
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static bool is_bank(const op_t &op)
|
||||
{
|
||||
if ( op.type != o_reg )
|
||||
return false;
|
||||
|
||||
return op.reg == DTB
|
||||
|| op.reg == ADB
|
||||
|| op.reg == SSB
|
||||
|| op.reg == USB
|
||||
|| op.reg == DPR
|
||||
|| op.reg == PCB;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void process_imm(const insn_t &insn, const op_t &x)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, calc_outf(x));
|
||||
|
||||
if ( is_defarg(get_flags(insn.ea), x.n) )
|
||||
return; // if already defined by user
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case F2MC_add:
|
||||
case F2MC_addl:
|
||||
case F2MC_addsp:
|
||||
case F2MC_addw2:
|
||||
case F2MC_and:
|
||||
case F2MC_andw2:
|
||||
case F2MC_callv:
|
||||
case F2MC_cbne:
|
||||
case F2MC_cmp2:
|
||||
case F2MC_cmpl:
|
||||
case F2MC_cmpw2:
|
||||
case F2MC_cwbne:
|
||||
case F2MC_int:
|
||||
case F2MC_link:
|
||||
case F2MC_mov:
|
||||
case F2MC_movl:
|
||||
case F2MC_movn:
|
||||
case F2MC_movw:
|
||||
case F2MC_movx:
|
||||
case F2MC_or:
|
||||
case F2MC_orw2:
|
||||
case F2MC_sub:
|
||||
case F2MC_subl:
|
||||
case F2MC_subw2:
|
||||
case F2MC_xor:
|
||||
case F2MC_xorw2:
|
||||
op_num(insn.ea, x.n);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void f2mc_t::handle_operand(const insn_t &insn, const op_t &x, bool use)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
case o_phrase:
|
||||
case o_reglist:
|
||||
return;
|
||||
|
||||
case o_near:
|
||||
case o_far:
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
ea_t ea = x.addr;
|
||||
// 24-bit (far) operands store the full address.
|
||||
// so this calculation is needed only for near jumps/calls
|
||||
if ( x.type == o_near )
|
||||
ea = calc_code_mem(insn, x.addr);
|
||||
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
QASSERT(10102, use);
|
||||
process_imm(insn, x);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = calc_data_mem(x.addr);
|
||||
insn.add_dref(ea, x.offb, use ? dr_R : dr_W);
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_displ:
|
||||
process_imm(insn, x);
|
||||
if ( may_create_stkvars() && x.reg == RW3 )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL
|
||||
&& (pfn->flags & FUNC_FRAME) != 0
|
||||
&& insn.create_stkvar(x, x.addr, STKVAR_VALID_SIZE) )
|
||||
{
|
||||
op_stkvar(insn.ea, x.n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
inline bool add_stkpnt(func_t *pfn, sval_t delta, const insn_t &insn)
|
||||
{
|
||||
return add_auto_stkpnt(pfn, insn.ea + insn.size, delta);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void trace_sp(const insn_t &insn)
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn == NULL )
|
||||
return;
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case F2MC_int:
|
||||
case F2MC_intp:
|
||||
case F2MC_int9:
|
||||
add_stkpnt(pfn, -6*2, insn);
|
||||
break;
|
||||
case F2MC_reti:
|
||||
add_stkpnt(pfn, 6*2, insn);
|
||||
break;
|
||||
case F2MC_link:
|
||||
add_stkpnt(pfn, -2-insn.Op1.value, insn);
|
||||
break;
|
||||
case F2MC_unlink:
|
||||
add_stkpnt(pfn, -get_spd(pfn, insn.ea), insn);
|
||||
break;
|
||||
case F2MC_ret:
|
||||
add_stkpnt(pfn, 2, insn);
|
||||
break;
|
||||
case F2MC_retp:
|
||||
add_stkpnt(pfn, 2*2, insn);
|
||||
break;
|
||||
case F2MC_pushw:
|
||||
if ( insn.Op1.type == o_reglist )
|
||||
add_stkpnt(pfn, -get_reglist_size(insn.Op1.reg)*2, insn);
|
||||
else
|
||||
add_stkpnt(pfn, -2, insn);
|
||||
break;
|
||||
case F2MC_popw:
|
||||
if ( insn.Op1.type == o_reglist )
|
||||
add_stkpnt(pfn, get_reglist_size(insn.Op1.reg)*2, insn);
|
||||
else
|
||||
add_stkpnt(pfn, 2, insn);
|
||||
break;
|
||||
case F2MC_addsp:
|
||||
add_stkpnt(pfn, insn.Op1.value, insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int f2mc_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
flow = (feature & CF_STOP) == 0;
|
||||
|
||||
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_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);
|
||||
|
||||
// check for CCR changes
|
||||
if ( insn.Op1.type == o_reg && insn.Op1.reg == CCR )
|
||||
{
|
||||
op_bin(insn.ea, 1);
|
||||
|
||||
sel_t ccr = get_sreg(insn.ea, CCR);
|
||||
if ( ccr == BADSEL )
|
||||
ccr = 0;
|
||||
|
||||
if ( insn.itype == F2MC_and )
|
||||
ccr &= insn.Op2.value; // and ccr,imm8
|
||||
else if ( insn.itype == F2MC_or )
|
||||
ccr |= insn.Op2.value; // or ccr,imm8
|
||||
split_sreg_range(get_item_end(insn.ea), CCR, ccr, SR_auto);
|
||||
}
|
||||
|
||||
|
||||
// check for DTB,ADB,SSB,USB,DPR changes
|
||||
if ( insn.itype == F2MC_mov && is_bank(insn.Op1)
|
||||
&& insn.Op2.type == o_reg && insn.Op2.reg == A ) // mov dtb|adb|ssb|usb|dpr,a
|
||||
{
|
||||
sel_t bank = BADSEL;
|
||||
insn_t l;
|
||||
if ( decode_prev_insn(&l, insn.ea) != BADADDR && l.itype == F2MC_mov
|
||||
&& l.Op1.type == o_reg && l.Op1.reg == A )
|
||||
{
|
||||
if ( l.Op2.type == o_imm ) // mov a,imm8
|
||||
bank = l.Op2.value;
|
||||
else if ( is_bank(l.Op2) ) // mov a,dtb|adb|ssb|usb|dpr|pcb
|
||||
{
|
||||
bank = get_sreg(l.ea, l.Op2.reg);
|
||||
if ( bank == BADSEL )
|
||||
bank = 0;
|
||||
}
|
||||
}
|
||||
if ( bank != BADSEL )
|
||||
split_sreg_range(get_item_end(insn.ea), insn.Op1.reg, bank, SR_auto);
|
||||
}
|
||||
|
||||
|
||||
// determine if the next instruction should be executed
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
flow = false;
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
if ( may_trace_sp() )
|
||||
{
|
||||
if ( !flow )
|
||||
recalc_spd(insn.ea); // recalculate SP register for the next insn
|
||||
else
|
||||
trace_sp(insn);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
if ( pfn != NULL )
|
||||
{
|
||||
if ( pfn->frame == BADNODE )
|
||||
{
|
||||
ea_t ea = pfn->start_ea;
|
||||
if ( ea + 4 < pfn->end_ea ) // minimum 2+1+1 bytes needed
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, ea);
|
||||
if ( insn.itype == F2MC_link )
|
||||
{
|
||||
size_t localsize = (size_t)insn.Op1.value;
|
||||
ushort regsize = 2;
|
||||
decode_insn(&insn, ea + 2);
|
||||
pfn->flags |= FUNC_FRAME;
|
||||
return add_frame(pfn, localsize, regsize, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &)
|
||||
{
|
||||
return OP_SP_ADD | OP_FP_BASED;
|
||||
}
|
||||
159
idasdk76/module/f2mc/f2mc.hpp
Normal file
159
idasdk76/module/f2mc/f2mc.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _F2MC_HPP
|
||||
#define _F2MC_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <segregs.hpp>
|
||||
#include "ins.hpp"
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
//------------------------------------------------------------------
|
||||
enum regnum_t
|
||||
{
|
||||
A, // accumulator
|
||||
AL, // accumulator
|
||||
AH, // accumulator
|
||||
PC, // program counter
|
||||
SP, // stack pointer
|
||||
R0,
|
||||
R1,
|
||||
R2,
|
||||
R3,
|
||||
R4,
|
||||
R5,
|
||||
R6,
|
||||
R7,
|
||||
RW0,
|
||||
RW1,
|
||||
RW2,
|
||||
RW3,
|
||||
RW4,
|
||||
RW5,
|
||||
RW6,
|
||||
RW7,
|
||||
RL0,
|
||||
RL1,
|
||||
RL2,
|
||||
RL3,
|
||||
|
||||
PCB, // program bank register
|
||||
DTB, // data bank register
|
||||
ADB, // additional data bank register
|
||||
SSB, // system stack bank register
|
||||
USB, // user stack bank register
|
||||
CCR, // condition code register
|
||||
DPR, // direct page register
|
||||
rVcs, rVds, // virtual registers for code and data segments
|
||||
|
||||
SPB, // stack pointer bank register
|
||||
PS, // processor status
|
||||
ILM, // interrupt level mask register
|
||||
RP // register bank pointer
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// specific processor records
|
||||
|
||||
#define default_bank segpref
|
||||
#define prefix_bank auxpref_u8[1]
|
||||
#define op_bank auxpref_u8[0]
|
||||
// o_phrase = @reg+(f2mc_index) (f2mc_index if PHRASE_INDEX)
|
||||
#define at specflag1 // number of @ indirections (dtype @ = op.dtype)
|
||||
#define special_mode specflag2
|
||||
#define MODE_INC 1
|
||||
#define MODE_INDEX 2
|
||||
#define f2mc_index specval_shorts.high
|
||||
#define o_reglist o_idpspec0
|
||||
// o_disp = @reg+value
|
||||
#define addr_dtyp specflag3
|
||||
#define MODE_BIT 1
|
||||
#define byte_bit specflag4
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// processor types
|
||||
|
||||
typedef uchar proctype_t;
|
||||
|
||||
const proctype_t F2MC16L = 0;
|
||||
const proctype_t F2MC16LX = 1;
|
||||
|
||||
extern ea_t dataseg;
|
||||
//------------------------------------------------------------------
|
||||
#define F2MC_MACRO 0x0001 // use instruction macros
|
||||
inline ea_t calc_code_mem(const insn_t &insn, ea_t ea) { return to_ea(insn.cs, ea); }
|
||||
inline ea_t calc_data_mem(ea_t ea) { return (get_sreg(ea, DTB) << 16) | ea; }
|
||||
|
||||
int get_signed(int byte,int mask);
|
||||
|
||||
ea_t map_port(ea_t from);
|
||||
int calc_outf(const op_t &x);
|
||||
//------------------------------------------------------------------
|
||||
void idaapi f2mc_segend(outctx_t &ctx, segment_t *seg);
|
||||
|
||||
bool idaapi create_func_frame(func_t *pfn);
|
||||
int idaapi is_sp_based(const insn_t &insn, const op_t &x);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct f2mc_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct f2mc_t ±
|
||||
f2mc_iohandler_t(f2mc_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual const char *aux_segm() const override { return "FSR"; }
|
||||
virtual bool area_processing(ea_t /*start*/, ea_t /*end*/, const char * /*name*/, const char * /*aclass*/) override;
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line) override;
|
||||
};
|
||||
|
||||
struct f2mc_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
f2mc_iohandler_t ioh = f2mc_iohandler_t(*this, helper);
|
||||
const char *cfgname = nullptr;
|
||||
proctype_t ptype = F2MC16LX; // contains processor type
|
||||
ushort idpflags = F2MC_MACRO;
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
void load_symbols(int _respect_info);
|
||||
const char *find_sym(ea_t address);
|
||||
const char *find_bit(ea_t address, int bit);
|
||||
bool exist_bits(ea_t ea, int bitl, int bith);
|
||||
void f2mc_set_device_name(int _respect_info);
|
||||
void choose_and_set_device(int flags);
|
||||
inline void choose_device();
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void * value,
|
||||
bool idb_loaded);
|
||||
void adjust_ea_bit(ea_t &ea, int &bit);
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool use);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void ana_F2MC16LX(insn_t &insn);
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void f2mc_header(outctx_t &ctx);
|
||||
void f2mc_assumes(outctx_t &ctx);
|
||||
void print_segment_register(outctx_t &ctx, int reg, sel_t value);
|
||||
void f2mc_segstart(outctx_t &ctx, segment_t *Srange) const;
|
||||
void f2mc_footer(outctx_t &ctx) const;
|
||||
|
||||
void save_idpflags() { helper.altset(-1, idpflags); }
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ f2mc"
|
||||
#define PROCMOD_NAME f2mc
|
||||
|
||||
#endif // _F2MC_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user