update to ida 7.6, add builds
This commit is contained in:
795
idasdk76/module/fr/ana.cpp
Normal file
795
idasdk76/module/fr/ana.cpp
Normal file
@@ -0,0 +1,795 @@
|
||||
|
||||
#include "fr.hpp"
|
||||
|
||||
// distinct sizes :
|
||||
//lint -esym(749, S_11) not referenced
|
||||
enum
|
||||
{
|
||||
S_0,
|
||||
S_4, // 4 bits
|
||||
S_5, // 5 bits
|
||||
S_8, // 8 bits
|
||||
S_11, // 11 bits
|
||||
S_12, // 12 bits
|
||||
S_16 // 16 bits
|
||||
};
|
||||
|
||||
// bits numbers for sizes :
|
||||
const int bits[] =
|
||||
{
|
||||
0,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
11,
|
||||
12,
|
||||
16
|
||||
};
|
||||
|
||||
// masks for sizes :
|
||||
const int masks[] =
|
||||
{
|
||||
0x0000,
|
||||
0x000F,
|
||||
0x001F,
|
||||
0x00FF,
|
||||
0x07FF,
|
||||
0x0FFF,
|
||||
0xFFFF
|
||||
};
|
||||
|
||||
const char dtypes[] =
|
||||
{
|
||||
0,
|
||||
dt_byte,
|
||||
dt_byte,
|
||||
dt_byte,
|
||||
dt_word,
|
||||
dt_word,
|
||||
dt_word
|
||||
};
|
||||
|
||||
// distinct operands :
|
||||
enum
|
||||
{
|
||||
O_null, // null opcode
|
||||
O_gr, // general register Ri
|
||||
O_gri, // general register indirect @Ri
|
||||
O_grip, // general register indirect post-increment @Ri+
|
||||
O_r13_gr_i, // indirect r13 + general register @(R13, Ri)
|
||||
O_r14_imm8_i, // indirect r14 + 8 bits immediate value @(R14, imm)
|
||||
O_r15_imm4_i, // indirect r15 + 4 bits immediate value @(R15, imm)
|
||||
O_r15ip, // indirect r15 post-increment @R15+
|
||||
O_r15im, // indirect r15 pre-decrement @-R15
|
||||
O_r13, // register r13 R13
|
||||
O_r13ip, // indirect r13 post-increment @R13+
|
||||
O_dr, // dedicated register Rs
|
||||
O_ps, // program status register (PS) PS
|
||||
O_imm, // immediate value #i
|
||||
O_diri, // indirect direct value @i
|
||||
O_rel, // relative value label5
|
||||
O_reglist // register list (R0, R1, R2, ...)
|
||||
};
|
||||
|
||||
static int invert_word(int word)
|
||||
{
|
||||
int new_word = 0;
|
||||
|
||||
new_word |= (word & 0x000F) >> 0;
|
||||
new_word <<= 4;
|
||||
new_word |= (word & 0x00F0) >> 4;
|
||||
new_word <<= 4;
|
||||
new_word |= (word & 0x0F00) >> 8;
|
||||
new_word <<= 4;
|
||||
new_word |= (word & 0xF000) >> 12;
|
||||
|
||||
return new_word;
|
||||
}
|
||||
|
||||
// structure of an opcode :
|
||||
struct opcode_t
|
||||
{
|
||||
int itype;
|
||||
int opcode;
|
||||
int opcode_size;
|
||||
|
||||
int op1;
|
||||
int op1_size;
|
||||
int op2;
|
||||
int op2_size;
|
||||
|
||||
#define I_SWAPOPS 0x00000100 // swap operands
|
||||
#define I_DSHOT 0x00000200 // delay shot
|
||||
#define I_ADDR_R OP_ADDR_R
|
||||
#define I_ADDR_W OP_ADDR_W
|
||||
#define I_IMM_2 0x00001000 // imm = imm * 2
|
||||
#define I_IMM_4 0x00002000 // imm = imm * 4
|
||||
int flags;
|
||||
|
||||
inline bool swap_ops(void) const { return (flags & I_SWAPOPS) != 0; }
|
||||
inline bool delay_shot(void) const { return (flags & I_DSHOT) != 0; }
|
||||
inline bool implied(void) const { return op1 == O_null && op2 == O_null; }
|
||||
|
||||
int size(void) const
|
||||
{
|
||||
int n = bits[opcode_size];
|
||||
if ( op1 != O_null )
|
||||
n += bits[op1_size];
|
||||
if ( op2 != O_null )
|
||||
n += bits[op2_size];
|
||||
return n;
|
||||
}
|
||||
|
||||
static void check(void);
|
||||
static const struct opcode_t *find(insn_t &insn, int *_data);
|
||||
};
|
||||
|
||||
// FR opcodes :
|
||||
static const struct opcode_t opcodes[] =
|
||||
{
|
||||
{ fr_add, 0xA6, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_add, 0xA4, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_add2, 0xA5, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_addc, 0xA7, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_addn, 0xA2, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_addn, 0xA0, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_addn2, 0xA1, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_sub, 0xAC, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_subc, 0xAD, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_subn, 0xAE, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_cmp, 0xAA, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_cmp, 0xA8, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_cmp2, 0xA9, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_and, 0x82, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_and, 0x84, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_andh, 0x85, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_andb, 0x86, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_or, 0x92, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_or, 0x94, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_orh, 0x95, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_orb, 0x96, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_eor, 0x9A, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_eor, 0x9C, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_eorh, 0x9D, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_eorb, 0x9E, S_8, O_gr, S_4, O_gri, S_4, 0 },
|
||||
{ fr_bandl, 0x80, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_bandh, 0x81, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_borl, 0x90, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_borh, 0x91, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_beorl, 0x98, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_beorh, 0x99, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_btstl, 0x88, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_btsth, 0x89, S_8, O_imm, S_4, O_gri, S_4, 0 },
|
||||
{ fr_mul, 0xAF, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_mulu, 0xAB, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_mulh, 0xBF, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_muluh, 0xBB, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_div0s, 0x974, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_div0u, 0x975, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_div1, 0x976, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_div2, 0x977, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_div3, 0x9F60, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_div4s, 0x9F70, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_lsl, 0xB6, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lsl, 0xB4, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lsl2, 0xB5, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lsr, 0xB2, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lsr, 0xB0, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lsr2, 0xB1, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_asr, 0xBA, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_asr, 0xB8, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
{ fr_asr2, 0xB9, S_8, O_imm, S_4, O_gr, S_4, 0 },
|
||||
// fr_ldi_32 not here (considered as special)
|
||||
// fr_ldi_20 not here (considered as special)
|
||||
{ fr_ldi_8, 0x0C, S_4, O_imm, S_8, O_gr, S_4, 0 },
|
||||
{ fr_ld, 0x04, S_8, O_gri, S_4, O_gr, S_4, 0 },
|
||||
{ fr_ld, 0x00, S_8, O_r13_gr_i, S_4, O_gr, S_4, 0 },
|
||||
{ fr_ld, 0x02, S_4, O_r14_imm8_i, S_8, O_gr, S_4, I_IMM_4 },
|
||||
{ fr_ld, 0x03, S_8, O_r15_imm4_i, S_4, O_gr, S_4, I_IMM_4 },
|
||||
{ fr_ld, 0x70, S_12, O_r15ip, S_0, O_gr, S_4, 0 },
|
||||
{ fr_ld, 0x78, S_12, O_r15ip, S_0, O_dr, S_4, 0 },
|
||||
{ fr_ld, 0x790, S_16, O_r15ip, S_0, O_ps, S_0, 0 },
|
||||
{ fr_lduh, 0x05, S_8, O_gri, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lduh, 0x01, S_8, O_r13_gr_i, S_4, O_gr, S_4, 0 },
|
||||
{ fr_lduh, 0x04, S_4, O_r14_imm8_i, S_8, O_gr, S_4, I_IMM_2 },
|
||||
{ fr_ldub, 0x06, S_8, O_gri, S_4, O_gr, S_4, 0 },
|
||||
{ fr_ldub, 0x02, S_8, O_r13_gr_i, S_4, O_gr, S_4, 0 },
|
||||
{ fr_ldub, 0x06, S_4, O_r14_imm8_i, S_8, O_gr, S_4, 0 },
|
||||
{ fr_st, 0x14, S_8, O_gri, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_st, 0x10, S_8, O_r13_gr_i, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_st, 0x03, S_4, O_r14_imm8_i, S_8, O_gr, S_4, I_SWAPOPS|I_IMM_4 },
|
||||
{ fr_st, 0x13, S_8, O_r15_imm4_i, S_4, O_gr, S_4, I_SWAPOPS|I_IMM_4 },
|
||||
{ fr_st, 0x170, S_12, O_gr, S_4, O_r15im, S_0, 0 },
|
||||
{ fr_st, 0x178, S_12, O_dr, S_4, O_r15im, S_0, 0 },
|
||||
{ fr_st, 0x1790, S_16, O_ps, S_0, O_r15im, S_0, 0 },
|
||||
{ fr_sth, 0x15, S_8, O_gri, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_sth, 0x11, S_8, O_r13_gr_i, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_sth, 0x05, S_4, O_r14_imm8_i, S_8, O_gr, S_4, I_SWAPOPS|I_IMM_2 },
|
||||
{ fr_stb, 0x16, S_8, O_gri, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_stb, 0x12, S_8, O_r13_gr_i, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_stb, 0x07, S_4, O_r14_imm8_i, S_8, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_mov, 0x8B, S_8, O_gr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_mov, 0xB7, S_8, O_dr, S_4, O_gr, S_4, 0 },
|
||||
{ fr_mov, 0x171, S_12, O_ps, S_0, O_gr, S_4, 0 },
|
||||
{ fr_mov, 0xB3, S_8, O_dr, S_4, O_gr, S_4, I_SWAPOPS },
|
||||
{ fr_mov, 0x71, S_12, O_gr, S_4, O_ps, S_0, 0 },
|
||||
{ fr_jmp, 0x970, S_12, O_gri, S_4, O_null, 0, 0 },
|
||||
{ fr_call, 0x971, S_12, O_gri, S_4, O_null, 0, 0 },
|
||||
{ fr_ret, 0x9720, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_int, 0x1F, S_8, O_imm, S_8, O_null, 0, 0 },
|
||||
{ fr_inte, 0x9F30, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_reti, 0x9730, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_bra, 0xE0, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bno, 0xE1, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_beq, 0xE2, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bne, 0xE3, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bc, 0xE4, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bnc, 0xE5, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bn, 0xE6, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bp, 0xE7, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bv, 0xE8, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bnv, 0xE9, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_blt, 0xEA, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bge, 0xEB, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_ble, 0xEC, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bgt, 0xED, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bls, 0xEE, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_bhi, 0xEF, S_8, O_rel, S_8, O_null, 0, 0 },
|
||||
{ fr_jmp, 0x9F0, S_12, O_gri, S_4, O_null, 0, I_DSHOT },
|
||||
{ fr_call, 0x9F1, S_12, O_gri, S_4, O_null, 0, I_DSHOT },
|
||||
{ fr_ret, 0x9F20, S_16, O_null, 0, O_null, 0, I_DSHOT },
|
||||
{ fr_bra, 0xF0, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bno, 0xF1, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_beq, 0xF2, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bne, 0xF3, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bc, 0xF4, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bnc, 0xF5, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bn, 0xF6, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bp, 0xF7, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bv, 0xF8, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bnv, 0xF9, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_blt, 0xFA, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bge, 0xFB, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_ble, 0xFC, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bgt, 0xFD, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bls, 0xFE, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_bhi, 0xFF, S_8, O_rel, S_8, O_null, 0, I_DSHOT },
|
||||
{ fr_dmov, 0x08, S_8, O_diri, S_8, O_r13, S_0, I_ADDR_R },
|
||||
{ fr_dmov, 0x18, S_8, O_r13, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_dmov, 0x0C, S_8, O_diri, S_8, O_r13ip, S_0, I_ADDR_R },
|
||||
{ fr_dmov, 0x1C, S_8, O_r13ip, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_dmov, 0x0B, S_8, O_diri, S_8, O_r15im, S_0, I_ADDR_R },
|
||||
{ fr_dmov, 0x1B, S_8, O_r15ip, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_dmovh, 0x09, S_8, O_diri, S_8, O_r13, S_0, I_ADDR_R },
|
||||
{ fr_dmovh, 0x19, S_8, O_r13, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_dmovh, 0x0D, S_8, O_diri, S_8, O_r13ip, S_0, I_ADDR_R },
|
||||
{ fr_dmovh, 0x1D, S_8, O_r13ip, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_dmovb, 0x0A, S_8, O_diri, S_8, O_r13, S_0, I_ADDR_R },
|
||||
{ fr_dmovb, 0x1A, S_8, O_r13, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_dmovb, 0x0E, S_8, O_diri, S_8, O_r13ip, S_0, I_ADDR_R },
|
||||
{ fr_dmovb, 0x1E, S_8, O_r13ip, S_0, O_diri, S_8, I_ADDR_W },
|
||||
{ fr_ldres, 0xBC, S_8, O_imm, S_4, O_grip, S_4, I_SWAPOPS },
|
||||
{ fr_stres, 0xBD, S_8, O_imm, S_4, O_grip, S_4, 0 },
|
||||
// fr_copop not here (considered as special)
|
||||
// fr_copld not here (considered as special)
|
||||
// fr_copst not here (considered as special)
|
||||
// fr_copsv not here (considered as special)
|
||||
{ fr_nop, 0x9FA0, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_andccr, 0x83, S_8, O_imm, S_8, O_null, 0, 0 },
|
||||
{ fr_orccr, 0x93, S_8, O_imm, S_8, O_null, 0, 0 },
|
||||
{ fr_stilm, 0x87, S_8, O_imm, S_8, O_null, 0, 0 },
|
||||
{ fr_addsp, 0xA3, S_8, O_imm, S_8, O_null, 0, 0 },
|
||||
{ fr_extsb, 0x978, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_extub, 0x979, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_extsh, 0x97A, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_extuh, 0x97B, S_12, O_gr, S_4, O_null, 0, 0 },
|
||||
{ fr_ldm0, 0x8C, S_8, O_reglist, S_8, O_null, 0, 0 },
|
||||
{ fr_ldm1, 0x8D, S_8, O_reglist, S_8, O_null, 0, 0 },
|
||||
{ fr_stm0, 0x8E, S_8, O_reglist, S_8, O_null, 0, 0 },
|
||||
{ fr_stm1, 0x8F, S_8, O_reglist, S_8, O_null, 0, 0 },
|
||||
{ fr_enter, 0x0F, S_8, O_imm, S_8, O_null, 0, I_IMM_4 },
|
||||
{ fr_leave, 0x9F90, S_16, O_null, 0, O_null, 0, 0 },
|
||||
{ fr_xchb, 0x8A, S_8, O_gri, S_4, O_gr, S_4, 0 }
|
||||
};
|
||||
|
||||
void opcode_t::check(void)
|
||||
{
|
||||
for ( int i = 0; i < qnumber(opcodes); i++ )
|
||||
{
|
||||
int n = opcodes[i].size();
|
||||
// if ( n != 16 && n != 32 )
|
||||
// msg("instruction n%d (%d) : size %d\n", i, opcodes[i].insn, n);
|
||||
QASSERT(10001, n == 16 || n == 32);
|
||||
}
|
||||
}
|
||||
|
||||
const struct opcode_t * opcode_t::find(insn_t &insn, int *_data)
|
||||
{
|
||||
QASSERT(10002, _data != NULL);
|
||||
|
||||
int data = (*_data << 8) | get_byte(insn.ip + insn.size);
|
||||
for ( int i = 0; i < qnumber(opcodes); i++ )
|
||||
{
|
||||
int mask;
|
||||
int shift;
|
||||
switch ( opcodes[i].opcode_size )
|
||||
{
|
||||
case S_4: mask = 0xF000; shift = 12; break;
|
||||
case S_5: mask = 0xF100; shift = 11; break;
|
||||
case S_8: mask = 0xFF00; shift = 8; break;
|
||||
case S_12: mask = 0xFFF0; shift = 4; break;
|
||||
case S_16: mask = 0xFFFF; shift = 0; break;
|
||||
default: INTERR(10012);
|
||||
}
|
||||
if ( ((data & mask) >> shift) != opcodes[i].opcode )
|
||||
continue;
|
||||
|
||||
insn.size++;
|
||||
*_data = invert_word(data);
|
||||
return &opcodes[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get general register.
|
||||
static int get_gr(const int num)
|
||||
{
|
||||
QASSERT(10003, num >= 0 && num <= 15);
|
||||
return num;
|
||||
}
|
||||
|
||||
// get coprocessor register.
|
||||
static int get_cr(const int num)
|
||||
{
|
||||
QASSERT(10004, num >= 0 && num <= 15);
|
||||
return num + 16;
|
||||
}
|
||||
|
||||
// get dedicated register.
|
||||
static int get_dr(int num)
|
||||
{
|
||||
static const int drs[] =
|
||||
{
|
||||
rTBR,
|
||||
rRP,
|
||||
rSSP,
|
||||
rUSP,
|
||||
rMDH,
|
||||
rMDL,
|
||||
rReserved6,
|
||||
rReserved7,
|
||||
rReserved8,
|
||||
rReserved9,
|
||||
rReserved10,
|
||||
rReserved11,
|
||||
rReserved12,
|
||||
rReserved13,
|
||||
rReserved14,
|
||||
rReserved15
|
||||
};
|
||||
QASSERT(10005, num >= 0 && num <= 15);
|
||||
return drs[num];
|
||||
}
|
||||
|
||||
// fill an operand as a register.
|
||||
static void set_reg(op_t &op, int reg, char d_typ)
|
||||
{
|
||||
op.type = o_reg;
|
||||
op.reg = (uint16)reg;
|
||||
op.dtype = d_typ;
|
||||
}
|
||||
|
||||
// fill an operand as an immediate value.
|
||||
static void set_imm(op_t &op, int imm, char d_typ)
|
||||
{
|
||||
op.type = o_imm;
|
||||
switch ( d_typ )
|
||||
{
|
||||
case dt_byte: op.value = (char) imm; break;
|
||||
case dt_word: op.value = (short) imm; break;
|
||||
case dt_dword: op.value = imm; break;
|
||||
default: INTERR(10013);
|
||||
}
|
||||
op.dtype = d_typ;
|
||||
}
|
||||
|
||||
// fill an operand as a phrase.
|
||||
static void set_phrase(op_t &op, int type, int val, char d_typ)
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case fIGR: // indirect general register
|
||||
case fIGRP: // indirect general register with post-increment
|
||||
case fIGRM: // indirect general register with pre-decrement
|
||||
case fR13RI: // indirect displacement between R13 and a general register
|
||||
op.reg = (uint16)val;
|
||||
break;
|
||||
|
||||
case fIRA: // indirect relative address
|
||||
op.addr = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10014);
|
||||
}
|
||||
op.type = o_phrase;
|
||||
op.specflag2 = (char)type;
|
||||
op.dtype = d_typ;
|
||||
}
|
||||
|
||||
// fill an operand as a relative address.
|
||||
static void set_rel(const insn_t &insn, op_t &op, int addr, char d_typ)
|
||||
{
|
||||
op.type = o_near;
|
||||
int raddr;
|
||||
switch ( d_typ ) /* ugly but functional */
|
||||
{
|
||||
case dt_byte:
|
||||
raddr = ((signed char) addr);
|
||||
break;
|
||||
|
||||
case dt_word:
|
||||
raddr = ((signed short) addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10015);
|
||||
}
|
||||
op.addr = insn.ip + 2 + (raddr * 2); //-V614 uninitialized variable 'raddr'
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a = 0x%a + 2 + ((signed) 0x%X) * 2)\n", op.addr, insn.ip, addr);
|
||||
#endif /* __DEBUG__ */
|
||||
op.dtype = dt_code;
|
||||
}
|
||||
|
||||
// fill an operand as a reglist
|
||||
static void set_reglist(op_t &op, int list)
|
||||
{
|
||||
op.type = o_reglist;
|
||||
op.value = list;
|
||||
op.dtype = dt_byte; // list is coded in a byte
|
||||
}
|
||||
|
||||
static void set_displ(op_t &op, int reg, int imm, int flag, int local_flag)
|
||||
{
|
||||
op.type = o_displ;
|
||||
if ( reg != -1 )
|
||||
op.reg = (uint16)get_gr(reg);
|
||||
if ( imm != -1 )
|
||||
{
|
||||
int mul = 1;
|
||||
if ( local_flag & I_IMM_2 )
|
||||
mul = 2;
|
||||
if ( local_flag & I_IMM_4 )
|
||||
mul = 4;
|
||||
op.value = ((unsigned) imm) * mul;
|
||||
}
|
||||
op.dtype = dt_byte;
|
||||
op.specflag1 |= flag;
|
||||
}
|
||||
|
||||
// swap 2 opcodes (o1 <=> o2).
|
||||
static void swap_ops(op_t &o1, op_t &o2)
|
||||
{
|
||||
QASSERT(10006, o1.type != o_void && o2.type != o_void);
|
||||
op_t tmp = o1;
|
||||
o1 = o2;
|
||||
o2 = tmp;
|
||||
}
|
||||
|
||||
static void adjust_data(int size, int *data)
|
||||
{
|
||||
QASSERT(10007, data != NULL);
|
||||
int new_data = *data >> bits[size];
|
||||
*data = new_data;
|
||||
}
|
||||
|
||||
/*
|
||||
static void prepare_data(int size, int *data) {
|
||||
QASSERT(10008, data != NULL);
|
||||
int new_data = 0;
|
||||
switch ( size ) {
|
||||
case S_0:
|
||||
case S_4:
|
||||
new_data = *data;
|
||||
break;
|
||||
|
||||
case S_5:
|
||||
case S_8:
|
||||
new_data |= (*data & 0x00F0) >> 4;
|
||||
new_data |= (*data & 0x000F) << 4;
|
||||
break;
|
||||
|
||||
case S_11:
|
||||
case S_12:
|
||||
new_data |= (*data & 0x0F00) >> 8;
|
||||
new_data |= (*data & 0x00F0) >> 0;
|
||||
new_data |= (*data & 0x000F) << 8;
|
||||
break;
|
||||
|
||||
case S_16:
|
||||
new_data |= (*data & 0xF000) >> 12;
|
||||
new_data |= (*data & 0x0F00) >> 4;
|
||||
new_data |= (*data & 0x00F0) << 4;
|
||||
new_data |= (*data & 0x000F) << 12;
|
||||
break;
|
||||
}
|
||||
*data = new_data;
|
||||
}*/
|
||||
|
||||
#define SWAP_IF_BYTE(data) \
|
||||
do \
|
||||
{ \
|
||||
if ( operand_size == S_8 ) \
|
||||
{ \
|
||||
int h = (data & 0x0F) << 4; \
|
||||
int l = (data & 0xF0) >> 4; \
|
||||
data = h | l; \
|
||||
} \
|
||||
} \
|
||||
while ( 0 )
|
||||
|
||||
//
|
||||
// defines some shortcuts.
|
||||
//
|
||||
|
||||
#define __set_gr(op, reg) set_reg(op, reg, dt_byte)
|
||||
#define set_gr(op, reg) __set_gr(op, get_gr(reg))
|
||||
#define __set_dr(op, reg) set_reg(op, reg, dt_word)
|
||||
#define set_dr(op, reg) __set_dr(op, get_dr(reg))
|
||||
#define __set_cr(op, reg) set_reg(op, reg, dt_word)
|
||||
#define set_cr(op, reg) __set_cr(op, get_cr(reg))
|
||||
|
||||
#define set_gri(insn, op, reg) set_phrase(op, fIGR, get_gr(reg), dt_byte)
|
||||
#define set_grip(insn, op, reg) set_phrase(op, fIGRP, get_gr(reg), dt_byte)
|
||||
#define set_grim(insn, op, reg) set_phrase(op, fIGRM, get_gr(reg), dt_byte)
|
||||
#define set_diri(insn, op, addr) set_phrase(op, fIRA, addr, dt_word)
|
||||
#define set_r13_gr_i(insn, op, reg) set_phrase(op, fR13RI, get_gr(reg), dt_byte)
|
||||
#define fill_op1(insn, data, opc) fill_op(insn, data, insn.Op1, opc->op1, opc->op1_size, opc->flags)
|
||||
#define fill_op2(insn, data, opc) fill_op(insn, data, insn.Op2, opc->op2, opc->op2_size, opc->flags)
|
||||
//#define set_displ_gr(op, gr, f1) set_displ(op, gr, -1, f1, 0)
|
||||
#define set_displ_imm(op, imm, f1, f2) set_displ(op, -1, imm, f1, f2)
|
||||
|
||||
static void fill_op(const insn_t &insn, int data, op_t &op, int operand, int operand_size, int flags)
|
||||
{
|
||||
data &= masks[operand_size];
|
||||
//prepare_data(operand_size, &data);
|
||||
switch ( operand )
|
||||
{
|
||||
case O_gr: // general register Ri
|
||||
QASSERT(10009, operand_size == S_4);
|
||||
set_gr(op, data);
|
||||
break;
|
||||
|
||||
case O_gri: // general register indirect @Ri
|
||||
QASSERT(10010, operand_size == S_4);
|
||||
set_gri(insn, op, data);
|
||||
break;
|
||||
|
||||
case O_grip: // general register indirect @Ri
|
||||
QASSERT(10011, operand_size == S_4);
|
||||
set_grip(insn, op, data);
|
||||
break;
|
||||
|
||||
case O_r13_gr_i: // indirect r13 + general register @(R13, Ri)
|
||||
set_r13_gr_i(insn, op, data);
|
||||
break;
|
||||
|
||||
case O_r14_imm8_i: // indirect r14 + 8 bits immediate value @(R14, imm)
|
||||
SWAP_IF_BYTE(data);
|
||||
set_displ_imm(op, data, OP_DISPL_IMM_R14, flags);
|
||||
break;
|
||||
|
||||
case O_r15_imm4_i: // indirect r15 + 4 bits immediate value @(R15, imm)
|
||||
SWAP_IF_BYTE(data);
|
||||
set_displ_imm(op, data, OP_DISPL_IMM_R15, flags);
|
||||
break;
|
||||
|
||||
case O_r15ip: // indirect r15 post-increment @R15+
|
||||
set_grip(insn, op, rR15);
|
||||
break;
|
||||
|
||||
case O_r15im: // indirect r15 pre-decrement @-R15
|
||||
set_grim(insn, op, rR15);
|
||||
break;
|
||||
|
||||
case O_r13: // register r13 R13
|
||||
__set_gr(op, rR13);
|
||||
break;
|
||||
|
||||
case O_r13ip: // indirect r13 post-increment @R13+
|
||||
set_grip(insn, op, rR13);
|
||||
break;
|
||||
|
||||
case O_dr: // dedicated register Rs
|
||||
set_dr(op, data);
|
||||
break;
|
||||
|
||||
case O_ps: // program status register (PS) PS
|
||||
__set_dr(op, rPS);
|
||||
break;
|
||||
|
||||
case O_imm: // immediate value #i
|
||||
SWAP_IF_BYTE(data);
|
||||
if ( insn.itype == fr_enter )
|
||||
data *= 4;
|
||||
if ( insn.itype == fr_addsp )
|
||||
data = ((signed) data) * 4;
|
||||
set_imm(op, data, dtypes[operand_size]);
|
||||
break;
|
||||
|
||||
case O_diri: // indirect direct value @i
|
||||
SWAP_IF_BYTE(data);
|
||||
if ( insn.itype == fr_dmov )
|
||||
data *= 4;
|
||||
if ( insn.itype == fr_dmovh )
|
||||
data *= 2;
|
||||
set_diri(insn, op, data);
|
||||
op.specflag1 |= flags;
|
||||
break;
|
||||
|
||||
case O_rel: // relative value label5
|
||||
SWAP_IF_BYTE(data);
|
||||
set_rel(insn, op, data, dtypes[operand_size]);
|
||||
break;
|
||||
|
||||
case O_reglist: // register list (R0, R1, R2, ...)
|
||||
SWAP_IF_BYTE(data);
|
||||
set_reglist(op, data);
|
||||
break;
|
||||
|
||||
case O_null: // null opcode
|
||||
INTERR(10016);
|
||||
}
|
||||
}
|
||||
|
||||
// analyze a "common" instruction (those which are listed in the opcodes[] array).
|
||||
static bool ana_common(insn_t &insn, int data)
|
||||
{
|
||||
const struct opcode_t *op = opcode_t::find(insn, &data);
|
||||
if ( op == NULL )
|
||||
return false;
|
||||
|
||||
// fill instruction type
|
||||
insn.itype = (uint16)op->itype;
|
||||
|
||||
// if instruction is implied, our job is finished!
|
||||
if ( op->implied() )
|
||||
goto ana_finished;
|
||||
|
||||
adjust_data(op->opcode_size, &data);
|
||||
|
||||
// fill operand 1
|
||||
if ( op->op1 != O_null )
|
||||
{
|
||||
fill_op1(insn, data, op);
|
||||
adjust_data(op->op1_size, &data);
|
||||
}
|
||||
|
||||
// fill operand 2
|
||||
if ( op->op2 != O_null )
|
||||
{
|
||||
fill_op2(insn, data, op);
|
||||
adjust_data(op->op2_size, &data);
|
||||
}
|
||||
|
||||
// swap opcodes if needed
|
||||
if ( op->swap_ops() )
|
||||
swap_ops(insn.Op1, insn.Op2);
|
||||
|
||||
ana_finished:
|
||||
insn.auxpref = 0;
|
||||
|
||||
// is insn delay shot ?
|
||||
if ( op->delay_shot() )
|
||||
insn.auxpref |= INSN_DELAY_SHOT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// analyze a "special" instruction (those which are NOT listed in the opcodes[] array).
|
||||
static bool ana_special(insn_t &insn, int data)
|
||||
{
|
||||
// detect ldi:20 instructions
|
||||
if ( data == 0x9B )
|
||||
{
|
||||
insn.itype = fr_ldi_20;
|
||||
data = (data << 8) | insn.get_next_byte();
|
||||
set_gr(insn.Op2, data & 0x000F);
|
||||
set_imm(insn.Op1, insn.get_next_word() | ((data & 0x00F0) << 12), dt_dword);
|
||||
return true;
|
||||
}
|
||||
|
||||
data = (data << 8) | get_byte(insn.ea + insn.size);
|
||||
|
||||
// detect ldi:32 instructions
|
||||
if ( (data & 0xFFF0) == 0x9F80 )
|
||||
{
|
||||
insn.size++;
|
||||
insn.itype = fr_ldi_32;
|
||||
set_gr(insn.Op2, data & 0x000F);
|
||||
set_imm(insn.Op1, insn.get_next_dword(), dt_dword);
|
||||
return true;
|
||||
}
|
||||
|
||||
// detect call [rel] instructions
|
||||
int tmp = (data & 0xF800) >> 11;
|
||||
if ( tmp == 0x1A || tmp == 0x1B )
|
||||
{
|
||||
insn.itype = fr_call;
|
||||
insn.size++;
|
||||
// extend sign
|
||||
if ( data & 0x400 )
|
||||
data |= ~0x07FF;
|
||||
else
|
||||
data &= 0x07FF;
|
||||
set_rel(insn, insn.Op1, data, dt_word);
|
||||
if ( tmp == 0x1B )
|
||||
insn.auxpref |= INSN_DELAY_SHOT;
|
||||
return true;
|
||||
}
|
||||
|
||||
// detect copop/copld/copst/copsv instructions
|
||||
if ( ((data & 0xFF00) >> 8) == 0x9F )
|
||||
{
|
||||
int word = get_word(insn.ea + insn.size + 1);
|
||||
insn.itype = fr_null;
|
||||
switch ( (data & 0x00F0) >> 4 )
|
||||
{
|
||||
// copop
|
||||
case 0xC:
|
||||
insn.itype = fr_copop;
|
||||
set_cr(insn.Op3, (word & 0x00F0) >> 4);
|
||||
set_cr(insn.Op4, word & 0x000F);
|
||||
break;
|
||||
|
||||
// copld
|
||||
case 0xD:
|
||||
insn.itype = fr_copld;
|
||||
set_gr(insn.Op3, (word & 0x00F0) >> 4);
|
||||
set_cr(insn.Op4, word & 0x000F);
|
||||
break;
|
||||
|
||||
// copst
|
||||
case 0xE:
|
||||
insn.itype = fr_copst;
|
||||
set_cr(insn.Op3, (word & 0x00F0) >> 4);
|
||||
set_gr(insn.Op4, word & 0x000F);
|
||||
break;
|
||||
|
||||
// copsv
|
||||
case 0xF:
|
||||
insn.itype = fr_copsv;
|
||||
set_cr(insn.Op3, (word & 0x00F0) >> 4);
|
||||
set_gr(insn.Op4, word & 0x000F);
|
||||
break;
|
||||
}
|
||||
if ( insn.itype != fr_null )
|
||||
{
|
||||
set_imm(insn.Op1, data & 0x000F, dt_byte);
|
||||
set_imm(insn.Op2, (word & 0xFF00) >> 8, dt_byte);
|
||||
insn.size += 3;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// analyze an instruction.
|
||||
int idaapi ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
#if defined(__DEBUG__)
|
||||
opcode_t::check();
|
||||
#endif /* __DEBUG__ */
|
||||
|
||||
int byte = insn.get_next_byte();
|
||||
|
||||
bool ok = ana_special(insn, byte);
|
||||
if ( !ok )
|
||||
ok = ana_common(insn, byte);
|
||||
|
||||
return ok ? insn.size : 0;
|
||||
}
|
||||
250
idasdk76/module/fr/emu.cpp
Normal file
250
idasdk76/module/fr/emu.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
|
||||
#include "fr.hpp"
|
||||
|
||||
// Analyze an instruction
|
||||
static ea_t next_insn(insn_t *insn, ea_t ea)
|
||||
{
|
||||
if ( decode_insn(insn, ea) == 0 )
|
||||
return 0;
|
||||
ea += insn->size;
|
||||
return ea;
|
||||
}
|
||||
|
||||
// Emulate an operand.
|
||||
static void handle_operand(const insn_t &insn, const op_t &op)
|
||||
{
|
||||
bool offset = false;
|
||||
switch ( op.type )
|
||||
{
|
||||
case o_near:
|
||||
insn.add_cref(to_ea(insn.cs, op.addr), op.offb, (insn.itype == fr_call) ? fl_CN : fl_JN);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
enum dref_t mode = dr_U;
|
||||
|
||||
if ( op.specflag1 & OP_ADDR_R )
|
||||
mode = dr_R;
|
||||
else if ( op.specflag1 & OP_ADDR_W )
|
||||
mode = dr_W;
|
||||
|
||||
ea_t ea = to_ea(insn.cs, op.addr);
|
||||
insn.add_dref(ea, op.offb, mode);
|
||||
insn.create_op_data(ea, op);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
// if current insn is ldi:32 #imm, r1
|
||||
// and next insn is call @r1,
|
||||
// replace the immediate value with an offset.
|
||||
if ( insn.itype == fr_ldi_32
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg )
|
||||
{
|
||||
const int callreg = insn.Op2.reg;
|
||||
insn_t nexti;
|
||||
if ( next_insn(&nexti, insn.ea + insn.size ) > 0
|
||||
&& nexti.itype == fr_call
|
||||
&& nexti.Op1.type == o_phrase
|
||||
&& nexti.Op1.specflag2 == fIGR
|
||||
&& nexti.Op1.reg == callreg )
|
||||
{
|
||||
offset = true;
|
||||
}
|
||||
if ( !is_defarg(get_flags(insn.ea), 0) && offset )
|
||||
op_plain_offset(insn.ea, 0, 0);
|
||||
}
|
||||
set_immd(insn.ea);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( !offset && op_adds_xrefs(get_flags(insn.ea), op.n) )
|
||||
insn.add_off_drefs(op, dr_O, 0);
|
||||
|
||||
// create stack variables if necessary
|
||||
{
|
||||
bool ok = false;
|
||||
// ldi8 #our_value, R1
|
||||
// extsb R1
|
||||
// addn R14, R1
|
||||
if ( insn.itype == fr_ldi_8
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == rR1 )
|
||||
{
|
||||
insn_t nexti;
|
||||
next_insn(&nexti, insn.ea + insn.size);
|
||||
if ( nexti.itype == fr_extsb
|
||||
&& nexti.Op1.type == o_reg
|
||||
&& nexti.Op1.reg == rR1 )
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
if ( ok )
|
||||
{
|
||||
ok = false;
|
||||
next_insn(&nexti, nexti.ea + insn.size);
|
||||
if ( nexti.itype == fr_addn
|
||||
&& nexti.Op1.type == o_reg
|
||||
&& nexti.Op1.reg == rR14
|
||||
&& nexti.Op2.type == o_reg
|
||||
&& nexti.Op2.reg == rR1 )
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ldi32 #our_value, Ri
|
||||
// addn R14, Ri
|
||||
//
|
||||
// (where Ri is either R1 or R2)
|
||||
else if ( insn.itype == fr_ldi_32
|
||||
&& insn.Op2.type == o_reg
|
||||
&& (insn.Op2.reg == rR1 || insn.Op2.reg == rR2) )
|
||||
{
|
||||
ushort the_reg = insn.Op2.reg;
|
||||
insn_t nexti;
|
||||
next_insn(&nexti, insn.ea + insn.size);
|
||||
if ( nexti.itype == fr_addn
|
||||
&& nexti.Op1.type == o_reg
|
||||
&& nexti.Op1.reg == rR14
|
||||
&& nexti.Op2.type == o_reg
|
||||
&& nexti.Op2.reg == the_reg )
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ok && may_create_stkvars()
|
||||
&& !is_defarg(get_flags(insn.ea), op.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL && pfn->flags & FUNC_FRAME )
|
||||
{
|
||||
if ( insn.create_stkvar(op, op.value, 0) )
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
case o_phrase: // XXX
|
||||
case o_reglist:
|
||||
case o_void:
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10017);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool fr_t::is_stop(const insn_t &insn) const
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
return (feature & CF_STOP) != 0;
|
||||
}
|
||||
|
||||
// Emulate an instruction.
|
||||
int fr_t::emu(const insn_t &insn) const
|
||||
{
|
||||
bool flow = !is_stop(insn) || (insn.auxpref & INSN_DELAY_SHOT);
|
||||
if ( flow )
|
||||
{
|
||||
insn_t previ;
|
||||
if ( decode_prev_insn(&previ, insn.ea) != BADADDR )
|
||||
flow = !(is_stop(previ) && (previ.auxpref & INSN_DELAY_SHOT));
|
||||
}
|
||||
|
||||
if ( insn.Op1.type != o_void ) handle_operand(insn, insn.Op1);
|
||||
if ( insn.Op2.type != o_void ) handle_operand(insn, insn.Op2);
|
||||
if ( insn.Op3.type != o_void ) handle_operand(insn, insn.Op3);
|
||||
if ( insn.Op4.type != o_void ) handle_operand(insn, insn.Op4);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a function frame
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
ushort savedreg_size = 0;
|
||||
uint32 args_size = 0;
|
||||
uint32 localvar_size;
|
||||
|
||||
ea_t ea = pfn->start_ea;
|
||||
|
||||
// detect multiple ``st Ri, @-R15'' instructions.
|
||||
insn_t insn;
|
||||
while ( (ea=next_insn(&insn, ea)) != 0
|
||||
&& insn.itype == fr_st
|
||||
&& insn.Op1.type == o_reg
|
||||
&& insn.Op2.type == o_phrase
|
||||
&& insn.Op2.reg == rR15
|
||||
&& insn.Op2.specflag2 == fIGRM )
|
||||
{
|
||||
savedreg_size += 4;
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a: detected st Rx, @-R15\n", ea);
|
||||
#endif /* __DEBUG__ */
|
||||
}
|
||||
|
||||
// detect enter #nn
|
||||
if ( insn.itype == fr_enter )
|
||||
{
|
||||
// R14 is automatically pushed by fr_enter
|
||||
savedreg_size += 4;
|
||||
localvar_size = uint32(insn.Op1.value - 4);
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a: detected enter #0x%a\n", ea, insn.Op1.value);
|
||||
#endif /* __DEBUG__ */
|
||||
}
|
||||
// detect mov R15, R14 + ldi #imm, R0 instructions
|
||||
else
|
||||
{
|
||||
if ( insn.itype != fr_mov
|
||||
|| insn.Op1.type != o_reg
|
||||
|| insn.Op1.reg != rR15
|
||||
|| insn.Op2.type != o_reg
|
||||
|| insn.Op2.reg != rR14 )
|
||||
{
|
||||
goto BAD_FUNC;
|
||||
}
|
||||
/*ea = */next_insn(&insn, ea);
|
||||
if ( (insn.itype == fr_ldi_20 || insn.itype == fr_ldi_32)
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == rR0 )
|
||||
{
|
||||
localvar_size = uint32(insn.Op1.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto BAD_FUNC;
|
||||
}
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a: detected ldi #0x%a, R0\n", ea, insn.Op1.value);
|
||||
#endif /* __DEBUG__ */
|
||||
}
|
||||
|
||||
// XXX we don't care about near/far functions, because currently
|
||||
// we don't know how to detect them ;-)
|
||||
|
||||
pfn->flags |= FUNC_FRAME;
|
||||
return add_frame(pfn, localvar_size, savedreg_size, args_size);
|
||||
|
||||
BAD_FUNC:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &)
|
||||
{
|
||||
return OP_SP_ADD | OP_FP_BASED;
|
||||
}
|
||||
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
return get_byte(ea) == 0;
|
||||
}
|
||||
249
idasdk76/module/fr/fr.cfg
Normal file
249
idasdk76/module/fr/fr.cfg
Normal file
@@ -0,0 +1,249 @@
|
||||
|
||||
; http://edevice.fujitsu.com/fj/MANUAL/MANUALl/allliste.html#WEB6
|
||||
|
||||
.default FR30
|
||||
|
||||
DUMMY 0xdeadbeef Dummy port
|
||||
|
||||
;.FR20 documentation under preparation...
|
||||
|
||||
.FR30
|
||||
|
||||
interrupt RESET 0x000FFFFC Reset
|
||||
; 0x000FFFF8 Reserved for system
|
||||
; 0x000FFFF4 Reserved for system
|
||||
; 0x000FFFF0 Reserved for system
|
||||
; 0x000FFFEC Reserved for system
|
||||
; 0x000FFFE8 Reserved for system
|
||||
; 0x000FFFE4 Reserved for system
|
||||
; 0x000FFFE0 Reserved for system
|
||||
; 0x000FFFDC Reserved for system
|
||||
; 0x000FFFD8 Reserved for system
|
||||
; 0x000FFFD4 Reserved for system
|
||||
; 0x000FFFD0 Reserved for system
|
||||
; 0x000FFFCC Reserved for system
|
||||
; 0x000FFFC8 Reserved for system
|
||||
interrupt UIE 0x000FFFC4 Undefined instruction exception
|
||||
interrupt NMI 0x000FFFC0 NMI request
|
||||
interrupt EI0 0x000FFFBC External 0
|
||||
interrupt EI1 0x000FFFB8 External 1
|
||||
interrupt EI2 0x000FFFB4 External 2
|
||||
interrupt EI3 0x000FFFB0 External 3
|
||||
interrupt UARTR0 0x000FFFAC UART 0 reception complete
|
||||
interrupt UARTR1 0x000FFFA8 UART 1 reception complete
|
||||
interrupt UARTR2 0x000FFFA4 UART 2 reception complete
|
||||
interrupt UARTT0 0x000FFFA0 UART 0 transmission complete
|
||||
interrupt UARTT1 0x000FFF9C UART 1 transmission complete
|
||||
interrupt UARTT2 0x000FFF98 UART 2 transmission complete
|
||||
interrupt DMAC0 0x000FFF94 DMAC 0 (end or error)
|
||||
interrupt DMAC1 0x000FFF90 DMAC 1 (end or error)
|
||||
interrupt DMAC2 0x000FFF8C DMAC 2 (end or error)
|
||||
interrupt DMAC3 0x000FFF88 DMAC 3 (end or error)
|
||||
interrupt DMAC4 0x000FFF84 DMAC 4 (end or error)
|
||||
interrupt DMAC5 0x000FFF80 DMAC 5 (end or error)
|
||||
interrupt DMAC6 0x000FFF7C DMAC 6 (end or error)
|
||||
interrupt DMAC7 0x000FFF78 DMAC 7 (end or error)
|
||||
interrupt AD 0x000FFF74 A/D (successive approximation)
|
||||
interrupt RLTIM0 0x000FFF70 Reload timer 0
|
||||
interrupt RLTIM1 0x000FFF6C Reload timer 1
|
||||
interrupt RLTIM2 0x000FFF68 Reload timer 2
|
||||
interrupt PWM0 0x000FFF64 PWM 0
|
||||
interrupt PWM1 0x000FFF60 PWM 1
|
||||
interrupt PWM2 0x000FFF5C PWM 2
|
||||
interrupt PWM3 0x000FFF58 PWM 3
|
||||
interrupt UTIMER0 0x000FFF54 U-TIMER 0
|
||||
interrupt UTIMER1 0x000FFF50 U-TIMER 1
|
||||
interrupt UTIMER2 0x000FFF4C U-TIMER 2
|
||||
interrupt EI4 0x000FFF48 External 4
|
||||
interrupt EI5 0x000FFF44 External 5
|
||||
interrupt EI6 0x000FFF40 External 6
|
||||
interrupt EI7 0x000FFF3C External 7
|
||||
interrupt DSPSI 0x000FFF38 DSP macro software interrupt
|
||||
interrupt DSPOI 0x000FFF34 DSP macro offset interrupt
|
||||
; 0x000FFF30 Reserved for system
|
||||
; 0x000FFF2C Reserved for system
|
||||
; 0x000FFF28 Reserved for system
|
||||
; 0x000FFF24 Reserved for system
|
||||
; 0x000FFF20 Reserved for system
|
||||
; 0x000FFF1C Reserved for system
|
||||
; 0x000FFF18 Reserved for system
|
||||
; 0x000FFF14 Reserved for systemword
|
||||
; 0x000FFF10 Reserved for system
|
||||
; 0x000FFF0C Reserved for system
|
||||
; 0x000FFF08 Reserved for system
|
||||
; 0x000FFF04 Reserved for system
|
||||
interrupt DIS 0x000FFF00 Delayed ressource
|
||||
; 0x000FFEFC Reserved for system (used by REALOS)
|
||||
; 0x000FFEF8 Reserved for system (used by REALOS)
|
||||
interrupt INT 0x000FFEF4 For INT instruction
|
||||
|
||||
.FR50
|
||||
|
||||
interrupt RESET 0x000FFFFC Reset
|
||||
interrupt MVEC 0x000FFFF8 Mode vector
|
||||
;0x000FFFF4 System reserved
|
||||
;0x000FFFF0 System reserved
|
||||
;0x000FFFEC System reserved
|
||||
;0x000FFFE8 System reserved
|
||||
;0x000FFFE4 System reserved
|
||||
interrupt COPTRAP 0x000FFFE0 Co-processor fault trap *4
|
||||
interrupt COPETRAP 0x000FFFDC Co-processor error trap *4
|
||||
interrupt INTE 0x000FFFD8 INTE instruction *4
|
||||
interrupt IBE 0x000FFFD4 Instruction break exception *4
|
||||
interrupt OBT 0x000FFFD0 Operand break trap *4
|
||||
interrupt STT 0x000FFFCC Step trace trap *4
|
||||
interrupt NMI 0x000FFFC8 NMI (tool)*4
|
||||
interrupt UIE 0x000FFFC4 Undefined instruction exception
|
||||
interrupt NMI_REQ 0x000FFFC0 NMI request
|
||||
interrupt EI0 0x000FFFBC External Interrupt 0
|
||||
interrupt EI1 0x000FFFB8 External Interrupt 1
|
||||
interrupt EI2 0x000FFFB4 External Interrupt 2
|
||||
interrupt EI3 0x000FFFB0 External Interrupt 3
|
||||
interrupt EI4 0x000FFFAC External Interrupt 4
|
||||
interrupt EI5 0x000FFFA8 External Interrupt 5
|
||||
interrupt EI6 0x000FFFA4 External Interrupt 6
|
||||
interrupt EI7 0x000FFFA0 External Interrupt 7
|
||||
interrupt RLTIM0 0x000FFF9C Reload Timer 0
|
||||
interrupt RLTIM1 0x000FFF98 Reload Timer 1
|
||||
interrupt RLTIM2 0x000FFF94 Reload Timer 2
|
||||
interrupt CAN0RX 0x000FFF90 CAN 0 RX
|
||||
interrupt CAN0TX 0x000FFF8C CAN 0 TX/NS
|
||||
interrupt CAN1RX 0x000FFF88 CAN 1 RX
|
||||
interrupt CAN1TX 0x000FFF84 CAN 1 TX/NS
|
||||
interrupt CAN2RX 0x000FFF80 CAN 2 RX
|
||||
interrupt CAN2TX 0x000FFF7C CAN 2 TX/NS
|
||||
interrupt CAN3RX 0x000FFF78 CAN 3 RX *5
|
||||
interrupt CAN3TX 0x000FFF74 CAN 3 TX/NS *5
|
||||
interrupt PPG01 0x000FFF70 PPG 0/1
|
||||
interrupt PPG23 0x000FFF6C PPG 2/3
|
||||
interrupt PPG45 0x000FFF68 PPG 4/5
|
||||
interrupt PPG67 0x000FFF64 PPG 6/7
|
||||
interrupt RLTIM3 0x000FFF60 Reload Timer 3
|
||||
interrupt RLTIM4 0x000FFF5C Reload Timer 4
|
||||
interrupt RLTIM5 0x000FFF58 Reload Timer 5
|
||||
interrupt ICU01 0x000FFF54 ICU 0/1
|
||||
interrupt OCU01 0x000FFF50 OCU 0/1
|
||||
interrupt ICU23 0x000FFF4C ICU 2/3
|
||||
interrupt OCU23 0x000FFF48 OCU 2/3
|
||||
interrupt ADC 0x000FFF44 ADC
|
||||
interrupt TO 0x000FFF40 Timebase Overflow
|
||||
interrupt FRC0 0x000FFF3C Free Running Counter 0
|
||||
interrupt FRC1 0x000FFF38 Free Running Counter 1
|
||||
interrupt SIO0 0x000FFF34 SIO 0 *6
|
||||
interrupt SIO1 0x000FFF30 SIO 1 *6
|
||||
interrupt SG 0x000FFF2C Sound Generator
|
||||
interrupt UART0RX 0x000FFF28 UART 0 RX
|
||||
interrupt UART0TX 0x000FFF24 UART 0 TX
|
||||
interrupt UART1RX 0x000FFF20 UART 1 RX
|
||||
interrupt UART1TX 0x000FFF1C UART 1 TX
|
||||
interrupt UART2RX 0x000FFF18 UART 2 RX
|
||||
interrupt UART3TX 0x000FFF14 UART 2 TX
|
||||
interrupt I2C 0x000FFF10 I2C
|
||||
interrupt ACMP 0x000FFF0C Alarm Comparator
|
||||
interrupt RTC 0x000FFF08 RTC (Watchtimer) / Calibration Unit
|
||||
interrupt DMA 0x000FFF04 DMA
|
||||
interrupt DIAB 0x000FFF00 Delayed activation bit
|
||||
;0x000FFEFC System reserved *3
|
||||
;0x000FFEF8 System reserved *3
|
||||
interrupt SECVEC 0x000FFEF4 Security vector
|
||||
;0x000FFEF0 System reserved
|
||||
;0x000FFEEC System reserved
|
||||
;0x000FFEE8 System reserved
|
||||
;0x000FFEE4 System reserved
|
||||
;0x000FFEE0 System reserved
|
||||
;0x000FFEDC System reserved
|
||||
;0x000FFED8 System reserved
|
||||
;0x000FFED4 System reserved
|
||||
;0x000FFED0 System reserved
|
||||
;0x000FFECC System reserved
|
||||
;0x000FFEC8 System reserved
|
||||
;0x000FFEC4 System reserved
|
||||
;0x000FFEC0 System reserved
|
||||
interrupt INT0 0x000FFEBC Used by the INT instruction.
|
||||
interrupt INT1 0x000FFC00 Used by the INT instruction.
|
||||
|
||||
.FR65E
|
||||
|
||||
interrupt RESET 0x000FFFFC Reset
|
||||
interrupt MVEC 0x000FFFF8 Mode vector
|
||||
; 0x000FFFF4 Reserved for system
|
||||
; 0x000FFFF0 Reserved for system
|
||||
; 0x000FFFEC Reserved for system
|
||||
; 0x000FFFE8 Reserved for system
|
||||
; 0x000FFFE4 Reserved for system
|
||||
interrupt COPTRAP 0x000FFFE0 No-coprocessor trap
|
||||
interrupt COPETRAP 0x000FFFDC Coprocessor error trap
|
||||
interrupt INTE 0x000FFFD8 INTE instruction
|
||||
interrupt IBE 0x000FFFD4 Instruction break exception
|
||||
interrupt OBT 0x000FFFD0 Operand break trap
|
||||
interrupt STT 0x000FFFCC Step trace trap
|
||||
interrupt NMI 0x000FFFC8 NMI request (tool)
|
||||
interrupt UIE 0x000FFFC4 Undefined instruction exception
|
||||
interrupt NMIREQ 0x000FFFC0 NMI request
|
||||
interrupt EI0 0x000FFFBC External Interrupt 0
|
||||
interrupt EI1 0x000FFFB8 External Interrupt 1
|
||||
interrupt EI2 0x000FFFB4 External Interrupt 2
|
||||
interrupt EI3 0x000FFFB0 External Interrupt 3
|
||||
interrupt EI4 0x000FFFAC External Interrupt 4
|
||||
interrupt EI5 0x000FFFA8 External Interrupt 5
|
||||
interrupt EI6 0x000FFFA4 External Interrupt 6
|
||||
interrupt EI7 0x000FFFA0 External Interrupt 7
|
||||
interrupt RLTIM0 0x000FFF9C Reload Timer 0
|
||||
interrupt RLTIM1 0x000FFF98 Reload Timer 1
|
||||
interrupt RLTIM2 0x000FFF94 Reload Timer 2
|
||||
interrupt UARTR0 0x000FFF90 UART0 (reception completed)
|
||||
interrupt UARTR1 0x000FFF8C UART1 (reception completed)
|
||||
interrupt UARTR2 0x000FFF88 UART2 (reception completed)
|
||||
interrupt UARTT0 0x000FFF84 UART0 (transmission completed)
|
||||
interrupt UARTT1 0x000FFF80 UART1 (transmission completed)
|
||||
interrupt UARTT2 0x000FFF7C UART2 (transmission completed)
|
||||
interrupt DMAC0 0x000FFF78 DMAC0 (end, error)
|
||||
interrupt DMAC1 0x000FFF74 DMAC1 (end, error)
|
||||
interrupt DMAC2 0x000FFF70 DMAC2 (end, error)
|
||||
interrupt DMAC3 0x000FFF6C DMAC3 (end, error)
|
||||
interrupt DMAC4 0x000FFF68 DMAC4 (end, error)
|
||||
interrupt AD 0x000FFF64 A/D
|
||||
interrupt I2C 0x000FFF60 I2C
|
||||
; 0x000FFF5C Reserved for system
|
||||
; 0x000FFF58 Reserved for system
|
||||
; 0x000FFF54 Reserved for system
|
||||
; 0x000FFF50 Reserved for system
|
||||
interrupt UTIMER0 0x000FFF4C U-TIMER0
|
||||
interrupt UTIMER1 0x000FFF48 U-TIMER1
|
||||
interrupt UTIMER2 0x000FFF44 U-TIMER2
|
||||
interrupt TBTO 0x000FFF40 Time base timer overflow
|
||||
; 0x000FFF3C Reserved for system
|
||||
; 0x000FFF38 Reserved for system
|
||||
; 0x000FFF34 Reserved for system
|
||||
; 0x000FFF30 Reserved for system
|
||||
; 0x000FFF2C Reserved for system
|
||||
; 0x000FFF28 Reserved for system
|
||||
; 0x000FFF24 Reserved for system
|
||||
; 0x000FFF20 Reserved for system
|
||||
; 0x000FFF1C Reserved for system
|
||||
; 0x000FFF18 Reserved for system
|
||||
; 0x000FFF14 Reserved for system
|
||||
; 0x000FFF10 Reserved for system
|
||||
; 0x000FFF0C Reserved for system
|
||||
; 0x000FFF08 Reserved for system
|
||||
; 0x000FFF04 Reserved for system
|
||||
interrupt DISB 0x000FFF00 Delayed source bit
|
||||
; 0x000FFEFC Reserved for system (used by REALOS)
|
||||
; 0x000FFEF8 Reserved for system (used by REALOS)
|
||||
; 0x000FFEF4 Reserved for system
|
||||
; 0x000FFEF0 Reserved for system
|
||||
; 0x000FFEEC Reserved for system
|
||||
; 0x000FFEE8 Reserved for system
|
||||
; 0x000FFEE4 Reserved for system
|
||||
; 0x000FFEE0 Reserved for system
|
||||
; 0x000FFEDC Reserved for system
|
||||
; 0x000FFED8 Reserved for system
|
||||
; 0x000FFED4 Reserved for system
|
||||
; 0x000FFED0 Reserved for system
|
||||
; 0x000FFECC Reserved for system
|
||||
; 0x000FFEC8 Reserved for system
|
||||
; 0x000FFEC4 Reserved for system
|
||||
; 0x000FFEC0 Reserved for system
|
||||
interrupt INT0 0x000FFEBC Used in INT instruction
|
||||
interrupt INT1 0x000FFC00 Used in INT instruction
|
||||
|
||||
144
idasdk76/module/fr/fr.hpp
Normal file
144
idasdk76/module/fr/fr.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
|
||||
#ifndef __FR_HPP
|
||||
#define __FR_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <frame.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
// uncomment this for the final release
|
||||
//#define __DEBUG__
|
||||
|
||||
// FR registers
|
||||
enum fr_registers
|
||||
{
|
||||
// general purpose registers :
|
||||
|
||||
rR0,
|
||||
rR1,
|
||||
rR2,
|
||||
rR3,
|
||||
rR4,
|
||||
rR5,
|
||||
rR6,
|
||||
rR7,
|
||||
rR8,
|
||||
rR9,
|
||||
rR10,
|
||||
rR11,
|
||||
rR12,
|
||||
rR13,
|
||||
rR14,
|
||||
rR15,
|
||||
|
||||
// coprocessor registers :
|
||||
|
||||
rCR0,
|
||||
rCR1,
|
||||
rCR2,
|
||||
rCR3,
|
||||
rCR4,
|
||||
rCR5,
|
||||
rCR6,
|
||||
rCR7,
|
||||
rCR8,
|
||||
rCR9,
|
||||
rCR10,
|
||||
rCR11,
|
||||
rCR12,
|
||||
rCR13,
|
||||
rCR14,
|
||||
rCR15,
|
||||
|
||||
// dedicated registers :
|
||||
|
||||
rPC, // program counter
|
||||
rPS, // program status
|
||||
rTBR, // table base register
|
||||
rRP, // return pointer
|
||||
rSSP, // system stack pointer
|
||||
rUSP, // user stack pointer
|
||||
rMDL, // multiplication/division register (LOW)
|
||||
rMDH, // multiplication/division register (HIGH)
|
||||
|
||||
// system use dedicated registers
|
||||
rReserved6,
|
||||
rReserved7,
|
||||
rReserved8,
|
||||
rReserved9,
|
||||
rReserved10,
|
||||
rReserved11,
|
||||
rReserved12,
|
||||
rReserved13,
|
||||
rReserved14,
|
||||
rReserved15,
|
||||
|
||||
// these 2 registers are required by the IDA kernel :
|
||||
|
||||
rVcs,
|
||||
rVds
|
||||
};
|
||||
|
||||
enum fr_phrases
|
||||
{
|
||||
fIGR, // indirect general register
|
||||
fIRA, // indirect relative address
|
||||
fIGRP, // indirect general register with post-increment
|
||||
fIGRM, // indirect general register with pre-decrement
|
||||
fR13RI, // indirect displacement between R13 and a general register
|
||||
};
|
||||
|
||||
// shortcut for a new operand type
|
||||
#define o_reglist o_idpspec0
|
||||
|
||||
// flags for insn.auxpref
|
||||
#define INSN_DELAY_SHOT 0x00000001 // postfix insn mnem by ":D"
|
||||
|
||||
// flags for opt.specflag1
|
||||
#define OP_DISPL_IMM_R14 0x00000001 // @(R14, #i)
|
||||
#define OP_DISPL_IMM_R15 0x00000002 // @(R15, #i)
|
||||
#define OP_ADDR_R 0x00000010 // read-access to memory
|
||||
#define OP_ADDR_W 0x00000012 // write-access to memory
|
||||
|
||||
inline bool op_displ_imm_r14(const op_t &op) { return (op.specflag1 & OP_DISPL_IMM_R14) != 0; }
|
||||
inline bool op_displ_imm_r15(const op_t &op) { return (op.specflag1 & OP_DISPL_IMM_R15) != 0; }
|
||||
|
||||
// exporting our routines
|
||||
int idaapi ana(insn_t *_insn);
|
||||
bool idaapi create_func_frame(func_t *pfn);
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &x);
|
||||
int idaapi is_align_insn(ea_t ea);
|
||||
|
||||
struct fr_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
iohandler_t ioh = iohandler_t(helper);
|
||||
bool print_comma = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
int choose_device();
|
||||
const ioport_t *find_sym(ea_t address);
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/);
|
||||
void fr_header(outctx_t &ctx);
|
||||
|
||||
int emu(const insn_t &insn) const;
|
||||
bool is_stop(const insn_t &insn) const;
|
||||
|
||||
void fr_footer(outctx_t &ctx) const;
|
||||
void fr_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
|
||||
void load_from_idb();
|
||||
};
|
||||
|
||||
extern int data_id;
|
||||
#define PROCMOD_NODE_NAME "$ fr"
|
||||
#define PROCMOD_NAME fr
|
||||
|
||||
#endif /* __FR_HPP */
|
||||
109
idasdk76/module/fr/ins.cpp
Normal file
109
idasdk76/module/fr/ins.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
#include "fr.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // null instruction
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG2 }, // add word data of source register / 4-bit immediate data to destination register
|
||||
{ "add2", CF_USE1|CF_USE2|CF_CHG2 }, // add 4-bit immediate data to destination register
|
||||
{ "addc", CF_USE1|CF_USE2|CF_CHG2 }, // add word data of source register and carry bit to destination register
|
||||
{ "addn", CF_USE1|CF_USE2|CF_CHG2 }, // add word data of source register / immediate data to destination register
|
||||
{ "addn2", CF_USE1|CF_USE2|CF_CHG2 }, // add immediate data to destination register
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG2 }, // subtract word data in source register from destination register
|
||||
{ "subc", CF_USE1|CF_USE2|CF_CHG2 }, // subtract word data in source register and carry bit from destination register
|
||||
{ "subn", CF_USE1|CF_USE2|CF_CHG2 }, // subtract word data in source register from destination register
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // compare word / immediate data in source register and destination register
|
||||
{ "cmp2", CF_USE1|CF_USE2 }, // compare immediate data and destination register
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG2 }, // and word data of source register to destination register / data in memory
|
||||
{ "andh", CF_USE1|CF_USE2|CF_CHG2 }, // and half-word data of source register to data in memory
|
||||
{ "andb", CF_USE1|CF_USE2|CF_CHG2 }, // and byte data of source register to data in memory
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG2 }, // or word data of source register to destination register / data in memory
|
||||
{ "orh", CF_USE1|CF_USE2|CF_CHG2 }, // or half-word data of source register to data in memory
|
||||
{ "orb", CF_USE1|CF_USE2|CF_CHG2 }, // or byte data of source register to data in memory
|
||||
{ "eor", CF_USE1|CF_USE2|CF_CHG2 }, // exclusive or word data of source register to destination register / data in memory
|
||||
{ "eorh", CF_USE1|CF_USE2|CF_CHG2 }, // exclusive or half-word data of source register to data in memory
|
||||
{ "eorb", CF_USE1|CF_USE2|CF_CHG2 }, // exclusive or byte data of source register to data in memory
|
||||
{ "bandl", CF_USE1|CF_USE2|CF_CHG2 }, // and 4-bit immediate data to lower 4 bits of byte data in memory
|
||||
{ "bandh", CF_USE1|CF_USE2|CF_CHG2 }, // and 4-bit immediate data to higher 4 bits of byte data in memory
|
||||
{ "borl", CF_USE1|CF_USE2|CF_CHG2 }, // or 4-bit immediate data to lower 4 bits of byte data in memory
|
||||
{ "borh", CF_USE1|CF_USE2|CF_CHG2 }, // or 4-bit immediate data to higher 4 bits of byte data in memory
|
||||
{ "beorl", CF_USE1|CF_USE2|CF_CHG2 }, // eor 4-bit immediate data to lower 4 bits of byte data in memory
|
||||
{ "beorh", CF_USE1|CF_USE2|CF_CHG2 }, // eor 4-bit immediate data to higher 4 bits of byte data in memory
|
||||
{ "btstl", CF_USE1|CF_USE2 }, // test lower 4 bits of byte data in memory
|
||||
{ "btsth", CF_USE1|CF_USE2 }, // test higher 4 bits of byte data in memory
|
||||
{ "mul", CF_USE1|CF_USE2 }, // multiply word data
|
||||
{ "mulu", CF_USE1|CF_USE2 }, // multiply unsigned word data
|
||||
{ "mulh", CF_USE1|CF_USE2 }, // multiply half-word data
|
||||
{ "muluh", CF_USE1|CF_USE2 }, // multiply unsigned half-word data
|
||||
{ "div0s", CF_USE1 }, // initial setting up for signed division
|
||||
{ "div0u", CF_USE1 }, // initial setting up for unsigned division
|
||||
{ "div1", CF_USE1 }, // main process of division
|
||||
{ "div2", CF_USE1 }, // correction when remainder is 0
|
||||
{ "div3", 0 }, // correction when remainder is 0
|
||||
{ "div4s", 0 }, // correction answer for signed division
|
||||
{ "lsl", CF_USE1|CF_USE2|CF_CHG2 }, // logical shift to the left direction
|
||||
{ "lsl2", CF_USE1|CF_USE2|CF_CHG2 }, // logical shift to the left direction
|
||||
{ "lsr", CF_USE1|CF_USE2|CF_CHG2 }, // logical shift to the right direction
|
||||
{ "lsr2", CF_USE1|CF_USE2|CF_CHG2 }, // logical shift to the right direction
|
||||
{ "asr", CF_USE1|CF_USE2|CF_CHG2 }, // arithmetic shift to the right direction
|
||||
{ "asr2", CF_USE1|CF_USE2|CF_CHG2 }, // arithmetic shift to the right direction
|
||||
{ "ldi:32", CF_USE1|CF_USE2|CF_CHG2 }, // load immediate 32-bit data to destination register
|
||||
{ "ldi:20", CF_USE1|CF_USE2|CF_CHG2 }, // load immediate 20-bit data to destination register
|
||||
{ "ldi:8", CF_USE1|CF_USE2|CF_CHG2 }, // load immediate 8-bit data to destination register
|
||||
{ "ld", CF_USE1|CF_USE2|CF_CHG2 }, // load word data in memory to register / program status register
|
||||
{ "lduh", CF_USE1|CF_USE2|CF_CHG2 }, // load half-word data in memory to register
|
||||
{ "ldub", CF_USE1|CF_USE2|CF_CHG2 }, // load byte data in memory to register
|
||||
{ "st", CF_USE1|CF_USE2|CF_CHG2 }, // store word data in register / program status register to memory
|
||||
{ "sth", CF_USE1|CF_USE2|CF_CHG2 }, // store half-word data in register to memory
|
||||
{ "stb", CF_USE1|CF_USE2|CF_CHG2 }, // store byte data in register to memory
|
||||
{ "mov", CF_USE1|CF_USE2|CF_CHG2 }, // move word data in source register / program status register to destination register / program status register
|
||||
{ "jmp", CF_USE1|CF_STOP }, // jump
|
||||
{ "call", CF_USE1|CF_CALL }, // call subroutine
|
||||
{ "ret", CF_STOP }, // return from subroutine
|
||||
{ "int", CF_USE1 }, // software interrupt
|
||||
{ "inte", 0 }, // software interrupt for emulator
|
||||
{ "reti", CF_STOP }, // return from interrupt
|
||||
{ "bra", CF_USE1|CF_STOP }, // branch relative if condition satisfied
|
||||
{ "bno", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "beq", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bne", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bc", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bnc", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bn", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bp", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bv", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bnv", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "blt", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bge", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "ble", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bgt", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bls", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "bhi", CF_USE1 }, // branch relative if condition satisfied
|
||||
{ "dmov", CF_USE1|CF_USE2|CF_CHG2 }, // move word data from register / address to register / address
|
||||
{ "dmovh", CF_USE1|CF_USE2|CF_CHG2 }, // move half-word data from register / address to register / address
|
||||
{ "dmovb", CF_USE1|CF_USE2|CF_CHG2 }, // move byte data from register / address to register / address
|
||||
{ "ldres", CF_USE1|CF_USE2|CF_CHG1 }, // load word data in memory to resource
|
||||
{ "stres", CF_USE1|CF_USE2|CF_CHG1 }, // store word data in resource to memory
|
||||
{ "copop", CF_USE1|CF_USE2|CF_USE3|CF_USE4 }, // coprocessor operation
|
||||
{ "copld", CF_USE1|CF_USE2|CF_USE3|CF_USE4|CF_CHG4 }, // load 32-bit data from register to coprocessor register
|
||||
{ "copst", CF_USE1|CF_USE2|CF_USE3|CF_USE4|CF_CHG4 }, // store 32-bit data from coprocessor register to register
|
||||
{ "copsv", CF_USE1|CF_USE2|CF_USE3|CF_USE4|CF_CHG4 }, // save 32-bit data from coprocessor register to register
|
||||
{ "nop", 0 }, // no operation
|
||||
{ "andccr", CF_USE1 }, // and condition code register and immediate data
|
||||
{ "orccr", CF_USE1 }, // or condition code register and immediate data
|
||||
{ "stilm", CF_USE1 }, // set immediate data to interrupt level mask register
|
||||
{ "addsp", CF_USE1 }, // add stack pointer and immediate data
|
||||
{ "extsb", CF_USE1|CF_CHG1 }, // sign extend from byte data to word data
|
||||
{ "extub", CF_USE1|CF_CHG1 }, // unsign extend from byte data to word data
|
||||
{ "extsh", CF_USE1|CF_CHG1 }, // sign extend from byte data to word data
|
||||
{ "extuh", CF_USE1|CF_CHG1 }, // unsigned extend from byte data to word data
|
||||
{ "ldm0", CF_USE1 }, // load multiple registers
|
||||
{ "ldm1", CF_USE1 }, // load multiple registers
|
||||
{ "stm0", CF_USE1 }, // store multiple registers
|
||||
{ "stm1", CF_USE1 }, // store multiple registers
|
||||
{ "enter", CF_USE1 }, // enter function
|
||||
{ "leave", CF_USE1 }, // leave function
|
||||
{ "xchb", CF_CHG1|CF_CHG2 } // exchange byte data
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == fr_last);
|
||||
114
idasdk76/module/fr/ins.hpp
Normal file
114
idasdk76/module/fr/ins.hpp
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
#ifndef __ins_hpp
|
||||
#define __ins_hpp
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
fr_null = 0, // null instruction
|
||||
|
||||
fr_add, // add word data of source register / 4-bit immediate data to destination register
|
||||
fr_add2, // add 4-bit immediate data to destination register
|
||||
fr_addc, // add word data of source register and carry bit to destination register
|
||||
fr_addn, // add word data of source register / immediate data to destination register
|
||||
fr_addn2, // add immediate data to destination register
|
||||
fr_sub, // subtract word data in source register from destination register
|
||||
fr_subc, // subtract word data in source register and carry bit from destination register
|
||||
fr_subn, // subtract word data in source register from destination register
|
||||
fr_cmp, // compare word / immediate data in source register and destination register
|
||||
fr_cmp2, // compare immediate data and destination register
|
||||
fr_and, // and word data of source register to destination register / data in memory
|
||||
fr_andh, // and half-word data of source register to data in memory
|
||||
fr_andb, // and byte data of source register to data in memory
|
||||
fr_or, // or word data of source register to destination register / data in memory
|
||||
fr_orh, // or half-word data of source register to data in memory
|
||||
fr_orb, // or byte data of source register to data in memory
|
||||
fr_eor, // exclusive or word data of source register to destination register / data in memory
|
||||
fr_eorh, // exclusive or half-word data of source register to data in memory
|
||||
fr_eorb, // exclusive or byte data of source register to data in memory
|
||||
fr_bandl, // and 4-bit immediate data to lower 4 bits of byte data in memory
|
||||
fr_bandh, // and 4-bit immediate data to higher 4 bits of byte data in memory
|
||||
fr_borl, // or 4-bit immediate data to lower 4 bits of byte data in memory
|
||||
fr_borh, // or 4-bit immediate data to higher 4 bits of byte data in memory
|
||||
fr_beorl, // eor 4-bit immediate data to lower 4 bits of byte data in memory
|
||||
fr_beorh, // eor 4-bit immediate data to higher 4 bits of byte data in memory
|
||||
fr_btstl, // test lower 4 bits of byte data in memory
|
||||
fr_btsth, // test higher 4 bits of byte data in memory
|
||||
fr_mul, // multiply word data
|
||||
fr_mulu, // multiply unsigned word data
|
||||
fr_mulh, // multiply half-word data
|
||||
fr_muluh, // multiply unsigned half-word data
|
||||
fr_div0s, // initial setting up for signed division
|
||||
fr_div0u, // initial setting up for unsigned division
|
||||
fr_div1, // main process of division
|
||||
fr_div2, // correction when remainder is 0
|
||||
fr_div3, // correction when remainder is 0
|
||||
fr_div4s, // correction answer for signed division
|
||||
fr_lsl, // logical shift to the left direction
|
||||
fr_lsl2, // logical shift to the left direction
|
||||
fr_lsr, // logical shift to the right direction
|
||||
fr_lsr2, // logical shift to the right direction
|
||||
fr_asr, // arithmetic shift to the right direction
|
||||
fr_asr2, // arithmetic shift to the right direction
|
||||
fr_ldi_32, // load immediate 32-bit data to destination register
|
||||
fr_ldi_20, // load immediate 20-bit data to destination register
|
||||
fr_ldi_8, // load immediate 8-bit data to destination register
|
||||
fr_ld, // load word data in memory to register / program status register
|
||||
fr_lduh, // load half-word data in memory to register
|
||||
fr_ldub, // load byte data in memory to register
|
||||
fr_st, // store word data in register / program status register to memory
|
||||
fr_sth, // store half-word data in register to memory
|
||||
fr_stb, // store byte data in register to memory
|
||||
fr_mov, // move word data in source register / program status register to destination register / program status register
|
||||
fr_jmp, // jump
|
||||
fr_call, // call subroutine
|
||||
fr_ret, // return from subroutine
|
||||
fr_int, // software interrupt
|
||||
fr_inte, // software interrupt for emulator
|
||||
fr_reti, // return from interrupt
|
||||
fr_bra, // branch relative if condition satisfied
|
||||
fr_bno, // branch relative if condition satisfied
|
||||
fr_beq, // branch relative if condition satisfied
|
||||
fr_bne, // branch relative if condition satisfied
|
||||
fr_bc, // branch relative if condition satisfied
|
||||
fr_bnc, // branch relative if condition satisfied
|
||||
fr_bn, // branch relative if condition satisfied
|
||||
fr_bp, // branch relative if condition satisfied
|
||||
fr_bv, // branch relative if condition satisfied
|
||||
fr_bnv, // branch relative if condition satisfied
|
||||
fr_blt, // branch relative if condition satisfied
|
||||
fr_bge, // branch relative if condition satisfied
|
||||
fr_ble, // branch relative if condition satisfied
|
||||
fr_bgt, // branch relative if condition satisfied
|
||||
fr_bls, // branch relative if condition satisfied
|
||||
fr_bhi, // branch relative if condition satisfied
|
||||
fr_dmov, // move word data from register / address to register / address
|
||||
fr_dmovh, // move half-word data from register / address to register / address
|
||||
fr_dmovb, // move byte data from register / address to register / address
|
||||
fr_ldres, // load word data in memory to resource
|
||||
fr_stres, // store word data in resource to memory
|
||||
fr_copop, // coprocessor operation
|
||||
fr_copld, // load 32-bit data from register to coprocessor register
|
||||
fr_copst, // store 32-bit data from coprocessor register to register
|
||||
fr_copsv, // save 32-bit data from coprocessor register to register
|
||||
fr_nop, // no operation
|
||||
fr_andccr, // and condition code register and immediate data
|
||||
fr_orccr, // or condition code register and immediate data
|
||||
fr_stilm, // set immediate data to interrupt level mask register
|
||||
fr_addsp, // add stack pointer and immediate data
|
||||
fr_extsb, // sign extend from byte data to word data
|
||||
fr_extub, // unsign extend from byte data to word data
|
||||
fr_extsh, // sign extend from byte data to word data
|
||||
fr_extuh, // unsigned extend from byte data to word data
|
||||
fr_ldm0, // load multiple registers
|
||||
fr_ldm1, // load multiple registers
|
||||
fr_stm0, // store multiple registers
|
||||
fr_stm1, // store multiple registers
|
||||
fr_enter, // enter function
|
||||
fr_leave, // leave function
|
||||
fr_xchb, // exchange byte data
|
||||
fr_last // last instruction
|
||||
};
|
||||
|
||||
#endif /* __ins_hpp */
|
||||
57
idasdk76/module/fr/makefile
Normal file
57
idasdk76/module/fr/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=fr
|
||||
CONFIGS=fr.cfg
|
||||
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
ana.cpp fr.hpp ins.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
emu.cpp fr.hpp ins.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
fr.hpp ins.cpp ins.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
fr.hpp ins.hpp out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp \
|
||||
$(I)entry.hpp $(I)fpro.h $(I)frame.hpp $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp fr.hpp ins.hpp reg.cpp
|
||||
298
idasdk76/module/fr/out.cpp
Normal file
298
idasdk76/module/fr/out.cpp
Normal file
@@ -0,0 +1,298 @@
|
||||
|
||||
#include "fr.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_fr_t : public outctx_t
|
||||
{
|
||||
out_fr_t(void) = delete; // not used
|
||||
public:
|
||||
void out_reg(ushort reg) { out_register(ph.reg_names[reg]); }
|
||||
void out_reg(const op_t &op) { out_reg(op.reg); }
|
||||
void out_imm(const op_t &op, bool no_sharp = false);
|
||||
void out_addr(const op_t &op);
|
||||
void out_reglist(const op_t &op);
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
private:
|
||||
void out_reg_if_bit(ushort reg, uval_t value, int bit);
|
||||
};
|
||||
CASSERT(sizeof(out_fr_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_fr_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Output an operand as an immediate value
|
||||
void out_fr_t::out_imm(const op_t &op, bool no_sharp)
|
||||
{
|
||||
if ( !no_sharp )
|
||||
out_symbol('#');
|
||||
out_value(op, OOFW_IMM);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Output an operand as an address
|
||||
void out_fr_t::out_addr(const op_t &op)
|
||||
{
|
||||
if ( !out_name_expr(op, to_ea(insn.cs, op.addr), op.addr) )
|
||||
out_value(op, OOF_ADDR | OOFS_NOSIGN | OOFW_32);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_fr_t::out_reg_if_bit(ushort reg, uval_t value, int bit)
|
||||
{
|
||||
fr_t &pm = *static_cast<fr_t *>(procmod);
|
||||
if ( (value & bit) == bit )
|
||||
{
|
||||
if ( pm.print_comma )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
}
|
||||
out_reg(reg);
|
||||
pm.print_comma = true;
|
||||
}
|
||||
}
|
||||
|
||||
void out_fr_t::out_reglist(const op_t &op)
|
||||
{
|
||||
static const uint16 regs_ldm0[] = { rR7, rR6, rR5, rR4, rR3, rR2, rR1, rR0 };
|
||||
static const uint16 regs_stm0[] = { rR0, rR1, rR2, rR3, rR4, rR5, rR6, rR7 };
|
||||
static const uint16 regs_ldm1[] = { rR15, rR14, rR13, rR12, rR11, rR10, rR9, rR8 };
|
||||
static const uint16 regs_stm1[] = { rR8, rR9, rR10, rR11, rR12, rR13, rR14, rR15 };
|
||||
fr_t &pm = *static_cast<fr_t *>(procmod);
|
||||
const uint16 *regs;
|
||||
bool left;
|
||||
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case fr_ldm0: regs = regs_ldm0; left = false; break;
|
||||
case fr_stm0: regs = regs_stm0; left = true; break;
|
||||
case fr_ldm1: regs = regs_ldm1; left = false; break;
|
||||
case fr_stm1: regs = regs_stm1; left = true; break;
|
||||
default:
|
||||
INTERR(10018);
|
||||
}
|
||||
|
||||
pm.print_comma = false;
|
||||
|
||||
out_symbol('(');
|
||||
if ( left ) //-V614 uninitialized variable 'left'
|
||||
{
|
||||
for ( int i = 0, bit = 128; bit != 0; bit >>= 1, i++ )
|
||||
out_reg_if_bit(regs[i], op.value, bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 7, bit = 1; bit <= 128; bit <<= 1, i-- )
|
||||
out_reg_if_bit(regs[i], op.value, bit);
|
||||
}
|
||||
out_symbol(')');
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Generate disassembly header
|
||||
void fr_t::fr_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Generate disassembly footer
|
||||
void fr_t::fr_footer(outctx_t &ctx) const
|
||||
{
|
||||
if ( ash.end != NULL )
|
||||
{
|
||||
ctx.gen_empty_line();
|
||||
ctx.out_line(ash.end, COLOR_ASMDIR);
|
||||
qstring name;
|
||||
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
||||
{
|
||||
ctx.out_char(' ');
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Generate a segment header
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void fr_t::fr_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
qstring sname;
|
||||
if ( get_visible_segm_name(&sname, Sarea) <= 0 )
|
||||
return;
|
||||
|
||||
const char *segname = sname.c_str();
|
||||
if ( *segname == '_' )
|
||||
segname++;
|
||||
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".section .%s", SCOLOR_ASMDIR), segname);
|
||||
|
||||
ea_t orgbase = ctx.insn_ea - get_segm_para(Sarea);
|
||||
|
||||
if ( orgbase != 0 )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
btoa(buf, sizeof(buf), orgbase);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Output an operand.
|
||||
bool out_fr_t::out_operand(const op_t & op)
|
||||
{
|
||||
fr_t &pm = *static_cast<fr_t *>(procmod);
|
||||
switch ( op.type )
|
||||
{
|
||||
case o_near:
|
||||
case o_mem:
|
||||
out_addr(op);
|
||||
break;
|
||||
|
||||
// immediate value
|
||||
case o_imm:
|
||||
{
|
||||
const ioport_t *port = pm.find_sym(op.value);
|
||||
|
||||
// this immediate is represented in the .cfg file
|
||||
// output the port name instead of the numeric value
|
||||
if ( port != NULL )
|
||||
out_line(port->name.c_str(), COLOR_IMPNAME);
|
||||
else // otherwise, simply print the value
|
||||
out_imm(op);
|
||||
}
|
||||
break;
|
||||
|
||||
// register
|
||||
case o_reg:
|
||||
out_reg(op);
|
||||
break;
|
||||
|
||||
// phrase
|
||||
case o_phrase:
|
||||
out_symbol('@');
|
||||
switch ( op.specflag2 )
|
||||
{
|
||||
case fIGR: // indirect general register
|
||||
out_reg(op);
|
||||
break;
|
||||
|
||||
case fIRA: // indirect relative address
|
||||
out_value(op, OOF_ADDR | OOFS_NOSIGN | OOFW_32);
|
||||
break;
|
||||
|
||||
case fIGRP: // indirect general register with post-increment
|
||||
out_reg(op);
|
||||
out_symbol('+');
|
||||
break;
|
||||
|
||||
case fIGRM: // indirect general register with pre-decrement
|
||||
out_symbol('-');
|
||||
out_reg(op);
|
||||
break;
|
||||
|
||||
case fR13RI: // indirect displacement between R13 and a general register
|
||||
out_symbol('(');
|
||||
out_reg(rR13);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_reg(op);
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10019);
|
||||
}
|
||||
break;
|
||||
|
||||
// displacement
|
||||
case o_displ:
|
||||
out_symbol('@');
|
||||
out_symbol('(');
|
||||
|
||||
// @(R14, #i)
|
||||
if ( op_displ_imm_r14(op) )
|
||||
{
|
||||
out_reg(rR14);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_imm(op, true);
|
||||
}
|
||||
// @(R15, #i)
|
||||
else if ( op_displ_imm_r15(op) )
|
||||
{
|
||||
out_reg(rR15);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_imm(op, true);
|
||||
}
|
||||
else
|
||||
INTERR(10020);
|
||||
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
// reglist
|
||||
case o_reglist:
|
||||
out_reglist(op);
|
||||
break;
|
||||
|
||||
// void operand
|
||||
case o_void:
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10021);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void out_fr_t::out_proc_mnem(void)
|
||||
{
|
||||
char postfix[5];
|
||||
postfix[0] = '\0';
|
||||
|
||||
if ( insn.auxpref & INSN_DELAY_SHOT )
|
||||
qstrncpy(postfix, ":D", sizeof(postfix));
|
||||
out_mnem(8, postfix);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Output an instruction
|
||||
void out_fr_t::out_insn(void)
|
||||
{
|
||||
|
||||
//
|
||||
// print insn mnemonic
|
||||
//
|
||||
out_mnemonic();
|
||||
|
||||
for ( int i=0; i < 4; i++ )
|
||||
{
|
||||
if ( insn.ops[i].type != o_void )
|
||||
{
|
||||
if ( i != 0 )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
}
|
||||
out_one_operand(i);
|
||||
}
|
||||
}
|
||||
|
||||
// output a character representation of the immediate values
|
||||
// embedded in the instruction as comments
|
||||
out_immchar_cmts();
|
||||
flush_outbuf();
|
||||
}
|
||||
439
idasdk76/module/fr/reg.cpp
Normal file
439
idasdk76/module/fr/reg.cpp
Normal file
@@ -0,0 +1,439 @@
|
||||
#include "fr.hpp"
|
||||
#include <segregs.hpp>
|
||||
int data_id;
|
||||
|
||||
// FR registers names
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
// general purpose registers :
|
||||
|
||||
"r0",
|
||||
"r1",
|
||||
"r2",
|
||||
"r3",
|
||||
"r4",
|
||||
"r5",
|
||||
"r6",
|
||||
"r7",
|
||||
"r8",
|
||||
"r9",
|
||||
"r10",
|
||||
"r11",
|
||||
"r12",
|
||||
"r13",
|
||||
"r14",
|
||||
"r15",
|
||||
|
||||
// coprocessor registers :
|
||||
|
||||
"cr0",
|
||||
"cr1",
|
||||
"cr2",
|
||||
"cr3",
|
||||
"cr4",
|
||||
"cr5",
|
||||
"cr6",
|
||||
"cr7",
|
||||
"cr8",
|
||||
"cr9",
|
||||
"cr10",
|
||||
"cr11",
|
||||
"cr12",
|
||||
"cr13",
|
||||
"cr14",
|
||||
"cr15",
|
||||
|
||||
// dedicated registers :
|
||||
|
||||
"pc", // program counter
|
||||
"ps", // program status
|
||||
"tbr", // table base register
|
||||
"rp", // return pointer
|
||||
"ssp", // system stack pointer
|
||||
"usp", // user stack pointer
|
||||
"mdl", // multiplication/division register (LOW)
|
||||
"mdh", // multiplication/division register (HIGH)
|
||||
|
||||
// system use dedicated registers
|
||||
"reserved6",
|
||||
"reserved7",
|
||||
"reserved8",
|
||||
"reserved9",
|
||||
"reserved10",
|
||||
"reserved11",
|
||||
"reserved12",
|
||||
"reserved13",
|
||||
"reserved14",
|
||||
"reserved15",
|
||||
|
||||
// these 2 registers are required by the IDA kernel :
|
||||
|
||||
"cs",
|
||||
"ds"
|
||||
};
|
||||
|
||||
int fr_t::choose_device()
|
||||
{
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
if ( choose_ioport_device(&ioh.device, cfgfile) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns a pointer to a ioport_t object if address was found in the config file.
|
||||
// otherwise, returns NULL.
|
||||
const ioport_t *fr_t::find_sym(ea_t address)
|
||||
{
|
||||
return find_ioport(ioh.ports, address);
|
||||
}
|
||||
|
||||
const char *fr_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/)
|
||||
{
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
|
||||
char cfgfile[QMAXFILE];
|
||||
ioh.get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
if ( !choose_ioport_device(&ioh.device, cfgfile)
|
||||
&& ioh.device == NONEPROC )
|
||||
{
|
||||
warning("No devices are defined in the configuration file %s", cfgfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_NONE);
|
||||
}
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void fr_t::load_from_idb()
|
||||
{
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// This old-style callback only returns the processor module object.
|
||||
static ssize_t idaapi notify(void *, int msgid, va_list)
|
||||
{
|
||||
if ( msgid == processor_t::ev_get_procmod )
|
||||
return size_t(SET_MODULE_DATA(fr_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t idaapi fr_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
inf_set_be(true);
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
choose_device();
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_mnem(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
fr_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
fr_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 *);
|
||||
fr_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return emu(*insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_insn:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_insn(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_operand:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return out_opnd(*ctx, *op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_sp_based:
|
||||
{
|
||||
int *mode = va_arg(va, int *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
*mode = is_sp_based(*insn, *op);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
create_func_frame(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_align_insn:
|
||||
{
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
return is_align_insn(ea);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// GNU assembler for fujitsu FR
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// gets a function's name
|
||||
//lint -e{818} could be declared const
|
||||
static bool fr_get_func_name(qstring *name, func_t *pfn)
|
||||
{
|
||||
ea_t ea = pfn->start_ea;
|
||||
if ( get_demangled_name(name, ea, inf_get_long_demnames(), DEMNAM_NAME) <= 0 )
|
||||
return false;
|
||||
|
||||
tag_addr(name, ea, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// prints function header
|
||||
static void idaapi gnu_func_header(outctx_t &ctx, func_t *pfn)
|
||||
{
|
||||
ctx.gen_func_header(pfn);
|
||||
|
||||
qstring namebuf;
|
||||
if ( fr_get_func_name(&namebuf, pfn) )
|
||||
{
|
||||
const char *name = namebuf.begin();
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".type %s, @function", SCOLOR_ASMDIR), name);
|
||||
ctx.gen_printf(0, COLSTR("%s:", SCOLOR_ASMDIR), name);
|
||||
ctx.ctxflags |= CTXF_LABEL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// prints function footer
|
||||
static void idaapi gnu_func_footer(outctx_t &ctx, func_t *pfn)
|
||||
{
|
||||
qstring namebuf;
|
||||
if ( fr_get_func_name(&namebuf, pfn) )
|
||||
{
|
||||
const char *name = namebuf.begin();
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".size %s, .-%s", SCOLOR_ASMDIR), name, name);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t gnu_asm =
|
||||
{
|
||||
AS_COLON
|
||||
|ASH_HEXF3 // hex 0x123 format
|
||||
|ASB_BINF0 // bin 0110b format
|
||||
|ASO_OCTF1 // oct 012345 format
|
||||
// don't display the final 0 in string declarations
|
||||
|/*AS_1TEXT |*/ AS_NCMAS,
|
||||
0,
|
||||
"GNU Assembler for the Fujitsu FR Family",
|
||||
0,
|
||||
NULL, // no headers
|
||||
".org", // origin directive
|
||||
NULL, // end directive
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
".ascii", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".word", // word directive
|
||||
".long", // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
".float", // float (4 bytes)
|
||||
".double", // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
"dfs %s", // uninited arrays
|
||||
"equ", // Equ
|
||||
NULL, // seg prefix
|
||||
"$", // current IP (instruction pointer) symbol in assembler
|
||||
gnu_func_header, // func_header
|
||||
gnu_func_footer, // func_footer
|
||||
".globl", // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
".align", // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"!", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
0, // flag2 ???
|
||||
NULL, // comment close string
|
||||
NULL, // low8 op
|
||||
NULL, // high8 op
|
||||
NULL, // low16 op
|
||||
NULL // high16 op
|
||||
};
|
||||
|
||||
//
|
||||
// Supported assemblers :
|
||||
//
|
||||
|
||||
static const asm_t *const asms[] = { &gnu_asm, NULL };
|
||||
|
||||
//
|
||||
// Short and long name for our module
|
||||
//
|
||||
#define FAMILY "Fujitsu FR 32-Bit Family:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"fr",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Fujitsu FR 32-Bit Family",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const uchar retcode_1[] = { 0x97, 0x20 }; // ret
|
||||
static const uchar retcode_2[] = { 0x9F, 0x20 }; // ret with delay shot
|
||||
static const uchar retcode_3[] = { 0x9F, 0x30 }; // reti
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ sizeof(retcode_3), retcode_3 },
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_FR, // id
|
||||
// flag
|
||||
PR_RNAMESOK // can use register names for byte names
|
||||
| PR_USE32 // supports 32-bit addressing
|
||||
| PR_DEFSEG32 // segments are 32-bit by default
|
||||
| PR_BINMEM, // The module creates RAM/ROM segments for binary files
|
||||
// (the kernel shouldn't ask the user about their sizes and addresses)
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // array of short processor names
|
||||
// the short names are used to specify the processor
|
||||
// with the -p command line switch)
|
||||
lnames, // array of long processor names
|
||||
// the long names are used to build the processor type
|
||||
// selection menu
|
||||
|
||||
asms, // array of target assemblers
|
||||
|
||||
notify, // the kernel event notification callback
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs, rVds,
|
||||
0, // size of a segment register
|
||||
rVcs, rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0, fr_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, 7, 15, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
fr_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
Reference in New Issue
Block a user