update to ida 7.6, add builds
This commit is contained in:
819
idasdk76/module/avr/ana.cpp
Normal file
819
idasdk76/module/avr/ana.cpp
Normal file
@@ -0,0 +1,819 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include <fixup.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
0000 0000 0000 0000 nop
|
||||
0000 0001 dddd rrrr movw Rd,Rr
|
||||
0000 0010 dddd rrrr muls Rd,Rr
|
||||
0000 0011 0ddd 0rrr mulsu Rd,Rr
|
||||
0000 0011 0ddd 1rrr fmul Rd,Rr
|
||||
0000 0011 1ddd 0rrr fmuls Rd,Rr
|
||||
0000 0011 1ddd 1rrr fmulsu Rd,Rr
|
||||
0000 01rd dddd rrrr cpc rd, rr
|
||||
0000 10rd dddd rrrr sbc rd, rr
|
||||
0000 11rd dddd rrrr add rd, rr lsl rd if rd==rr
|
||||
0001 00rd dddd rrrr cpse rd, rr
|
||||
0001 01rd dddd rrrr cp rd, rr
|
||||
0001 10rd dddd rrrr sub rd, rr
|
||||
0001 11rd dddd rrrr adc rd, rr rol rd if rd==rr
|
||||
0010 00rd dddd rrrr and rd, rr tst rd if rd==rr
|
||||
0010 01rd dddd rrrr eor rd, rr clr rd if rd==rr
|
||||
0010 10rd dddd rrrr or rd, rr
|
||||
0010 11rd dddd rrrr mov rd, rr
|
||||
0011 kkkk dddd kkkk cpi rd, k (16<=d<=31)
|
||||
0100 kkkk dddd kkkk sbci rd, k (16<=d<=31)
|
||||
0101 kkkk dddd kkkk subi rd, k (16<=d<=31)
|
||||
0110 kkkk dddd kkkk ori/sbr rd, k (16<=d<=31)
|
||||
0111 kkkk dddd kkkk andi rd, k (16<=d<=31) cbr rd, k if op2 is bitwise negated
|
||||
1000 000d dddd 0000 ld rd, Z
|
||||
1000 000d dddd 1000 ld rd, Y
|
||||
1000 001r rrrr 0000 st Z, rr
|
||||
1000 001r rrrr 1000 st Y, rr
|
||||
1001 000d dddd 0000(1*k)lds rd, k
|
||||
1001 000d dddd 0001 ld rd, Z+
|
||||
1001 000d dddd 0010 ld rd, -Z
|
||||
1001 000d dddd 0100 lpm Rd, Z
|
||||
1001 000d dddd 0101 lpm Rd, Z+
|
||||
1001 000d dddd 0110 elpm Rd, Z
|
||||
1001 000d dddd 0111 elpm Rd, Z+
|
||||
1001 000d dddd 1001 ld rd, Y+
|
||||
1001 000d dddd 1010 ld rd, -Y
|
||||
1001 000d dddd 1100 ld rd, X
|
||||
1001 000d dddd 1101 ld rd, X+
|
||||
1001 000d dddd 1110 ld rd, -X
|
||||
1001 000d dddd 1111 pop rd
|
||||
1001 001d dddd 0000(1*k)sts k, rd
|
||||
1001 001d dddd 1111 push rd
|
||||
1001 001r rrrr 0001 st Z+, rr
|
||||
1001 001r rrrr 0010 st -Z, rr
|
||||
1001 001r rrrr 0100 xch Z, rr
|
||||
1001 001r rrrr 0101 las Z, rr
|
||||
1001 001r rrrr 0110 lac Z, rr
|
||||
1001 001r rrrr 0111 lat Z, rr
|
||||
1001 001r rrrr 1001 st Y+, rr
|
||||
1001 001r rrrr 1010 st -Y, rr
|
||||
1001 001r rrrr 1100 st X, rr
|
||||
1001 001r rrrr 1101 st X+, rr
|
||||
1001 001r rrrr 1110 st -X, rr
|
||||
1001 0100 0000 1000 sec
|
||||
1001 0100 0001 1000 sez
|
||||
1001 0100 0010 1000 sen
|
||||
1001 0100 0011 1000 sev
|
||||
1001 0100 0100 1000 ses
|
||||
1001 0100 0101 1000 seh
|
||||
1001 0100 0110 1000 set
|
||||
1001 0100 0111 1000 sei
|
||||
1001 0100 0sss 1000 bset s
|
||||
1001 0100 1000 1000 clc
|
||||
1001 0100 1001 1000 clz
|
||||
1001 0100 1010 1000 cln
|
||||
1001 0100 1011 1000 clv
|
||||
1001 0100 1100 1000 cls
|
||||
1001 0100 1101 1000 clh
|
||||
1001 0100 1110 1000 clt
|
||||
1001 0100 1111 1000 cli
|
||||
1001 0100 1sss 1000 bclr s
|
||||
1001 0100 0000 1001 ijmp
|
||||
1001 0100 0001 1001 eijmp
|
||||
1001 0100 KKKK 1011 des K
|
||||
1001 0101 0xx0 1000 ret
|
||||
1001 0101 0xx1 1000 reti
|
||||
1001 0101 100x 1000 sleep
|
||||
1001 0101 101x 1000 wdr
|
||||
1001 0101 110x 1000 lpm
|
||||
1001 0101 1101 1000 elpm
|
||||
1001 0101 1110 1000 spm
|
||||
1001 0101 1111 1000 espm
|
||||
1001 0101 0000 1001 icall
|
||||
1001 0101 0001 1001 eicall
|
||||
1001 010d dddd 0000 com rd
|
||||
1001 010d dddd 0001 neg rd
|
||||
1001 010d dddd 0010 swap rd
|
||||
1001 010d dddd 0011 inc rd
|
||||
1001 010d dddd 0101 asr rd
|
||||
1001 010d dddd 0110 lsr rd
|
||||
1001 010d dddd 0111 ror rd
|
||||
1001 010d dddd 1010 dec rd
|
||||
1001 010k kkkk 110k(1*k)jmp k
|
||||
1001 010k kkkk 111k(1*k)call k
|
||||
1001 0110 kkdd kkkk adiw rd, k (d=24,26,28,30)
|
||||
1001 0111 kkdd kkkk sbiw rd, k (d=24,26,28,30)
|
||||
1001 1000 pppp pbbb cbi p, b
|
||||
1001 1001 pppp pbbb sbic p, b
|
||||
1001 1010 pppp pbbb sbi p, b
|
||||
1001 1011 pppp pbbb sbis p, b
|
||||
1001 11rd dddd rrrr mul rd, rr
|
||||
1011 0ppd dddd pppp in rd, p
|
||||
1011 1ppr rrrr pppp out p, rr
|
||||
10q0 qq0d dddd 0qqq ldd rd, Z+q
|
||||
10q0 qq0d dddd 1qqq ldd rd, Y+q
|
||||
10q0 qq1r rrrr 0qqq std Z+d, rr
|
||||
10q0 qq1r rrrr 1qqq std Y+d, rr
|
||||
1100 kkkk kkkk kkkk rjmp k
|
||||
1101 kkkk kkkk kkkk rcall k
|
||||
1110 1111 dddd 1111 ser rd (16<=d<=31)
|
||||
1110 kkkk dddd kkkk ldi rd, k
|
||||
1111 00kk kkkk k000 brcs/brlo k
|
||||
1111 00kk kkkk k001 brne k
|
||||
1111 00kk kkkk k010 brmi k
|
||||
1111 00kk kkkk k011 brvs k
|
||||
1111 00kk kkkk k100 brlt k
|
||||
1111 00kk kkkk k101 brhs k
|
||||
1111 00kk kkkk k110 brts k
|
||||
1111 00kk kkkk k111 brie k
|
||||
1111 00kk kkkk ksss brbs s, k
|
||||
1111 01kk kkkk k000 brcc/brsh k
|
||||
1111 01kk kkkk k001 breq k
|
||||
1111 01kk kkkk k010 brpl k
|
||||
1111 01kk kkkk k011 brvc k
|
||||
1111 01kk kkkk k100 brge k
|
||||
1111 01kk kkkk k101 brhc k
|
||||
1111 01kk kkkk k110 brtc k
|
||||
1111 01kk kkkk k111 brid k
|
||||
1111 01kk kkkk ksss brbc s, k
|
||||
1111 100d dddd 0bbb bld rd, b
|
||||
1111 101d dddd Xbbb bst rd, b
|
||||
1111 110r rrrr xbbb sbrc rr, b
|
||||
1111 111r rrrr xbbb sbrs rr, b
|
||||
*/
|
||||
|
||||
// handle wraparound jumps
|
||||
inline uint32 avr_t::code_address(const insn_t &insn, signed int delta) const
|
||||
{
|
||||
ea_t newip = insn.ip + 1 + delta;
|
||||
uint32 size = romsize != 0 ? romsize : 0x10000;
|
||||
if ( insn.ip > size )
|
||||
return newip;
|
||||
else
|
||||
return newip % size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline ushort ua_next_full_byte(insn_t &insn)
|
||||
{
|
||||
return (ushort)get_wide_byte(insn.ea + insn.size++);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opreg(op_t &x, uint16 n, bool rpair = false)
|
||||
{
|
||||
x.type = o_reg;
|
||||
x.dtype = dt_byte;
|
||||
x.reg = n;
|
||||
if ( rpair )
|
||||
x.reg_pair = 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void avr_t::opimm(const insn_t &insn, op_t &x, int value) const
|
||||
{
|
||||
x.type = o_imm;
|
||||
x.dtype = dt_byte;
|
||||
x.value = value;
|
||||
x.specflag1 = uchar(helper.charval_ea(insn.ea, ELF_AVR_TAG) == ELF_AVR_LDI_NEG);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opnear(op_t &x, ea_t addr)
|
||||
{
|
||||
x.type = o_near;
|
||||
x.dtype = dt_code;
|
||||
x.addr = addr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opmem(insn_t &insn, op_t &x)
|
||||
{
|
||||
x.type = o_mem;
|
||||
x.dtype = dt_byte;
|
||||
x.offb = (char)insn.size;
|
||||
x.addr = ua_next_full_byte(insn);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 0001 10rd dddd rrrr sub rd, rr 6
|
||||
static void tworegs(insn_t &insn, int code)
|
||||
{
|
||||
opreg(insn.Op1, (code >> 4) & 31);
|
||||
opreg(insn.Op2, (code & 15) | ((code >> 5) & 16));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 1000 000d dddd 1000 ld rd, Y
|
||||
inline void opregd(op_t &x, int code)
|
||||
{
|
||||
opreg(x, (code >> 4) & 31);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opphr(op_t &x, phrase_t phrase)
|
||||
{
|
||||
x.type = o_phrase;
|
||||
x.phrase = phrase;
|
||||
x.dtype = dt_byte;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opport(op_t &x, int portnum)
|
||||
{
|
||||
x.type = o_port;
|
||||
x.addr = portnum;
|
||||
x.dtype = dt_byte;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void opdisp(op_t &x, phrase_t phrase, int delta)
|
||||
{
|
||||
if ( delta )
|
||||
{
|
||||
x.type = o_displ;
|
||||
x.phrase = phrase;
|
||||
x.addr = delta;
|
||||
x.dtype = dt_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
opphr(x, phrase);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int avr_t::ana(insn_t *_insn)
|
||||
{
|
||||
if ( _insn == NULL )
|
||||
return 0;
|
||||
insn_t &insn = *_insn;
|
||||
// if ( insn.ip & 1 ) return 0; // alignment error
|
||||
int code = ua_next_full_byte(insn);
|
||||
switch ( code >> 12 )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
// 0000 0000 0000 0000 nop 0
|
||||
// 0000 0001 dddd rrrr movw Rd, Rr 0
|
||||
// 0000 0010 dddd rrrr muls Rd, Rr 0
|
||||
// 0000 0011 0ddd 0rrr mulsu Rd, Rr 0
|
||||
// 0000 0011 0ddd 1rrr fmul Rd, Rr 0
|
||||
// 0000 0011 1ddd 0rrr fmuls Rd, Rr 0
|
||||
// 0000 0011 1ddd 1rrr fmulsu Rd, Rr 0
|
||||
// 0000 01rd dddd rrrr cpc rd, rr 1
|
||||
// 0000 10rd dddd rrrr sbc rd, rr 2
|
||||
// 0000 11rd dddd rrrr add rd, rr 3 lsl rd if rd==rr
|
||||
// 0001 00rd dddd rrrr cpse rd, rr 4
|
||||
// 0001 01rd dddd rrrr cp rd, rr 5
|
||||
// 0001 10rd dddd rrrr sub rd, rr 6
|
||||
// 0001 11rd dddd rrrr adc rd, rr 7 rol rd if rd==rr
|
||||
// 0010 00rd dddd rrrr and rd, rr 8 tst rd if rd==rr
|
||||
// 0010 01rd dddd rrrr eor rd, rr 9 clr rd if rd==rr
|
||||
// 0010 10rd dddd rrrr or rd, rr A
|
||||
// 0010 11rd dddd rrrr mov rd, rr B
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_nop, // 0
|
||||
AVR_cpc, // 1
|
||||
AVR_sbc, // 2
|
||||
AVR_add, // 3
|
||||
AVR_cpse, // 4
|
||||
AVR_cp, // 5
|
||||
AVR_sub, // 6
|
||||
AVR_adc, // 7
|
||||
AVR_and, // 8
|
||||
AVR_eor, // 9
|
||||
AVR_or, // A
|
||||
AVR_mov // B
|
||||
};
|
||||
int idx = (code >> 10) & 15;
|
||||
insn.itype = itypes[idx];
|
||||
tworegs(insn, code);
|
||||
switch ( idx )
|
||||
{
|
||||
case 0:
|
||||
switch ( (code>>8) & 3 )
|
||||
{
|
||||
case 0: // nop
|
||||
if ( code != 0 )
|
||||
return 0;
|
||||
insn.Op1.type = insn.Op2.type = o_void;
|
||||
break;
|
||||
case 1: // movw
|
||||
insn.itype = AVR_movw;
|
||||
opreg(insn.Op1, ((code >> 3) & 30), true);
|
||||
opreg(insn.Op2, ((code << 1) & 30), true);
|
||||
break;
|
||||
case 2: // muls
|
||||
insn.itype = AVR_muls;
|
||||
opreg(insn.Op1, 16 + (((code >> 4) & 15)));
|
||||
opreg(insn.Op2, 16 + (((code >> 0) & 15)));
|
||||
break;
|
||||
// 0000 0011 0ddd 0rrr mulsu Rd, Rr 0
|
||||
// 0000 0011 0ddd 1rrr fmul Rd, Rr 0
|
||||
// 0000 0011 1ddd 0rrr fmuls Rd, Rr 0
|
||||
// 0000 0011 1ddd 1rrr fmulsu Rd, Rr 0
|
||||
case 3: // mulsu, fmul, fmuls, fmulsu
|
||||
{
|
||||
idx = ((code >> 6) & 2) | ((code>>3) & 1);
|
||||
static const uchar subtypes[] =
|
||||
{ AVR_mulsu, AVR_fmul, AVR_fmuls, AVR_fmulsu };
|
||||
insn.itype = subtypes[idx];
|
||||
}
|
||||
opreg(insn.Op1, 16 + (((code >> 4) & 7)));
|
||||
opreg(insn.Op2, 16 + (((code >> 0) & 7)));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3: // lsl
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_lsl;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
case 7: // rol
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_rol;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
case 8: // tst
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_tst;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
case 9: // clr
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
{
|
||||
insn.itype = AVR_clr;
|
||||
insn.Op2.type = o_void;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
// 0011 kkkk dddd kkkk cpi rd, k (16<=d<=31)
|
||||
// 0100 kkkk dddd kkkk sbci rd, k (16<=d<=31)
|
||||
// 0101 kkkk dddd kkkk subi rd, k (16<=d<=31)
|
||||
// 0110 kkkk dddd kkkk ori/sbr rd, k (16<=d<=31)
|
||||
// 0111 kkkk dddd kkkk andi rd, k (16<=d<=31) cbr rd, k if op2 is bitwise negated
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_cpi,
|
||||
AVR_sbci,
|
||||
AVR_subi,
|
||||
AVR_ori,
|
||||
AVR_andi,
|
||||
};
|
||||
insn.itype = itypes[(code >> 12) - 3];
|
||||
opreg(insn.Op1, ((code >> 4) & 15) + 16);
|
||||
opimm(insn, insn.Op2, (code & 0x0F) | ((code >> 4) & 0xF0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 10:
|
||||
// 10q0 qq0d dddd 0qqq ldd rd, Z+q
|
||||
// 10q0 qq0d dddd 1qqq ldd rd, Y+q
|
||||
// 10q0 qq1r rrrr 0qqq std Z+d, rr
|
||||
// 10q0 qq1r rrrr 1qqq std Y+d, rr
|
||||
// 1000 000d dddd 0000 ld rd, Z
|
||||
// 1000 000d dddd 1000 ld rd, Y
|
||||
// 1000 001r rrrr 0000 st Z, rr
|
||||
// 1000 001r rrrr 1000 st Y, rr
|
||||
{
|
||||
int delta = ((code & 0x2000) >> 8)
|
||||
| ((code & 0x0C00) >> 7)
|
||||
| (code & 0x0007);
|
||||
if ( code & 0x200 )
|
||||
{
|
||||
insn.itype = delta ? AVR_std : AVR_st;
|
||||
opdisp(insn.Op1, (code & 8) ? PH_Y : PH_Z, delta);
|
||||
opregd(insn.Op2, code);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = delta ? AVR_ldd : AVR_ld;
|
||||
opregd(insn.Op1, code);
|
||||
opdisp(insn.Op2, (code & 8) ? PH_Y : PH_Z, delta);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
switch ( (code >> 8) & 15 )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// 1001 000d dddd 0000(8*k)lds rd, k 0
|
||||
// 1001 000d dddd 0001 ld rd, Z+ 1
|
||||
// 1001 000d dddd 0010 ld rd, -Z 2
|
||||
// 1001 000d dddd 0100 lpm Rd, Z 4
|
||||
// 1001 000d dddd 0101 lpm Rd, Z+ 5
|
||||
// 1001 000d dddd 0110 elpm Rd, Z 6
|
||||
// 1001 000d dddd 0111 elpm Rd, Z+ 7
|
||||
// 1001 000d dddd 1001 ld rd, Y+ 9
|
||||
// 1001 000d dddd 1010 ld rd, -Y A
|
||||
// 1001 000d dddd 1100 ld rd, X C
|
||||
// 1001 000d dddd 1101 ld rd, X+ D
|
||||
// 1001 000d dddd 1110 ld rd, -X E
|
||||
// 1001 000d dddd 1111 pop rd F
|
||||
|
||||
// 1001 001d dddd 0000(8*k)sts k, rd 0
|
||||
// 1001 001r rrrr 0001 st Z+, rr 1
|
||||
// 1001 001r rrrr 0010 st -Z, rr 2
|
||||
// 1001 001r rrrr 0011 <unallocated> 3
|
||||
// 1001 001r rrrr 0100 xch Z, rr 4
|
||||
// 1001 001r rrrr 0101 las Z, rr 5
|
||||
// 1001 001r rrrr 0110 lac Z, rr 6
|
||||
// 1001 001r rrrr 0111 lat Z, rr 7
|
||||
// 1001 001r rrrr 1000 <unallocated> 8
|
||||
// 1001 001r rrrr 1001 st Y+, rr 9
|
||||
// 1001 001r rrrr 1010 st -Y, rr A
|
||||
// 1001 001r rrrr 1100 st X, rr C
|
||||
// 1001 001r rrrr 1101 st X+, rr D
|
||||
// 1001 001r rrrr 1110 st -X, rr E
|
||||
// 1001 001d dddd 1111 push rd F
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_lds, AVR_ld, AVR_ld, 0,
|
||||
AVR_lpm, AVR_lpm, AVR_elpm, AVR_elpm,
|
||||
0, AVR_ld, AVR_ld, 0,
|
||||
AVR_ld, AVR_ld, AVR_ld, AVR_pop
|
||||
};
|
||||
insn.itype = itypes[code & 15];
|
||||
opregd(insn.Op1, code);
|
||||
switch ( code & 15 )
|
||||
{
|
||||
case 0x0:
|
||||
opmem(insn, insn.Op2);
|
||||
switch ( helper.charval_ea(insn.ea+1, ELF_AVR_TAG) )
|
||||
{
|
||||
case ELF_AVR_EEP_OFF:
|
||||
insn.Op2.addr += ELF_AVR_EEPROMBASE-ELF_AVR_RAMBASE;
|
||||
case ELF_AVR_RAM_OFF:
|
||||
insn.Op2.addr += ELF_AVR_RAMBASE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x1: opphr(insn.Op2, PH_ZPLUS); break;
|
||||
case 0x2: opphr(insn.Op2, PH_MINUSZ); break;
|
||||
case 0x4: opphr(insn.Op2, PH_Z); break;
|
||||
case 0x5: opphr(insn.Op2, PH_ZPLUS); break;
|
||||
case 0x6: opphr(insn.Op2, PH_Z); break;
|
||||
case 0x7: opphr(insn.Op2, PH_ZPLUS); break;
|
||||
case 0x9: opphr(insn.Op2, PH_YPLUS); break;
|
||||
case 0xA: opphr(insn.Op2, PH_MINUSY); break;
|
||||
case 0xC: opphr(insn.Op2, PH_X); break;
|
||||
case 0xD: opphr(insn.Op2, PH_XPLUS); break;
|
||||
case 0xE: opphr(insn.Op2, PH_MINUSX); break;
|
||||
case 0xF: break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if ( code & 0x200 )
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case AVR_pop:
|
||||
insn.itype = AVR_push;
|
||||
break;
|
||||
case AVR_lds:
|
||||
insn.itype = AVR_sts;
|
||||
goto SWAP_OPERANDS;
|
||||
case AVR_ld:
|
||||
insn.itype = AVR_st;
|
||||
SWAP_OPERANDS:
|
||||
{
|
||||
op_t tmp = insn.Op1;
|
||||
insn.Op1 = insn.Op2;
|
||||
insn.Op2 = tmp;
|
||||
}
|
||||
break;
|
||||
case AVR_lpm:
|
||||
case AVR_elpm:
|
||||
// 1001 001r rrrr 0100 xch Z, rr 4
|
||||
// 1001 001r rrrr 0101 las Z, rr 5
|
||||
// 1001 001r rrrr 0110 lac Z, rr 6
|
||||
// 1001 001r rrrr 0111 lat Z, rr 7
|
||||
{
|
||||
static const uchar itypes2[] =
|
||||
{
|
||||
AVR_xch, AVR_las, AVR_lac, AVR_lat,
|
||||
};
|
||||
insn.itype = itypes2[code & 3];
|
||||
opphr(insn.Op1, PH_Z);
|
||||
opregd(insn.Op2, code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
switch ( code & 0xF )
|
||||
{
|
||||
case 11:
|
||||
// 1001 0100 KKKK 1011 des K
|
||||
switch ( code & 0x0F00 )
|
||||
{
|
||||
case 0x0400:
|
||||
insn.itype = AVR_des;
|
||||
opimm(insn, insn.Op1, (code >> 4) & 0xF);
|
||||
break;
|
||||
default: return 0;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
// 1001 0100 0000 1001 ijmp
|
||||
// 1001 0100 0001 1001 eijmp
|
||||
// 1001 0101 0000 1001 icall
|
||||
// 1001 0101 0001 1001 eicall
|
||||
switch ( code & 0xFF0 )
|
||||
{
|
||||
case 0x400: insn.itype = AVR_ijmp; break;
|
||||
case 0x410: insn.itype = AVR_eijmp; break;
|
||||
case 0x500: insn.itype = AVR_icall; break;
|
||||
case 0x510: insn.itype = AVR_eicall; break;
|
||||
default: return 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
// 1001 0101 0xx0 1000 ret
|
||||
// 1001 0101 0xx1 1000 reti
|
||||
// 1001 0101 100x 1000 sleep
|
||||
// 1001 0101 101x 1000 wdr
|
||||
// 1001 0101 1100 1000 lpm
|
||||
// 1001 0101 1101 1000 elpm
|
||||
// 1001 0101 1110 1000 spm
|
||||
// 1001 0101 1111 1000 espm
|
||||
if ( (code & 0x0F00) == 0x0500 )
|
||||
{
|
||||
if ( (code & 0x0090) == 0x0000 )
|
||||
insn.itype = AVR_ret;
|
||||
else if ( (code & 0x0090) == 0x0010 )
|
||||
insn.itype = AVR_reti;
|
||||
else if ( (code & 0x00E0) == 0x0080 )
|
||||
insn.itype = AVR_sleep;
|
||||
else if ( (code & 0x00E0) == 0x00A0 )
|
||||
insn.itype = AVR_wdr;
|
||||
else if ( (code & 0x00F0) == 0x00C0 )
|
||||
insn.itype = AVR_lpm;
|
||||
else if ( (code & 0x00F0) == 0x00D0 )
|
||||
insn.itype = AVR_elpm;
|
||||
else if ( (code & 0x00F0) == 0x00E0 )
|
||||
insn.itype = AVR_spm;
|
||||
else if ( (code & 0x00F0) == 0x00F0 )
|
||||
insn.itype = AVR_espm;
|
||||
break;
|
||||
}
|
||||
// 1001 0100 0000 1000 sec 0
|
||||
// 1001 0100 0001 1000 sez 1
|
||||
// 1001 0100 0010 1000 sen 2
|
||||
// 1001 0100 0011 1000 sev 3
|
||||
// 1001 0100 0100 1000 ses 4
|
||||
// 1001 0100 0101 1000 seh 5
|
||||
// 1001 0100 0110 1000 set 6
|
||||
// 1001 0100 0111 1000 sei 7
|
||||
// 1001 0100 0sss 1000 bset s
|
||||
// 1001 0100 1000 1000 clc 8
|
||||
// 1001 0100 1001 1000 clz 9
|
||||
// 1001 0100 1010 1000 cln a
|
||||
// 1001 0100 1011 1000 clv b
|
||||
// 1001 0100 1100 1000 cls c
|
||||
// 1001 0100 1101 1000 clh d
|
||||
// 1001 0100 1110 1000 clt e
|
||||
// 1001 0100 1111 1000 cli f
|
||||
// 1001 0100 1sss 1000 bclr s
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_sec, AVR_sez, AVR_sen, AVR_sev,
|
||||
AVR_ses, AVR_seh, AVR_set, AVR_sei,
|
||||
AVR_clc, AVR_clz, AVR_cln, AVR_clv,
|
||||
AVR_cls, AVR_clh, AVR_clt, AVR_cli,
|
||||
};
|
||||
insn.itype = itypes[(code >> 4) & 15];
|
||||
}
|
||||
break; // case 8
|
||||
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 10:
|
||||
// 1001 010d dddd 0000 com rd 0
|
||||
// 1001 010d dddd 0001 neg rd 1
|
||||
// 1001 010d dddd 0010 swap rd 2
|
||||
// 1001 010d dddd 0011 inc rd 3
|
||||
// 1001 010d dddd 0101 asr rd 5
|
||||
// 1001 010d dddd 0110 lsr rd 6
|
||||
// 1001 010d dddd 0111 ror rd 7
|
||||
// 1001 010d dddd 1010 dec rd 10
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_com, AVR_neg, AVR_swap, AVR_inc,
|
||||
0, AVR_asr, AVR_lsr, AVR_ror,
|
||||
0, 0, AVR_dec,
|
||||
};
|
||||
insn.itype = itypes[code & 15];
|
||||
opregd(insn.Op1, code);
|
||||
}
|
||||
break; // case 8
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
// 1001 010k kkkk 110k(1*k)jmp k
|
||||
// 1001 010k kkkk 111k(1*k)call k
|
||||
insn.itype = (code & 2) ? AVR_call : AVR_jmp;
|
||||
opnear(insn.Op1, (ea_t((code & 1) | ((code >> 3) & 0x3E)) << 16)
|
||||
| ua_next_full_byte(insn));
|
||||
if ( helper.charval_ea(insn.ea+1, ELF_AVR_TAG) == ELF_AVR_ABS_OFF )
|
||||
insn.Op1.addr += ELF_AVR_ABSBASE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 7:
|
||||
// 1001 0110 kkdd kkkk adiw rd, k (d=24,26,28,30)
|
||||
// 1001 0111 kkdd kkkk sbiw rd, k (d=24,26,28,30)
|
||||
insn.itype = (code & 0x100) ? AVR_sbiw : AVR_adiw;
|
||||
opreg(insn.Op1, R24 + ((code >> 3) & 6), true);
|
||||
opimm(insn, insn.Op2, ((code >> 2) & 0x30) | (code & 0x0F));
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
// 1001 1000 pppp pbbb cbi p, b
|
||||
// 1001 1001 pppp pbbb sbic p, b
|
||||
// 1001 1010 pppp pbbb sbi p, b
|
||||
// 1001 1011 pppp pbbb sbis p, b
|
||||
{
|
||||
static const uchar itypes[] = { AVR_cbi, AVR_sbic, AVR_sbi, AVR_sbis };
|
||||
insn.itype = itypes[(code >> 8) & 3];
|
||||
opport(insn.Op1, (code >> 3) & 0x1F);
|
||||
opimm(insn, insn.Op2, code & 7);
|
||||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
// 1001 11rd dddd rrrr mul rd, rr
|
||||
insn.itype = AVR_mul;
|
||||
tworegs(insn, code);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
// 1011 0ppd dddd pppp in rd, p
|
||||
// 1011 1ppr rrrr pppp out p, rr
|
||||
if ( code & 0x800 )
|
||||
{
|
||||
insn.itype = AVR_out;
|
||||
opport(insn.Op1, ((code & 0x0600) >> 5) | (code & 15));
|
||||
opregd(insn.Op2, code);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn.itype = AVR_in;
|
||||
opregd(insn.Op1, code);
|
||||
opport(insn.Op2, ((code & 0x0600) >> 5) | (code & 15));
|
||||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
case 13:
|
||||
// 1100 kkkk kkkk kkkk rjmp k
|
||||
// 1101 kkkk kkkk kkkk rcall k
|
||||
{
|
||||
insn.itype = (code & 0x1000) ? AVR_rcall : AVR_rjmp;
|
||||
signed int delta = (code & 0xFFF);
|
||||
if ( delta & 0x800 )
|
||||
delta |= ~0xFFF;
|
||||
opnear(insn.Op1, code_address(insn, delta));
|
||||
}
|
||||
break;
|
||||
|
||||
case 14:
|
||||
// 1110 1111 dddd 1111 ser rd (16<=d<=31)
|
||||
// 1110 kkkk dddd kkkk ldi rd, k
|
||||
{
|
||||
insn.itype = AVR_ldi;
|
||||
opreg(insn.Op1, ((code >> 4) & 15) + 16);
|
||||
int x = ((code >> 4) & 0xF0) | (code & 0x0F);
|
||||
if ( x == 0xFF && !exists_fixup(insn.ea) )
|
||||
{
|
||||
insn.itype = AVR_ser;
|
||||
break;
|
||||
}
|
||||
opimm(insn, insn.Op2, x);
|
||||
}
|
||||
break;
|
||||
|
||||
case 15:
|
||||
switch ( (code >> 9) & 7 )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// 1111 00kk kkkk k000 brcs/brlo k
|
||||
// 1111 00kk kkkk k001 breq k
|
||||
// 1111 00kk kkkk k010 brmi k
|
||||
// 1111 00kk kkkk k011 brvs k
|
||||
// 1111 00kk kkkk k100 brlt k
|
||||
// 1111 00kk kkkk k101 brhs k
|
||||
// 1111 00kk kkkk k110 brts k
|
||||
// 1111 00kk kkkk k111 brie k
|
||||
// 1111 00kk kkkk ksss brbs s, k
|
||||
// 1111 01kk kkkk k000 brcc/brsh k
|
||||
// 1111 01kk kkkk k001 brne k
|
||||
// 1111 01kk kkkk k010 brpl k
|
||||
// 1111 01kk kkkk k011 brvc k
|
||||
// 1111 01kk kkkk k100 brge k
|
||||
// 1111 01kk kkkk k101 brhc k
|
||||
// 1111 01kk kkkk k110 brtc k
|
||||
// 1111 01kk kkkk k111 brid k
|
||||
// 1111 01kk kkkk ksss brbc s, k
|
||||
{
|
||||
static const uchar itypes[] =
|
||||
{
|
||||
AVR_brcs, AVR_breq, AVR_brmi, AVR_brvs,
|
||||
AVR_brlt, AVR_brhs, AVR_brts, AVR_brie,
|
||||
AVR_brcc, AVR_brne, AVR_brpl, AVR_brvc,
|
||||
AVR_brge, AVR_brhc, AVR_brtc, AVR_brid,
|
||||
};
|
||||
insn.itype = itypes[((code >> 7) & 8) | (code & 7)];
|
||||
signed int delta = (code >> 3) & 0x7F;
|
||||
if ( delta & 0x40 )
|
||||
delta |= ~0x7F;
|
||||
opnear(insn.Op1, code_address(insn, delta));
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// 1111 100d dddd 0bbb bld rd, b
|
||||
if ( code & 8 )
|
||||
return 0;
|
||||
insn.itype = AVR_bld;
|
||||
goto REGBIT;
|
||||
case 5:
|
||||
// 1111 101d dddd Xbbb bst rd, b
|
||||
insn.itype = AVR_bst;
|
||||
goto REGBIT;
|
||||
case 6:
|
||||
// 1111 110r rrrr xbbb sbrc rr, b
|
||||
insn.itype = AVR_sbrc;
|
||||
goto REGBIT;
|
||||
case 7:
|
||||
insn.itype = AVR_sbrs;
|
||||
// 1111 111r rrrr xbbb sbrs rr, b
|
||||
REGBIT:
|
||||
opregd(insn.Op1, code);
|
||||
opimm(insn, insn.Op2, code & 7);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( insn.itype == AVR_null )
|
||||
return 0;
|
||||
return insn.size;
|
||||
}
|
||||
17813
idasdk76/module/avr/avr.cfg
Normal file
17813
idasdk76/module/avr/avr.cfg
Normal file
File diff suppressed because it is too large
Load Diff
136
idasdk76/module/avr/avr.hpp
Normal file
136
idasdk76/module/avr/avr.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AVR_HPP
|
||||
#define _AVR_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <fixup.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
#include "../../ldr/elf/elfr_avr.h"
|
||||
extern int data_id;
|
||||
|
||||
#define PROCMOD_NAME avr
|
||||
#define PROCMOD_NODE_NAME AVR_INFO_NODENAME
|
||||
|
||||
//---------------------------------
|
||||
// Operand types:
|
||||
|
||||
enum phrase_t ENUM_SIZE(uint16)
|
||||
{
|
||||
PH_X, // X
|
||||
PH_XPLUS, // X+
|
||||
PH_MINUSX, // -X
|
||||
PH_Y, // Y
|
||||
PH_YPLUS, // Y+
|
||||
PH_MINUSY, // -Y
|
||||
PH_Z, // Z
|
||||
PH_ZPLUS, // Z+
|
||||
PH_MINUSZ, // -Z
|
||||
};
|
||||
|
||||
|
||||
#define reg_pair specflag1 // o_reg: operand is 16bit a register pair (even register is in op.reg)
|
||||
#define o_port o_idpspec0 // port number in x.addr
|
||||
|
||||
//------------------------------------------------------------------
|
||||
enum RegNo
|
||||
{
|
||||
R0, R1, R2, R3, R4, R5, R6, R7,
|
||||
R8, R9, R10, R11, R12, R13, R14, R15,
|
||||
R16, R17, R18, R19, R20, R21, R22, R23,
|
||||
R24, R25, R26, R27, R28, R29, R30, R31,
|
||||
rVcs, rVds, // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void idaapi avr_segend(outctx_t &ctx, segment_t *seg);
|
||||
void idaapi avr_assumes(outctx_t &ctx); // function to produce assume directives
|
||||
|
||||
int idaapi is_align_insn(ea_t ea);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct avr_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct avr_t ±
|
||||
avr_iohandler_t(avr_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line) override;
|
||||
virtual bool entry_processing(ea_t &, const char * /*word*/, const char * /*cmt*/) override;
|
||||
virtual bool check_ioresp() const override;
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(idb_listener_t, struct avr_t);
|
||||
|
||||
struct avr_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
avr_iohandler_t ioh = avr_iohandler_t(*this, helper);
|
||||
idb_listener_t idb_listener = idb_listener_t(*this);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// not tested
|
||||
fixup_handler_t cfh_avr16 =
|
||||
{
|
||||
sizeof(fixup_handler_t),
|
||||
"AVR16", // Format name, must be unique
|
||||
0, // props
|
||||
2, 16, 0, 0, // size, width, shift
|
||||
REFINFO_CUSTOM, // reftype
|
||||
nullptr, // apply, will be inited in processor_t::ev_init
|
||||
NULL, // get_value
|
||||
NULL, // patch_value
|
||||
};
|
||||
fixup_type_t cfh_avr16_id = 0;
|
||||
int ref_avr16_id = 0;
|
||||
|
||||
int subarch = 0;
|
||||
|
||||
// memory configuration
|
||||
ea_t ram = BADADDR;
|
||||
uint32 ramsize = 0;
|
||||
uint32 romsize = 0;
|
||||
uint32 eepromsize = 0;
|
||||
|
||||
bool imageFile = false;
|
||||
bool nonBinary = false;
|
||||
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
const ioport_t *find_port(ea_t address);
|
||||
const char *find_bit(ea_t address, size_t bit);
|
||||
void setup_avr_device(int resp_info);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void *value,
|
||||
bool idb_loaded);
|
||||
bool set_param_by_arch(void);
|
||||
bool is_possible_subarch(int addr) const;
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool isAlt, bool isload);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void avr_header(outctx_t &ctx);
|
||||
|
||||
inline void opimm(const insn_t &insn, op_t &x, int value) const;
|
||||
inline uint32 code_address(const insn_t &insn, signed int delta) const;
|
||||
int ana(insn_t *_insn);
|
||||
|
||||
void avr_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void avr_footer(outctx_t &ctx) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
#endif // _AVR_HPP
|
||||
170
idasdk76/module/avr/emu.cpp
Normal file
170
idasdk76/module/avr/emu.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include "../../ldr/elf/elfr_avr.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static void set_immd_bit(const insn_t &insn, int n)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
if ( is_defarg(get_flags(insn.ea), n) )
|
||||
return;
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case AVR_andi:
|
||||
case AVR_ori:
|
||||
op_num(insn.ea, n);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void avr_t::handle_operand(const insn_t &insn, const op_t &x, bool isforced, bool isload)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
case o_phrase:
|
||||
break;
|
||||
case o_imm:
|
||||
if ( !isload )
|
||||
goto WRONG_CALL;
|
||||
set_immd_bit(insn, x.n);
|
||||
if ( op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
insn.add_off_drefs(x, dr_O, OOF_SIGNED);
|
||||
break;
|
||||
case o_displ:
|
||||
set_immd_bit(insn, x.n);
|
||||
if ( !isforced && op_adds_xrefs(get_flags(insn.ea), x.n) )
|
||||
{
|
||||
int outf = OOF_ADDR|OOFS_NEEDSIGN|OOFW_32;
|
||||
ea_t ea = insn.add_off_drefs(x, isload ? dr_R : dr_W, outf);
|
||||
if ( ea != BADADDR )
|
||||
insn.create_op_data(ea, x);
|
||||
}
|
||||
break;
|
||||
case o_near:
|
||||
{
|
||||
cref_t ftype = fl_JN;
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
if ( has_insn_feature(insn.itype, CF_CALL) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, x.offb, ftype);
|
||||
}
|
||||
break;
|
||||
case o_port:
|
||||
if ( ram != BADADDR )
|
||||
{
|
||||
ea_t ea = ram + x.addr;
|
||||
if ( subarch < E_AVR_MACH_TINY )
|
||||
ea += 0x20; // skip 32 mapped GPRs for legacy archs
|
||||
if ( x.type == o_port )
|
||||
{ // verify that the calculated address corresponds to the register name
|
||||
const ioport_t *port = find_port(x.addr);
|
||||
if ( port == NULL || port->name.empty() )
|
||||
break;
|
||||
ea_t rev = get_name_ea(BADADDR, port->name.c_str());
|
||||
if ( rev != ea )
|
||||
break;
|
||||
}
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
}
|
||||
break;
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = map_data_ea(insn, x);
|
||||
insn.add_dref(ea, x.offb, isload ? dr_R : dr_W);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WRONG_CALL:
|
||||
if ( insn.itype != AVR_lpm && insn.itype != AVR_elpm )
|
||||
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool may_be_skipped(const insn_t &insn)
|
||||
{
|
||||
ea_t ea = insn.ea - 1;
|
||||
if ( is_code(get_flags(ea)) )
|
||||
{
|
||||
int code = get_wide_byte(ea);
|
||||
switch ( code & 0xFC00 )
|
||||
{
|
||||
// 0001 00rd dddd rrrr cpse rd, rr 4 Compare, Skip if Equal
|
||||
case 0x1000:
|
||||
// 1111 110r rrrr xbbb sbrc rr, b Skip if Bit in I/O Register Cleared
|
||||
// 1111 111r rrrr xbbb sbrs rr, b Skip if Bit in I/O Register Set
|
||||
case 0xFC00:
|
||||
return true;
|
||||
// 1001 1001 pppp pbbb sbic p, b Skip if Bit in Register Cleared
|
||||
// 1001 1011 pppp pbbb sbis p, b Skip if Bit in Register Set
|
||||
case 0x9800:
|
||||
return (code & 0x0100) != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int avr_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
bool flag1 = is_forced_operand(insn.ea, 0);
|
||||
bool flag2 = is_forced_operand(insn.ea, 1);
|
||||
bool flag3 = is_forced_operand(insn.ea, 2);
|
||||
|
||||
flow = (Feature & CF_STOP) == 0;
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, flag1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, flag2, true);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, flag3, true);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, flag1, false);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, flag2, false);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, flag3, false);
|
||||
|
||||
//
|
||||
// Determine if the next instruction should be executed
|
||||
//
|
||||
if ( !flow )
|
||||
flow = may_be_skipped(insn);
|
||||
if ( segtype(insn.ea) == SEG_XTRN )
|
||||
flow = false;
|
||||
if ( flow )
|
||||
add_cref(insn.ea,insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, ea);
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case AVR_mov:
|
||||
if ( insn.Op1.reg == insn.Op2.reg )
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case AVR_nop:
|
||||
break;
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
150
idasdk76/module/avr/ins.cpp
Normal file
150
idasdk76/module/avr/ins.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
|
||||
// ARITHMETIC AND LOGIC INSTRUCTIONS
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // Add without Carry
|
||||
{ "adc", CF_USE1|CF_USE2|CF_CHG1 }, // Add with Carry
|
||||
{ "adiw", CF_USE1|CF_USE2|CF_CHG1 }, // Add Immediate to Word
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract without Carry
|
||||
{ "subi", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Immediate
|
||||
{ "sbc", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract with Carry
|
||||
{ "sbci", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Immediate with Carry
|
||||
{ "sbiw", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Immediate from Word
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND
|
||||
{ "andi", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND with Immediate
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR
|
||||
{ "ori", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR with Immediate
|
||||
{ "eor", CF_USE1|CF_USE2|CF_CHG1 }, // Exclusive OR
|
||||
{ "com", CF_USE1| CF_CHG1 }, // One's Complement
|
||||
{ "neg", CF_USE1| CF_CHG1 }, // Two's Complement
|
||||
{ "sbr", CF_USE1|CF_USE2|CF_CHG1 }, // Set Bit(s) in Register
|
||||
{ "cbr", CF_USE1|CF_USE2|CF_CHG1 }, // Clear Bit(s) in Register
|
||||
{ "inc", CF_USE1| CF_CHG1 }, // Increment
|
||||
{ "dec", CF_USE1| CF_CHG1 }, // Decrement
|
||||
{ "tst", CF_USE1| CF_CHG1 }, // Test for Zero or Minus
|
||||
{ "clr", CF_CHG1 }, // Clear Register
|
||||
{ "ser", CF_CHG1 }, // Set Register
|
||||
{ "cp", CF_USE1|CF_USE2 }, // Compare
|
||||
{ "cpc", CF_USE1|CF_USE2 }, // Compare with Carry
|
||||
{ "cpi", CF_USE1|CF_USE2 }, // Compare with Immediate
|
||||
{ "mul", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply
|
||||
|
||||
// BRANCH INSTRUCTIONS
|
||||
{ "rjmp", CF_USE1|CF_STOP }, // Relative Jump
|
||||
{ "ijmp", CF_STOP|CF_JUMP }, // Indirect Jump to (Z)
|
||||
{ "jmp", CF_USE1|CF_STOP }, // Jump
|
||||
{ "rcall", CF_USE1 |CF_CALL }, // Relative Call Subroutine
|
||||
{ "icall", CF_JUMP|CF_CALL }, // Indirect Call to (Z)
|
||||
{ "call", CF_USE1 |CF_CALL }, // Call Subroutine
|
||||
{ "ret", CF_STOP }, // Subroutine Return
|
||||
{ "reti", CF_STOP }, // Interrupt Return
|
||||
{ "cpse", CF_USE1|CF_USE2 }, // Compare", Skip if Equal
|
||||
{ "sbrc", CF_USE1|CF_USE2 }, // Skip if Bit in Register Cleared
|
||||
{ "sbrs", CF_USE1|CF_USE2 }, // Skip if Bit in Register Set
|
||||
{ "sbic", CF_USE1|CF_USE2 }, // Skip if Bit in I/O Register Cleared
|
||||
{ "sbis", CF_USE1|CF_USE2 }, // Skip if Bit in I/O Register Set
|
||||
{ "brbs", CF_USE1|CF_USE2 }, // Branch if Status Flag Set
|
||||
{ "brbc", CF_USE1|CF_USE2 }, // Branch if Status Flag Cleared
|
||||
{ "breq", CF_USE1 }, // Branch if Equal
|
||||
{ "brne", CF_USE1 }, // Branch if Not Equal
|
||||
{ "brcs", CF_USE1 }, // Branch if Carry Set
|
||||
{ "brcc", CF_USE1 }, // Branch if Carry Cleared
|
||||
{ "brsh", CF_USE1 }, // Branch if Same or Higher
|
||||
{ "brlo", CF_USE1 }, // Branch if Lower
|
||||
{ "brmi", CF_USE1 }, // Branch if Minus
|
||||
{ "brpl", CF_USE1 }, // Branch if Plus
|
||||
{ "brge", CF_USE1 }, // Branch if Greater or Equal
|
||||
{ "brlt", CF_USE1 }, // Branch if Less Than
|
||||
{ "brhs", CF_USE1 }, // Branch if Half Carry Flag Set
|
||||
{ "brhc", CF_USE1 }, // Branch if Half Carry Flag Cleared
|
||||
{ "brts", CF_USE1 }, // Branch if T Flag Set
|
||||
{ "brtc", CF_USE1 }, // Branch if T Flag Cleared
|
||||
{ "brvs", CF_USE1 }, // Branch if Overflow Flag is Set
|
||||
{ "brvc", CF_USE1 }, // Branch if Overflow Flag is Cleared
|
||||
{ "brie", CF_USE1 }, // Branch if Interrupt Enabled
|
||||
{ "brid", CF_USE1 }, // Branch if Interrupt Disabled
|
||||
|
||||
// DATA TRANSFER INSTRUCTIONS
|
||||
{ "mov", CF_CHG1|CF_USE2 }, // Copy Register
|
||||
{ "ldi", CF_CHG1|CF_USE2 }, // Load Immediate
|
||||
{ "lds", CF_CHG1|CF_USE2 }, // Load Direct
|
||||
{ "ld", CF_CHG1|CF_USE2 }, // Load Indirect
|
||||
{ "ldd", CF_CHG1|CF_USE2 }, // Load Indirect with Displacement
|
||||
{ "sts", CF_CHG1|CF_USE2 }, // Store Direct to SRAM
|
||||
{ "st", CF_USE1|CF_USE2 }, // Store Indirect
|
||||
{ "std", CF_USE1|CF_USE2 }, // Store Indirect with Displacement
|
||||
{ "lpm", CF_USE1|CF_USE2|CF_CHG1 }, // Load Program Memory
|
||||
{ "in", CF_CHG1|CF_USE2 }, // In Port
|
||||
{ "out", CF_USE1|CF_USE2 }, // Out Port
|
||||
{ "push", CF_USE1 }, // Push Register on Stack
|
||||
{ "pop", CF_CHG1 }, // Pop Register from Stack
|
||||
|
||||
// BIT AND BIT-TEST INSTRUCTIONS
|
||||
{ "lsl", CF_USE1|CF_CHG1 }, // Logical Shift Left
|
||||
{ "lsr", CF_USE1|CF_CHG1 }, // Logical Shift Right
|
||||
{ "rol", CF_USE1|CF_CHG1 }, // Rotate Left Through Carry
|
||||
{ "ror", CF_USE1|CF_CHG1 }, // Rotate Right Through Carry
|
||||
{ "asr", CF_USE1|CF_CHG1 }, // Arithmetic Shift Right
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // Swap Nibbles
|
||||
{ "bset", CF_USE1 }, // Flag Set
|
||||
{ "bclr", CF_USE1 }, // Flag Clear
|
||||
{ "sbi", CF_USE1|CF_USE2 }, // Set Bit in I/O Register
|
||||
{ "cbi", CF_USE1|CF_USE2 }, // Clear Bit in I/O Register
|
||||
{ "bst", CF_USE1|CF_USE2 }, // Bit Store from Register to T
|
||||
{ "bld", CF_USE1|CF_USE2 }, // Bit load from T to Register
|
||||
{ "sec", 0 }, // Set Carry
|
||||
{ "clc", 0 }, // Clear Carry
|
||||
{ "sen", 0 }, // Set Negative Flag
|
||||
{ "cln", 0 }, // Clear Negative Flag
|
||||
{ "sez", 0 }, // Set Zero Flag
|
||||
{ "clz", 0 }, // Clear Zero Flag
|
||||
{ "sei", 0 }, // Global Interrupt Enable
|
||||
{ "cli", 0 }, // Global Interrupt Disable
|
||||
{ "ses", 0 }, // Set Signed Test Flag
|
||||
{ "cls", 0 }, // Clear Signed Test Flag
|
||||
{ "sev", 0 }, // Set Two's Complement Overflow
|
||||
{ "clv", 0 }, // Clear Two's Complement Overflow
|
||||
{ "set", 0 }, // Set T in SREG
|
||||
{ "clt", 0 }, // Clear T in SREG
|
||||
{ "seh", 0 }, // Set Half Carry Flag in SREG
|
||||
{ "clh", 0 }, // Clear Half Carry Flag in SREG
|
||||
{ "nop", 0 }, // No Operation
|
||||
{ "sleep", 0 }, // Sleep
|
||||
{ "wdr", 0 }, // Watchdog Reset
|
||||
|
||||
// New MegaAVR instructions
|
||||
{ "elpm", CF_USE2|CF_CHG1 }, // Extended Load Program Memory
|
||||
{ "espm", 0 }, // Extended Store Program Memory
|
||||
{ "fmul", CF_USE1|CF_USE2|CF_CHG1 }, // Fractional Multiply Unsigned
|
||||
{ "fmuls", CF_USE1|CF_USE2|CF_CHG1 }, // Fractional Multiply Signed
|
||||
{ "fmulsu", CF_USE1|CF_USE2|CF_CHG1 }, // Fractional Multiply Signed with Unsigned
|
||||
{ "movw", CF_USE1|CF_USE2|CF_CHG1 }, // Copy Register Word
|
||||
{ "muls", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply Signed
|
||||
{ "mulsu", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply Signed with Unsigned
|
||||
{ "spm", 0 }, // Store Program Memory
|
||||
{ "eicall", 0 }, // Extended Indirect Call to Subroutine
|
||||
{ "eijmp", 0 }, // Extended Indirect Jump
|
||||
|
||||
// New XMega instructions
|
||||
{ "des", CF_USE1 }, // Data Encryption Standard
|
||||
{ "lac", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Load And Clear
|
||||
{ "las", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Load And Set
|
||||
{ "lat", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Load And Toggle
|
||||
{ "xch", CF_USE1|CF_USE2|CF_CHG1|CF_CHG2 }, // Exchange
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == AVR_last);
|
||||
157
idasdk76/module/avr/ins.hpp
Normal file
157
idasdk76/module/avr/ins.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
|
||||
AVR_null = 0, // Unknown Operation
|
||||
|
||||
// ARITHMETIC AND LOGIC INSTRUCTIONS
|
||||
AVR_add, // Add without Carry
|
||||
AVR_adc, // Add with Carry
|
||||
AVR_adiw, // Add Immediate to Word
|
||||
AVR_sub, // Subtract without Carry
|
||||
AVR_subi, // Subtract Immediate
|
||||
AVR_sbc, // Subtract with Carry
|
||||
AVR_sbci, // Subtract Immediate with Carry
|
||||
AVR_sbiw, // Subtract Immediate from Word
|
||||
AVR_and, // Logical AND
|
||||
AVR_andi, // Logical AND with Immediate
|
||||
AVR_or, // Logical OR
|
||||
AVR_ori, // Logical OR with Immediate
|
||||
AVR_eor, // Exclusive OR
|
||||
AVR_com, // One's Complement
|
||||
AVR_neg, // Two's Complement
|
||||
AVR_sbr, // Set Bit(s) in Register
|
||||
AVR_cbr, // Clear Bit(s) in Register
|
||||
AVR_inc, // Increment
|
||||
AVR_dec, // Decrement
|
||||
AVR_tst, // Test for Zero or Minus
|
||||
AVR_clr, // Clear Register
|
||||
AVR_ser, // Set Register
|
||||
AVR_cp, // Compare
|
||||
AVR_cpc, // Compare with Carry
|
||||
AVR_cpi, // Compare with Immediate
|
||||
AVR_mul, // Multiply
|
||||
|
||||
// BRANCH INSTRUCTIONS
|
||||
AVR_rjmp, // Relative Jump
|
||||
AVR_ijmp, // Indirect Jump to (Z)
|
||||
AVR_jmp, // Jump
|
||||
AVR_rcall, // Relative Call Subroutine
|
||||
AVR_icall, // Indirect Call to (Z)
|
||||
AVR_call, // Call Subroutine
|
||||
AVR_ret, // Subroutine Return
|
||||
AVR_reti, // Interrupt Return
|
||||
AVR_cpse, // Compare, Skip if Equal
|
||||
AVR_sbrc, // Skip if Bit in Register Cleared
|
||||
AVR_sbrs, // Skip if Bit in Register Set
|
||||
AVR_sbic, // Skip if Bit in I/O Register Cleared
|
||||
AVR_sbis, // Skip if Bit in I/O Register Set
|
||||
AVR_brbs, // Branch if Status Flag Set
|
||||
AVR_brbc, // Branch if Status Flag Cleared
|
||||
AVR_breq, // Branch if Equal
|
||||
AVR_brne, // Branch if Not Equal
|
||||
AVR_brcs, // Branch if Carry Set
|
||||
AVR_brcc, // Branch if Carry Cleared
|
||||
AVR_brsh, // Branch if Same or Higher
|
||||
AVR_brlo, // Branch if Lower
|
||||
AVR_brmi, // Branch if Minus
|
||||
AVR_brpl, // Branch if Plus
|
||||
AVR_brge, // Branch if Greater or Equal
|
||||
AVR_brlt, // Branch if Less Than
|
||||
AVR_brhs, // Branch if Half Carry Flag Set
|
||||
AVR_brhc, // Branch if Half Carry Flag Cleared
|
||||
AVR_brts, // Branch if T Flag Set
|
||||
AVR_brtc, // Branch if T Flag Cleared
|
||||
AVR_brvs, // Branch if Overflow Flag is Set
|
||||
AVR_brvc, // Branch if Overflow Flag is Cleared
|
||||
AVR_brie, // Branch if Interrupt Enabled
|
||||
AVR_brid, // Branch if Interrupt Disabled
|
||||
|
||||
// DATA TRANSFER INSTRUCTIONS
|
||||
AVR_mov, // Copy Register
|
||||
AVR_ldi, // Load Immediate
|
||||
AVR_lds, // Load Direct
|
||||
AVR_ld, // Load Indirect
|
||||
AVR_ldd, // Load Indirect with Displacement
|
||||
AVR_sts, // Store Direct to SRAM
|
||||
AVR_st, // Store Indirect
|
||||
AVR_std, // Store Indirect with Displacement
|
||||
AVR_lpm, // Load Program Memory
|
||||
AVR_in, // In Port
|
||||
AVR_out, // Out Port
|
||||
AVR_push, // Push Register on Stack
|
||||
AVR_pop, // Pop Register from Stack
|
||||
|
||||
// BIT AND BIT-TEST INSTRUCTIONS
|
||||
AVR_lsl, // Logical Shift Left
|
||||
AVR_lsr, // Logical Shift Right
|
||||
AVR_rol, // Rotate Left Through Carry
|
||||
AVR_ror, // Rotate Right Through Carry
|
||||
AVR_asr, // Arithmetic Shift Right
|
||||
AVR_swap, // Swap Nibbles
|
||||
AVR_bset, // Flag Set
|
||||
AVR_bclr, // Flag Clear
|
||||
AVR_sbi, // Set Bit in I/O Register
|
||||
AVR_cbi, // Clear Bit in I/O Register
|
||||
AVR_bst, // Bit Store from Register to T
|
||||
AVR_bld, // Bit load from T to Register
|
||||
AVR_sec, // Set Carry
|
||||
AVR_clc, // Clear Carry
|
||||
AVR_sen, // Set Negative Flag
|
||||
AVR_cln, // Clear Negative Flag
|
||||
AVR_sez, // Set Zero Flag
|
||||
AVR_clz, // Clear Zero Flag
|
||||
AVR_sei, // Global Interrupt Enable
|
||||
AVR_cli, // Global Interrupt Disable
|
||||
AVR_ses, // Set Signed Test Flag
|
||||
AVR_cls, // Clear Signed Test Flag
|
||||
AVR_sev, // Set Two's Complement Overflow
|
||||
AVR_clv, // Clear Two's Complement Overflow
|
||||
AVR_set, // Set T in SREG
|
||||
AVR_clt, // Clear T in SREG
|
||||
AVR_seh, // Set Half Carry Flag in SREG
|
||||
AVR_clh, // Clear Half Carry Flag in SREG
|
||||
AVR_nop, // No Operation
|
||||
AVR_sleep, // Sleep
|
||||
AVR_wdr, // Watchdog Reset
|
||||
|
||||
// New MegaAVR instructions
|
||||
|
||||
AVR_elpm, // Extended Load Program Memory
|
||||
AVR_espm, // Extended Store Program Memory
|
||||
AVR_fmul, // Fractional Multiply Unsigned
|
||||
AVR_fmuls, // Fractional Multiply Signed
|
||||
AVR_fmulsu, // Fractional Multiply Signed with Unsigned
|
||||
AVR_movw, // Copy Register Word
|
||||
AVR_muls, // Multiply Signed
|
||||
AVR_mulsu, // Multiply Signed with Unsigned
|
||||
AVR_spm, // Store Program Memory
|
||||
AVR_eicall, // Extended Indirect Call to Subroutine
|
||||
AVR_eijmp, // Extended Indirect Jump
|
||||
|
||||
// New XMega instructions
|
||||
|
||||
AVR_des, // Data Encryption Standard
|
||||
AVR_lac, // Load And Clear
|
||||
AVR_las, // Load And Set
|
||||
AVR_lat, // Load And Toggle
|
||||
AVR_xch, // Exchange
|
||||
|
||||
AVR_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
63
idasdk76/module/avr/makefile
Normal file
63
idasdk76/module/avr/makefile
Normal file
@@ -0,0 +1,63 @@
|
||||
PROC=avr
|
||||
CONFIGS=avr.cfg
|
||||
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
ana.cpp avr.hpp ins.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
avr.hpp emu.cpp ins.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
avr.hpp ins.cpp ins.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp \
|
||||
avr.hpp ins.hpp out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/elf/elfbase.h \
|
||||
../idaidp.hpp ../iohandler.hpp avr.hpp ins.hpp \
|
||||
notify_codes.hpp reg.cpp
|
||||
34
idasdk76/module/avr/notify_codes.hpp
Normal file
34
idasdk76/module/avr/notify_codes.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2021 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AVR_NOTIFY_CODES_HPP
|
||||
#define __AVR_NOTIFY_CODES_HPP
|
||||
|
||||
#include <idp.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// The following events are supported by the AVR module in the ph.notify() function
|
||||
namespace avr_module_t
|
||||
{
|
||||
enum event_codes_t
|
||||
{
|
||||
ev_set_machine_type = processor_t::ev_loader,
|
||||
// elf-loader 'set machine type' and file type
|
||||
};
|
||||
|
||||
inline processor_t::event_t idp_ev(event_codes_t ev)
|
||||
{
|
||||
return processor_t::event_t(ev);
|
||||
}
|
||||
|
||||
inline void set_machine_type(int subarch, bool image_file)
|
||||
{
|
||||
processor_t::notify(idp_ev(ev_set_machine_type), subarch, image_file);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __AVR_NOTIFY_CODES_HPP
|
||||
257
idasdk76/module/avr/out.cpp
Normal file
257
idasdk76/module/avr/out.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include "../../ldr/elf/elfr_avr.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_avr_t : public outctx_t
|
||||
{
|
||||
void out_regop(const op_t &x);
|
||||
out_avr_t(void) = delete; // not used
|
||||
public:
|
||||
void out_phrase(int phn);
|
||||
void out_bad_address(ea_t addr);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_avr_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_avr_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_avr_t::out_phrase(int phn)
|
||||
{
|
||||
switch ( phn )
|
||||
{
|
||||
case PH_XPLUS: // X+
|
||||
out_register("X");
|
||||
out_symbol('+');
|
||||
break;
|
||||
case PH_MINUSX: // -X
|
||||
out_symbol('-');
|
||||
case PH_X: // X
|
||||
out_register("X");
|
||||
break;
|
||||
case PH_YPLUS: // Y+
|
||||
out_register("Y");
|
||||
out_symbol('+');
|
||||
break;
|
||||
case PH_MINUSY: // -Y
|
||||
out_symbol('-');
|
||||
case PH_Y: // Y
|
||||
out_register("Y");
|
||||
break;
|
||||
case PH_ZPLUS: // Z+
|
||||
out_register("Z");
|
||||
out_symbol('+');
|
||||
break;
|
||||
case PH_MINUSZ: // -Z
|
||||
out_symbol('-');
|
||||
case PH_Z: // Z
|
||||
out_register("Z");
|
||||
break;
|
||||
default:
|
||||
error("%a: bad phrase number", insn.ea);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_avr_t::out_bad_address(ea_t addr)
|
||||
{
|
||||
out_tagon(COLOR_ERROR);
|
||||
out_btoa(addr, 16);
|
||||
out_tagoff(COLOR_ERROR);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
}
|
||||
|
||||
void out_avr_t::out_regop(const op_t &x)
|
||||
{
|
||||
avr_t &pm = *static_cast<avr_t *>(procmod);
|
||||
qstring name;
|
||||
// for legacy architectures, try to get SRAM name if available
|
||||
if ( x.reg_pair
|
||||
|| pm.ram == BADADDR || pm.subarch >= E_AVR_MACH_TINY
|
||||
|| get_visible_name(&name, pm.ram+x.reg) <= 0 )
|
||||
{
|
||||
// no name or reg pair: use standard reg name
|
||||
name = ph.reg_names[x.reg];
|
||||
if ( x.reg_pair )
|
||||
{
|
||||
switch ( x.reg )
|
||||
{
|
||||
case R26: name = "X"; break;
|
||||
case R28: name = "Y"; break;
|
||||
case R30: name = "Z"; break;
|
||||
default:
|
||||
// r1:r2
|
||||
out_register(name.begin());
|
||||
out_symbol(':');
|
||||
name = ph.reg_names[x.reg+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out_register(name.begin());
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
bool out_avr_t::out_operand(const op_t &x)
|
||||
{
|
||||
avr_t &pm = *static_cast<avr_t *>(procmod);
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_void:
|
||||
return 0;
|
||||
|
||||
case o_reg:
|
||||
out_regop(x);
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
{
|
||||
if ( insn.itype == AVR_cbi
|
||||
|| insn.itype == AVR_sbic
|
||||
|| insn.itype == AVR_sbi
|
||||
|| insn.itype == AVR_sbis )
|
||||
{
|
||||
const char *bit = pm.find_bit(insn.Op1.addr, (size_t)x.value);
|
||||
if ( bit != NULL && bit[0] != '\0' )
|
||||
{
|
||||
out_line(bit, COLOR_REG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( x.specflag1 && is_off1(F) && !is_invsign(insn.ea, F, 1) )
|
||||
out_symbol('-');
|
||||
int flags = OOFS_IFSIGN|OOFW_8;
|
||||
if ( insn.itype == AVR_subi || insn.itype == AVR_sbci )
|
||||
flags |= OOF_SIGNED;
|
||||
out_value(x, flags);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near:
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, x.addr);
|
||||
if ( !out_name_expr(x, ea, x.addr) )
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
ea_t ea = map_data_ea(insn, x);
|
||||
if ( !out_name_expr(x, ea, x.addr) )
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
out_phrase(x.phrase);
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
out_phrase(x.phrase);
|
||||
out_value(x, OOF_ADDR|OOFS_NEEDSIGN|OOFW_32);
|
||||
break;
|
||||
|
||||
case o_port:
|
||||
{
|
||||
const ioport_t *port = pm.find_port(x.addr);
|
||||
if ( port != NULL && !port->name.empty() )
|
||||
out_register(port->name.c_str());
|
||||
else
|
||||
out_bad_address(x.addr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d", insn.ea, x.type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_avr_t::out_insn(void)
|
||||
{
|
||||
avr_t &pm = *static_cast<avr_t *>(procmod);
|
||||
// output .org for enties without any labels
|
||||
if ( !has_any_name(F) && pm.helper.altval_ea(insn.ea) )
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
btoa(buf, sizeof(buf), insn.ip);
|
||||
int saved_flags = forbid_annotations();
|
||||
gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
restore_ctxflags(saved_flags);
|
||||
}
|
||||
|
||||
out_mnemonic();
|
||||
|
||||
out_one_operand(0);
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1);
|
||||
}
|
||||
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void avr_t::avr_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
if ( is_spec_segm(Sarea->type) )
|
||||
return;
|
||||
qstring sname;
|
||||
qstring sclas;
|
||||
get_visible_segm_name(&sname, Sarea);
|
||||
get_segm_class(&sclas, Sarea);
|
||||
ctx.gen_printf(0,
|
||||
COLSTR("%s", SCOLOR_ASMDIR) " " COLSTR("%s %s", SCOLOR_AUTOCMT),
|
||||
sclas == "CODE"
|
||||
? ".CSEG"
|
||||
: sclas == "DATA"
|
||||
? ".DSEG"
|
||||
: ".ESEG",
|
||||
ash.cmnt,
|
||||
sname.c_str());
|
||||
if ( Sarea->orgbase != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), Sarea->orgbase);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi avr_segend(outctx_t &, segment_t *)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void avr_t::avr_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void avr_t::avr_footer(outctx_t &ctx) const
|
||||
{
|
||||
qstring name = get_visible_name(inf_get_start_ea());
|
||||
ctx.gen_printf(DEFAULT_INDENT,
|
||||
COLSTR("%s",SCOLOR_ASMDIR) " " COLSTR("%s %s",SCOLOR_AUTOCMT),
|
||||
ash.end, ash.cmnt, name.c_str());
|
||||
}
|
||||
803
idasdk76/module/avr/reg.cpp
Normal file
803
idasdk76/module/avr/reg.cpp
Normal file
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-99 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@datarescue.com
|
||||
*
|
||||
* Atmel AVR - 8-bit RISC processor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "avr.hpp"
|
||||
#include <segregs.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <fixup.hpp>
|
||||
#include "notify_codes.hpp"
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const register_names[] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "XL", "XH", "YL", "YH", "ZL", "ZH",
|
||||
"cs","ds", // virtual registers for code and data segments
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// AVR assembler
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const avr_header[] =
|
||||
{
|
||||
".equ XL, 26",
|
||||
".equ XH, 27",
|
||||
".equ YL, 28",
|
||||
".equ YH, 29",
|
||||
".equ ZL, 30",
|
||||
".equ ZH, 31",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t avrasm =
|
||||
{
|
||||
AS_COLON|AS_N2CHR|ASH_HEXF3|ASD_DECF0|ASB_BINF3|ASO_OCTF0|AS_ONEDUP,
|
||||
0,
|
||||
"AVR Assembler",
|
||||
0,
|
||||
avr_header, // header lines
|
||||
".org", // org
|
||||
".exit", // end
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\"'", // special symbols in char and string constants
|
||||
|
||||
".db", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
".dd", // double words
|
||||
NULL, // no qwords
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
".byte %s", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // 'seg' prefix (example: push seg seg001)
|
||||
NULL, // current IP (instruction pointer)
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // "public" name keyword
|
||||
NULL, // "weak" name keyword
|
||||
NULL, // "extrn" name keyword
|
||||
NULL, // "comm" (communal variable)
|
||||
NULL, // get_type_name
|
||||
NULL, // "align" keyword
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"~", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] = { &avrasm, NULL };
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char cfgname[] = "avr.cfg";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_iohandler_t::entry_processing(ea_t &ea1, const char * /*word*/, const char * /*cmt*/)
|
||||
{
|
||||
pm.helper.altset_ea(ea1, 1);
|
||||
create_insn(ea1);
|
||||
ea_t ea = get_first_fcref_from(ea1);
|
||||
if ( ea != BADADDR )
|
||||
ea1 = ea;
|
||||
return false; // continue processing
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_iohandler_t::check_ioresp() const
|
||||
{
|
||||
return inf_like_binary() || pm.imageFile;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_t::is_possible_subarch(int addr) const
|
||||
{
|
||||
// old version of gcc-arm don't use 31/51/etc subarches - only 3/5/... :(
|
||||
// maybe make option?
|
||||
return subarch == 0 || subarch == addr || (addr/10 == subarch);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *avr_iohandler_t::iocallback(const ioports_t &_ports, const char *line)
|
||||
{
|
||||
int addr;
|
||||
char word[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
CASSERT(MAXSTR == 1024);
|
||||
if ( qsscanf(line, "%1023[^=] = %d", word, &addr) == 2 )
|
||||
{
|
||||
if ( streq(word, "RAM") )
|
||||
{
|
||||
pm.ramsize = addr;
|
||||
return NULL;
|
||||
}
|
||||
if ( streq(word, "ROM") )
|
||||
{
|
||||
pm.romsize = addr >> 1;
|
||||
return NULL;
|
||||
}
|
||||
if ( streq(word, "EEPROM") )
|
||||
{
|
||||
pm.eepromsize = addr;
|
||||
return NULL;
|
||||
}
|
||||
if ( streq(word, "SUBARCH") )
|
||||
{
|
||||
// set pm.subarch based on SUBARCH in the config file
|
||||
// it is needed to do XMEGA specific things for non-elf files
|
||||
pm.subarch = addr;
|
||||
return pm.is_possible_subarch(addr) ? NULL : IOPORT_SKIP_DEVICE;
|
||||
}
|
||||
}
|
||||
return standard_callback(_ports, line);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct avr_ioport_parser_t : public choose_ioport_parser_t
|
||||
{
|
||||
avr_t ±
|
||||
|
||||
avr_ioport_parser_t(avr_t &_pm) : pm(_pm) {}
|
||||
virtual bool parse(qstring *, const char *line) override
|
||||
{
|
||||
int addr;
|
||||
char word[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
CASSERT(MAXSTR == 1024);
|
||||
bool skip = qsscanf(line, "%1023[^=] = %d", word, &addr) == 2
|
||||
&& strcmp(word, "SUBARCH") == 0
|
||||
&& !pm.is_possible_subarch(addr);
|
||||
return !skip;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const ioport_t *avr_t::find_port(ea_t address)
|
||||
{
|
||||
return find_ioport(ioh.ports, address);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *avr_t::find_bit(ea_t address, size_t bit)
|
||||
{
|
||||
const ioport_bit_t *b = find_ioport_bit(ioh.ports, address, bit);
|
||||
return b ? b->name.c_str() : NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void avr_t::setup_avr_device(int resp_info)
|
||||
{
|
||||
if ( !choose_ioport_device(&ioh.device, cfgname) )
|
||||
return;
|
||||
|
||||
ioh.set_device_name(ioh.device.c_str(), resp_info);
|
||||
if ( get_first_seg() == NULL ) // set processor options before load file
|
||||
return;
|
||||
plan_range(0, BADADDR); // reanalyze program
|
||||
|
||||
// resize the ROM segment
|
||||
{
|
||||
segment_t *s = getseg(node2ea(helper.altval(-1)));
|
||||
if ( s == NULL )
|
||||
s = get_first_seg(); // for the old databases
|
||||
if ( s != NULL ) //-V547 's != 0' is always true
|
||||
{
|
||||
if ( s->size() > romsize )
|
||||
warning("The input file is bigger than the ROM size of the current device");
|
||||
set_segm_end(s->start_ea, s->start_ea+romsize, SEGMOD_KILL);
|
||||
}
|
||||
}
|
||||
// resize the RAM segment
|
||||
{
|
||||
segment_t *s = get_segm_by_name("RAM");
|
||||
if ( s == NULL && ramsize != 0 )
|
||||
{
|
||||
ea_t start = (inf_get_max_ea() + 0xFFFFF) & ~0xFFFFF;
|
||||
add_segm(start>>4, start, start+ramsize, "RAM", "DATA");
|
||||
s = getseg(start);
|
||||
}
|
||||
ram = BADADDR;
|
||||
if ( s != NULL )
|
||||
{
|
||||
int i;
|
||||
// offset added to I/O port address to get RAM address
|
||||
int ram_offset = 0;
|
||||
ram = s->start_ea;
|
||||
set_segm_end(ram, ram+ramsize, SEGMOD_KILL);
|
||||
|
||||
if ( subarch < E_AVR_MACH_TINY )
|
||||
{
|
||||
// legacy devices start with 32 GPRs
|
||||
// 0x20 needs to be added to the port address
|
||||
ram_offset = 0x20;
|
||||
// set register names for aliases in data memory
|
||||
for ( i=0; i < 32; i++ )
|
||||
if ( !has_any_name(get_flags(ram+i)) )
|
||||
set_name(ram+i, register_names[i], SN_NODUMMY);
|
||||
}
|
||||
|
||||
// set I/O port names
|
||||
for ( i=0; i < ioh.ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ioh.ports[i];
|
||||
set_name(ram+p.address+ram_offset, p.name.c_str(), SN_NODUMMY);
|
||||
set_cmt(ram+p.address+ram_offset, p.cmt.c_str(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *avr_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int value_type,
|
||||
const void *value,
|
||||
bool idb_loaded)
|
||||
{
|
||||
if ( keyword == NULL )
|
||||
{
|
||||
setup_avr_device(IORESP_INT);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
else if ( strcmp(keyword, "AVR_MCPU") == 0 )
|
||||
{
|
||||
if ( value_type != IDPOPT_STR )
|
||||
return IDPOPT_BADTYPE;
|
||||
|
||||
ioh.device = (const char *) value;
|
||||
if ( idb_loaded )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_NONE);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
return IDPOPT_BADKEY;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool avr_t::set_param_by_arch(void)
|
||||
{
|
||||
int max_rom, max_ram, max_eeprom;
|
||||
// preset MAXIMUM's of memory size's by mcpu subtype
|
||||
switch ( subarch )
|
||||
{
|
||||
default:
|
||||
subarch = 0;
|
||||
return false; // LOGICAL ERROR?
|
||||
|
||||
// at90s1200, attiny10, attiny11, attiny12, attiny15, attiny28
|
||||
case E_AVR_MACH_AVR1: // ROM<=1k
|
||||
max_rom = 1024;
|
||||
max_ram = 32;
|
||||
max_eeprom = 64;
|
||||
break;
|
||||
// at90s2313, at90s2323, at90s2333, at90s2343, attiny22, attiny26,
|
||||
// at90s4414 /* XXX -> 8515 */, at90s4433, at90s4434 /* XXX -> 8535 */,
|
||||
// at90s8515, at90c8534, at90s8535
|
||||
case E_AVR_MACH_AVR2: // ROM<=8k
|
||||
// attiny13, attiny13a, attiny2313, attiny24, attiny44, attiny84,
|
||||
// attiny25, attiny45, attiny85, attiny261, attiny461, attiny861,
|
||||
// attiny43u, attiny48, attiny88, at86rf401
|
||||
// PASS THRU
|
||||
case E_AVR_MACH_AVR25: // ROM<=8k
|
||||
max_rom = 8*1024;
|
||||
max_ram = 512;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// at43usb355, at76c711
|
||||
case E_AVR_MACH_AVR3: // ROM>=8k<=64k
|
||||
max_rom = 64*1024;
|
||||
max_ram = 1024;
|
||||
max_eeprom = 0;
|
||||
break;
|
||||
// atmega103, at43usb320,
|
||||
case E_AVR_MACH_AVR31: // ROM>=65k&&<=128k, (RAM=65k, EEPROM=4k)
|
||||
max_rom = 128*1024;
|
||||
max_ram = 4*1024;
|
||||
max_eeprom = 4*1024;
|
||||
break;
|
||||
// attiny167, at90usb82, at90usb162
|
||||
case E_AVR_MACH_AVR35: // ROM>=8k&&<=64k,
|
||||
max_rom = 64*1024;
|
||||
max_ram = 512;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// atmega8, atmega48, atmega48p, atmega88, atmega88p, atmega8515,
|
||||
// atmega8535, atmega8hva, at90pwm1, at90pwm2, at90pwm2b, at90pwm3,
|
||||
// at90pwm3b
|
||||
case E_AVR_MACH_AVR4: // ROM<=8k
|
||||
max_rom = 8*1024;
|
||||
max_ram = 1024;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// atmega16, atmega161, atmega162, atmega163, atmega164p, atmega165,
|
||||
// atmega165p, atmega168, atmega168p, atmega169, atmega169p, atmega32,
|
||||
// atmega323, atmega324p, atmega325, atmega325p, atmega3250, atmega3250p,
|
||||
// atmega328p, atmega329, atmega329p, atmega3290, atmega3290p, atmega406,
|
||||
// atmega64, atmega640, atmega644, atmega644p, atmega645, atmega649,
|
||||
// atmega6450, atmega6490, atmega16hva, at90can32, at90can64, at90pwm216,
|
||||
// at90pwm316, atmega32c1, atmega32m1, atmega32u4, at90usb646, at90usb647,
|
||||
// at94k
|
||||
case E_AVR_MACH_AVR5: // ROM>=8k&&<=64k
|
||||
max_rom = 64*1024;
|
||||
max_ram = 4*1024;
|
||||
max_eeprom = 2*1024;
|
||||
break;
|
||||
// atmega128, atmega1280, atmega1281, atmega1284p,
|
||||
// at90can128, at90usb1286, at90usb1287
|
||||
case E_AVR_MACH_AVR51: // ROM=128k
|
||||
max_rom = 128*1024;
|
||||
max_ram = 16*1024;
|
||||
max_eeprom = 4*1024;
|
||||
break;
|
||||
// atmega2560, atmega2561
|
||||
case E_AVR_MACH_AVR6: // ROM=256k (3-byte pc -- is supported?)
|
||||
max_rom = 256*1024;
|
||||
max_ram = 8*1024;
|
||||
max_eeprom = 4*1024;
|
||||
break;
|
||||
case E_AVR_MACH_XMEGA1: // ROM < 8K, ram=?
|
||||
max_rom = 8*1024;
|
||||
max_ram = 1024;
|
||||
max_eeprom = 512;
|
||||
break;
|
||||
// ATxmega16A4, ATxmega16D4, ATxmega32D4
|
||||
case E_AVR_MACH_XMEGA2: // 8K < FLASH <= 64K, RAM <= 64K
|
||||
max_rom = 64*1024;
|
||||
max_ram = 64*1024;
|
||||
max_eeprom = 1024;
|
||||
break;
|
||||
// ATxmega32A4
|
||||
case E_AVR_MACH_XMEGA3: // 8K < FLASH <= 64K, RAM > 64K
|
||||
max_rom = 64*1024;
|
||||
max_ram = 128*1024; // ?
|
||||
max_eeprom = 1024;
|
||||
break;
|
||||
// ATxmega64A3, ATxmega64D3
|
||||
case E_AVR_MACH_XMEGA4: // 64K < FLASH <= 128K, RAM <= 64K
|
||||
max_rom = 128*1024;
|
||||
max_ram = 64*1024;
|
||||
max_eeprom = 2048;
|
||||
break;
|
||||
// ATxmega64A1
|
||||
case E_AVR_MACH_XMEGA5: // 64K < FLASH <= 128K, RAM > 64K
|
||||
max_rom = 128*1024;
|
||||
max_ram = 128*1024;
|
||||
max_eeprom = 2048;
|
||||
break;
|
||||
// ATxmega128A3, ATxmega128D3, ATxmega192A3, ATxmega192D3,
|
||||
// ATxmega256A3B, ATxmega256A3, ATxmega256D3
|
||||
case E_AVR_MACH_XMEGA6: // 128K < FLASH <= 256K, RAM <= 64K
|
||||
max_rom = 256*1024;
|
||||
max_ram = 64*1024;
|
||||
max_eeprom = 4096;
|
||||
break;
|
||||
// ATxmega128A1
|
||||
case E_AVR_MACH_XMEGA7: // 128K < FLASH <= 256K, RAM > 64K
|
||||
max_rom = 256*1024;
|
||||
max_ram = 128*1024;
|
||||
max_eeprom = 4096;
|
||||
break;
|
||||
}
|
||||
avr_ioport_parser_t parser(*this);
|
||||
if ( !choose_ioport_device2(&ioh.device, cfgname, &parser) )
|
||||
{
|
||||
ioh.device.sprnt("avr%d", subarch);
|
||||
ioh.device[sizeof("avrX")-1] = '\0';
|
||||
romsize = max_rom >> 1;
|
||||
ramsize = max_ram;
|
||||
eepromsize = max_eeprom;
|
||||
}
|
||||
else
|
||||
{
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_INT);
|
||||
plan_range(0, BADADDR); // reanalyze program
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static inline ea_t get16bit(ea_t ea)
|
||||
{
|
||||
if ( segtype(ea) == SEG_CODE )
|
||||
return get_wide_byte(ea);
|
||||
|
||||
return get_word(ea);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case idb_event::segm_added:
|
||||
{
|
||||
segment_t *s = va_arg(va, segment_t *);
|
||||
qstring sclass;
|
||||
if ( get_segm_class(&sclass, s) > 0 && sclass == "DATA" )
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
case idb_event::segm_moved: // A segment is moved
|
||||
// Fix processor dependent address sensitive information
|
||||
{
|
||||
ea_t from = va_arg(va, ea_t);
|
||||
ea_t to = va_arg(va, ea_t);
|
||||
asize_t size = va_arg(va, asize_t);
|
||||
//bool changed_netmap = va_argi(va, bool);
|
||||
|
||||
nodeidx_t ndx1 = ea2node(from);
|
||||
nodeidx_t ndx2 = ea2node(to);
|
||||
pm.helper.altshift(ndx1, ndx2, size); // move address information
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool idaapi avr16_apply(
|
||||
const fixup_handler_t *fh,
|
||||
ea_t item_ea,
|
||||
ea_t fixup_ea,
|
||||
int opnum,
|
||||
bool /*is_macro*/,
|
||||
const fixup_data_t &fd)
|
||||
{
|
||||
avr_t &pm = *GET_MODULE_DATA(avr_t);
|
||||
if ( !pm.nonBinary
|
||||
|| fd.has_base()
|
||||
|| fd.is_unused()
|
||||
|| fd.displacement != 0 )
|
||||
{
|
||||
msg("%a: Unexpected or incorrect CUSTOM_FIXUP\n", fixup_ea);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_unknown(get_flags(item_ea)) )
|
||||
create_16bit_data(item_ea, 2);
|
||||
|
||||
refinfo_t ri;
|
||||
ri.flags = fh->reftype;
|
||||
ri.base = fd.get_base();
|
||||
ri.target = ri.base + fd.off;
|
||||
ri.tdelta = fd.displacement;
|
||||
op_offset_ex(item_ea, opnum, &ri);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{818} could be declared const
|
||||
static int idaapi avr16_gen_expr(
|
||||
qstring * /*buf*/,
|
||||
qstring * /*format*/,
|
||||
ea_t ea,
|
||||
int numop,
|
||||
const refinfo_t &ri,
|
||||
ea_t /*from*/,
|
||||
adiff_t *opval,
|
||||
ea_t * /*target*/,
|
||||
ea_t * /*fullvalue*/,
|
||||
int /*getn_flags*/)
|
||||
{
|
||||
avr_t &pm = *GET_MODULE_DATA(avr_t);
|
||||
if ( !pm.nonBinary
|
||||
|| numop != 0
|
||||
|| ri.type() == (pm.ref_avr16_id | REFINFO_CUSTOM)
|
||||
|| ri.tdelta != 0
|
||||
|| ri.target == BADADDR
|
||||
|| *opval != get16bit(ea) )
|
||||
{
|
||||
msg("%a: Unexpected or incorrect CUSTOM offset\n", ea);
|
||||
return 0;
|
||||
}
|
||||
return 3; // process as a regular fixup
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const custom_refinfo_handler_t ref_avr16 =
|
||||
{
|
||||
sizeof(custom_refinfo_handler_t),
|
||||
"AVR16",
|
||||
"AVR 16-bit offset",
|
||||
0, // properties (currently 0)
|
||||
avr16_gen_expr, // gen_expr
|
||||
NULL, // calc_reference_data
|
||||
NULL, // get_format
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// This old-style callback only returns the processor module object.
|
||||
static ssize_t idaapi notify(void *, int msgid, va_list)
|
||||
{
|
||||
if ( msgid == processor_t::ev_get_procmod )
|
||||
return size_t(SET_MODULE_DATA(avr_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void avr_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
segment_t *s = get_segm_by_name("RAM");
|
||||
if ( s != NULL )
|
||||
ram = s->start_ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi avr_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
cfh_avr16.apply = avr16_apply;
|
||||
cfh_avr16_id = register_custom_fixup(&cfh_avr16);
|
||||
ref_avr16_id = register_custom_refinfo(&ref_avr16);
|
||||
cfh_avr16.reftype = REFINFO_CUSTOM | ref_avr16_id;
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
cfh_avr16.reftype = REFINFO_CUSTOM;
|
||||
unregister_custom_refinfo(ref_avr16_id);
|
||||
unregister_custom_fixup(cfh_avr16_id);
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case avr_module_t::ev_set_machine_type: // elf-loader 'set machine type' and file type
|
||||
subarch = va_arg(va, int);
|
||||
imageFile = va_argi(va, bool);
|
||||
nonBinary = true;
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile: // new file loaded
|
||||
// remember the ROM segment
|
||||
{
|
||||
segment_t *s = get_first_seg();
|
||||
if ( s != NULL )
|
||||
{
|
||||
if ( subarch == 0 )
|
||||
set_segm_name(s, "ROM");
|
||||
helper.altset(-1, ea2node(s->start_ea));
|
||||
}
|
||||
}
|
||||
if ( subarch != 0 && set_param_by_arch() )
|
||||
break;
|
||||
setup_avr_device(/*IORESP_AREA|*/IORESP_INT); // allow the user to select the device
|
||||
if ( subarch != 0 )
|
||||
break;
|
||||
// create additional segments
|
||||
{
|
||||
ea_t start = (inf_get_max_ea() + 0xFFFFF) & ~0xFFFFF;
|
||||
if ( eepromsize != 0 )
|
||||
{
|
||||
char *file = ask_file(false, "*.bin", "Please enter the binary EEPROM image file");
|
||||
if ( file != NULL )
|
||||
{
|
||||
add_segm(start>>4, start, start+eepromsize, "EEPROM", "DATA");
|
||||
linput_t *li = open_linput(file, false);
|
||||
if ( li != NULL )
|
||||
{
|
||||
uint64 size = qlsize(li);
|
||||
if ( size > eepromsize )
|
||||
size = eepromsize;
|
||||
file2base(li, 0, start, start+size, FILEREG_NOTPATCHABLE);
|
||||
close_linput(li);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile: // old file loaded
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc: // new processor type
|
||||
break;
|
||||
|
||||
case processor_t::ev_newasm: // new assembler type
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_label: // The kernel is going to generate an instruction
|
||||
// label line or a function header
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
if ( helper.altval_ea(ctx->insn_ea) ) // if entry point
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), ctx->insn_ea);
|
||||
ctx->gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
avr_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
avr_footer(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segstart:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
avr_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segend:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
avr_segend(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return emu(*insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_insn:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_insn(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_operand:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return out_opnd(*ctx, *op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 1001 0101 0xx0 1000 ret
|
||||
// 1001 0101 0xx1 1000 reti
|
||||
static const uchar retcode_1[] = { 0x08, 0x95 }; // ret
|
||||
static const uchar retcode_2[] = { 0x18, 0x95 }; // reti
|
||||
static const uchar retcode_3[] = { 0x28, 0x95 }; // ret
|
||||
static const uchar retcode_4[] = { 0x38, 0x95 }; // reti
|
||||
static const uchar retcode_5[] = { 0x48, 0x95 }; // ret
|
||||
static const uchar retcode_6[] = { 0x58, 0x95 }; // reti
|
||||
static const uchar retcode_7[] = { 0x68, 0x95 }; // ret
|
||||
static const uchar retcode_8[] = { 0x78, 0x95 }; // reti
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ sizeof(retcode_3), retcode_3 },
|
||||
{ sizeof(retcode_4), retcode_4 },
|
||||
{ sizeof(retcode_5), retcode_5 },
|
||||
{ sizeof(retcode_6), retcode_6 },
|
||||
{ sizeof(retcode_7), retcode_7 },
|
||||
{ sizeof(retcode_8), retcode_8 },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
#define FAMILY "Atmel AVR series:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"AVR",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Atmel AVR",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_AVR, // id
|
||||
// flag
|
||||
PRN_HEX
|
||||
| PR_RNAMESOK,
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
16, // 16 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames,
|
||||
lnames,
|
||||
|
||||
asms,
|
||||
|
||||
notify,
|
||||
|
||||
register_names, // Register names
|
||||
qnumber(register_names), // Number of registers
|
||||
|
||||
rVcs, // first
|
||||
rVds, // last
|
||||
0, // size of a segment register
|
||||
rVcs, rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
AVR_null,
|
||||
AVR_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
AVR_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
Reference in New Issue
Block a user