update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

View 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;
}

View 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;
}

View 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);

View 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

View 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

View 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

View 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");
}
}

View 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
};

View 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;
}

View 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

View 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

View 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;
}

View 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);

View 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

View 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

View 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

View 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

View 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");
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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;
}

View 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);

View 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

View 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

View 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");
}
}

View 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
};

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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;
}

View 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);

View 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

View 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

View 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");
}
}

View 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
};

View 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 &reg, 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;
}

View 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;
}

View 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 &reg, 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

View 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);

View 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

View 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

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

502
idasdk76/module/arc/arc.hpp Normal file
View 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 &pm;
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

File diff suppressed because it is too large Load Diff

361
idasdk76/module/arc/ins.cpp Normal file
View 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
View 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

View 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
View 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
View 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(&regs);
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

File diff suppressed because it is too large Load Diff

View 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
View 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

File diff suppressed because it is too large Load Diff

136
idasdk76/module/avr/avr.hpp Normal file
View 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 &pm;
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
View 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
View 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
View 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

View 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

View 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
View 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
View 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 &pm;
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
View 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
View 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
;

View 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

View 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
View 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
View 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

View 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
View 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
View 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
};

View 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
};

View 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;
}

View 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

View 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

View 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;
}

View 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);

View 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

View 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

View 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");
}
}

View 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
};

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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 &pm;
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

View 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;
}

View 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);

View 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

View 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

View 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);
}

View 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
};

View File

@@ -0,0 +1,4 @@
{
global: LPH;
local: *;
};

1217
idasdk76/module/f2mc/ana.cpp Normal file

File diff suppressed because it is too large Load Diff

View 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;
}

View 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 &pm;
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