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

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