update to ida 7.6, add builds
This commit is contained in:
879
idasdk76/module/m32r/ana.cpp
Normal file
879
idasdk76/module/m32r/ana.cpp
Normal file
@@ -0,0 +1,879 @@
|
||||
|
||||
#include "m32r.hpp"
|
||||
|
||||
struct opcode
|
||||
{
|
||||
int instruction; // instruction name
|
||||
|
||||
// flags for opcode_flags
|
||||
#define OC_1 0x00000001 // first 4 bits, 0xF000
|
||||
#define OC_2 0x00000002 // second 4 bits, 0x0F00
|
||||
#define OC_3 0x00000004 // third 4 bits, 0x00F0
|
||||
#define OC_4 0x00000008 // last 4 bits, 0x000F
|
||||
|
||||
int opcode_flags; // flags to situate the operation code (example OC_1|OC_3 : first and third operands)
|
||||
int opcode_value; // value for the operation code
|
||||
|
||||
// flags for op[1-3].flags
|
||||
|
||||
// operand type
|
||||
#define OP_REG 0x00000001 // operand is register
|
||||
#define OP_IMM 0x00000002 // operand is immediate
|
||||
#define OP_ADDR 0x00000004 // operand is immediate
|
||||
|
||||
// operand size
|
||||
#define OP_S4 0x00000010 // operand is 4 bits long
|
||||
#define OP_S8 0x00000020 // operand is 8 bits long
|
||||
#define OP_S16 0x00000040 // operand is 16 bits long
|
||||
#define OP_S24 0x00000080 // operand is 24 bits long
|
||||
|
||||
// operand offset
|
||||
#define OP_O4 0x00000100 // operand is located at offset 4
|
||||
#define OP_O8 0x00000200 // operand is located at offset 8
|
||||
#define OP_O12 0x00000400 // operand is located at offset 12
|
||||
#define OP_O16 0x00000800 // operand is located at offset 16
|
||||
|
||||
// operand phrase type (optional for non-phrase op)
|
||||
#define OP_PHRASE1 0x00001000 // @R
|
||||
#define OP_PHRASE2 0x00002000 // @R+
|
||||
#define OP_PHRASE4 0x00008000 // @+R
|
||||
#define OP_PHRASE5 0x00010000 // @-R
|
||||
|
||||
// displacement argument
|
||||
#define OP_DISPL_A 0x00004000 // reg in @(imm, reg)
|
||||
#define OP_DISPL_B 0x00100000 // imm in @(imm, reg)
|
||||
|
||||
int op1_flags; // first operand flags, if exists
|
||||
int op2_flags; // second operand flags, if exists
|
||||
int op3_flags; // third operand flags, if exists
|
||||
|
||||
#define op1 op1_flags
|
||||
#define op2 op2_flags
|
||||
#define op3 op3_flags
|
||||
};
|
||||
|
||||
static const opcode opcodes[] =
|
||||
{
|
||||
{ m32r_add, OC_1|OC_3, 0x000A, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_add3, OC_1|OC_3, 0x008A, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
{ m32r_addi, OC_1, 0x0004, OP_REG|OP_S4|OP_O4, OP_IMM|OP_S8|OP_O8, 0 },
|
||||
{ m32r_addv, OC_1|OC_3, 0x0008, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_addv3, OC_1|OC_3, 0x0088, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
{ m32r_addx, OC_1|OC_3, 0x0009, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_and, OC_1|OC_3, 0x000C, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_and3, OC_1|OC_3, 0x008C, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
{ m32r_bc, OC_1|OC_2, 0x007C, OP_ADDR|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32r_bc, OC_1|OC_2, 0x00FC, OP_ADDR|OP_S24|OP_O8, 0, 0 },
|
||||
{ m32r_beq, OC_1|OC_3, 0x00B0, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16 },
|
||||
{ m32r_beqz, OC_1|OC_2|OC_3, 0x0B08, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16, 0 },
|
||||
{ m32r_bgez, OC_1|OC_2|OC_3, 0x0B0B, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16, 0 },
|
||||
{ m32r_bgtz, OC_1|OC_2|OC_3, 0x0B0D, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16, 0 },
|
||||
{ m32r_bl, OC_1|OC_2, 0x007E, OP_ADDR|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32r_bl, OC_1|OC_2, 0x00FE, OP_ADDR|OP_S24|OP_O8, 0, 0 },
|
||||
{ m32r_blez, OC_1|OC_2|OC_3, 0x0B0C, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16, 0 },
|
||||
{ m32r_bltz, OC_1|OC_2|OC_3, 0x0B0A, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16, 0 },
|
||||
{ m32r_bnc, OC_1|OC_2, 0x007D, OP_ADDR|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32r_bnc, OC_1|OC_2, 0x00FD, OP_ADDR|OP_S24|OP_O8, 0, 0 },
|
||||
{ m32r_bne, OC_1|OC_3, 0x00B1, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16 },
|
||||
{ m32r_bnez, OC_1|OC_2|OC_3, 0x0B09, OP_REG|OP_S4|OP_O12, OP_ADDR|OP_S16|OP_O16, 0 },
|
||||
{ m32r_bra, OC_1|OC_2, 0x007F, OP_ADDR|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32r_bra, OC_1|OC_2, 0x00FF, OP_ADDR|OP_S24|OP_O8, 0, 0 },
|
||||
{ m32r_cmp, OC_1|OC_3, 0x0004, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_cmpi, OC_1|OC_2|OC_3, 0x0804, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16, 0 },
|
||||
{ m32r_cmpu, OC_1|OC_3, 0x0005, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_cmpui, OC_1|OC_2|OC_3, 0x0805, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16, 0 },
|
||||
{ m32r_div, OC_1|OC_3, 0x0090, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_divu, OC_1|OC_3, 0x0091, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_jl, OC_1|OC_2|OC_3, 0x01EC, OP_REG|OP_S4|OP_O12, 0, 0 },
|
||||
{ m32r_jmp, OC_1|OC_2|OC_3, 0x01FC, OP_REG|OP_S4|OP_O12, 0, 0 },
|
||||
{ m32r_ld, OC_1|OC_3, 0x002C, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_ld, OC_1|OC_3, 0x002E, OP_REG|OP_S4|OP_O4, OP_PHRASE2|OP_S4|OP_O12, 0 },
|
||||
{ m32r_ld, OC_1|OC_3, 0x00AC, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_ld24, OC_1, 0x000E, OP_REG|OP_S4|OP_O4, OP_IMM|OP_S24|OP_O8, 0 },
|
||||
{ m32r_ldb, OC_1|OC_3, 0x0028, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_ldb, OC_1|OC_3, 0x00A8, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_ldh, OC_1|OC_3, 0x002A, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_ldh, OC_1|OC_3, 0x00AA, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_ldi, OC_1, 0x0006, OP_REG|OP_S4|OP_O4, OP_IMM|OP_S8|OP_O8, 0 },
|
||||
{ m32r_ldi, OC_1|OC_3|OC_4, 0x09F0, OP_REG|OP_S4|OP_O4, OP_IMM|OP_S16|OP_O16, 0 },
|
||||
{ m32r_ldub, OC_1|OC_3, 0x0029, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_ldub, OC_1|OC_3, 0x00A9, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_lduh, OC_1|OC_3, 0x002B, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_lduh, OC_1|OC_3, 0x00AB, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_lock, OC_1|OC_3, 0x002D, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_machi, OC_1|OC_3, 0x0034, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_maclo, OC_1|OC_3, 0x0035, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_macwhi, OC_1|OC_3, 0x0036, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_macwlo, OC_1|OC_3, 0x0037, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mul, OC_1|OC_3, 0x0016, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mulhi, OC_1|OC_3, 0x0030, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mullo, OC_1|OC_3, 0x0031, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mulwhi, OC_1|OC_3, 0x0032, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mulwlo, OC_1|OC_3, 0x0033, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mv, OC_1|OC_3, 0x0018, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mvfachi, OC_1|OC_3|OC_4, 0x05F0, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32r_mvfaclo, OC_1|OC_3|OC_4, 0x05F1, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32r_mvfacmi, OC_1|OC_3|OC_4, 0x05F2, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32r_mvfc, OC_1|OC_3, 0x0019, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_mvtachi, OC_1|OC_3|OC_4, 0x0570, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32r_mvtaclo, OC_1|OC_3|OC_4, 0x0571, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32r_mvtc, OC_1|OC_3, 0x001A, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_neg, OC_1|OC_3, 0x0003, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_nop, OC_1|OC_2|OC_3|OC_4, 0x7000, 0, 0, 0 },
|
||||
{ m32r_not, OC_1|OC_3, 0x000B, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_or, OC_1|OC_3, 0x000E, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_or3, OC_1|OC_3, 0x008E, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
{ m32r_rac, OC_1|OC_2|OC_3|OC_4, 0x5090, 0, 0, 0 },
|
||||
{ m32r_rach, OC_1|OC_2|OC_3|OC_4, 0x5080, 0, 0, 0 },
|
||||
{ m32r_rem, OC_1|OC_3, 0x0092, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_remu, OC_1|OC_3, 0x0093, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_rte, OC_1|OC_2|OC_3|OC_4, 0x10D6, 0, 0, 0 },
|
||||
{ m32r_seth, OC_1|OC_3|OC_4, 0x0DC0, OP_REG|OP_S4|OP_O4, OP_IMM|OP_S16|OP_O16, 0 },
|
||||
{ m32r_sll, OC_1|OC_3, 0x0014, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_sll3, OC_1|OC_3, 0x009C, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
{ m32r_sra, OC_1|OC_3, 0x0012, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_sra3, OC_1|OC_3, 0x009A, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
#if 0
|
||||
{ m32r_srai, OC_1|OC_3, 0x0051 }, // Shirt right arithmetic immediate
|
||||
{ m32r_slli, OC_1|OC_3, 0x0082 }, // Shift left logical immediate
|
||||
{ m32r_srli, OC_1|OC_3, 0x0050 }, // Shift right logical immediate
|
||||
#endif
|
||||
{ m32r_srl, OC_1|OC_3, 0x0010, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_srl3, OC_1|OC_3, 0x0098, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
{ m32r_st, OC_1|OC_3, 0x0024, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_st, OC_1|OC_3, 0x0026, OP_REG|OP_S4|OP_O4, OP_PHRASE4|OP_S4|OP_O12, 0 },
|
||||
{ m32r_st, OC_1|OC_3, 0x0027, OP_REG|OP_S4|OP_O4, OP_PHRASE5|OP_S4|OP_O12, 0 },
|
||||
{ m32r_st, OC_1|OC_3, 0x00A4, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_stb, OC_1|OC_3, 0x0020, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_stb, OC_1|OC_3, 0x00A0, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_sth, OC_1|OC_3, 0x0022, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_sth, OC_1|OC_3, 0x0023, OP_REG|OP_S4|OP_O4, OP_PHRASE2|OP_S4|OP_O12, 0 }, // guessed, see mail from David.Ward@ecutek.com
|
||||
{ m32r_sth, OC_1|OC_3, 0x00A2, OP_REG|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_sub, OC_1|OC_3, 0x0002, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_subv, OC_1|OC_3, 0x0000, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_subx, OC_1|OC_3, 0x0001, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_trap, OC_1|OC_2|OC_3, 0x010F, OP_IMM|OP_S4|OP_O12, 0, 0 },
|
||||
{ m32r_unlock, OC_1|OC_3, 0x0025, OP_REG|OP_S4|OP_O4, OP_PHRASE1|OP_S4|OP_O12, 0 },
|
||||
{ m32r_xor, OC_1|OC_3, 0x000D, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32r_xor3, OC_1|OC_3, 0x008D, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, OP_IMM|OP_S16|OP_O16 },
|
||||
|
||||
{ m32r_setpsw, OC_1|OC_2, 0x0071, OP_IMM|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32r_clrpsw, OC_1|OC_2, 0x0072, OP_IMM|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32r_bset, OC_1|OC_3, 0x00A6, OP_IMM|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_bclr, OC_1|OC_3, 0x00A7, OP_IMM|OP_S4|OP_O4, OP_DISPL_A|OP_S4|OP_O12, OP_DISPL_B|OP_S16|OP_O16 },
|
||||
{ m32r_btst, OC_1|OC_3, 0x000F, OP_IMM|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
};
|
||||
|
||||
// M32RX additional opcodes :
|
||||
static const opcode ext_opcodes[] =
|
||||
{
|
||||
{ m32rx_bcl, OC_1|OC_2, 0x0078, OP_ADDR|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32rx_bcl, OC_1|OC_2, 0x00F8, OP_ADDR|OP_S24|OP_O8, 0, 0 },
|
||||
{ m32rx_bncl, OC_1|OC_2, 0x0079, OP_ADDR|OP_S8|OP_O8, 0, 0 },
|
||||
{ m32rx_bncl, OC_1|OC_2, 0x00F9, OP_ADDR|OP_S24|OP_O8, 0, 0 },
|
||||
{ m32rx_cmpeq, OC_1|OC_3, 0x0006, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_cmpz, OC_1|OC_2|OC_3, 0x0007, OP_REG|OP_S4|OP_O12, 0, 0 },
|
||||
{ m32rx_mulwu1, OC_1|OC_3, 0x005A, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_macwu1, OC_1|OC_3, 0x005B, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_maclh1, OC_1|OC_3, 0x005C, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_msblo, OC_1|OC_3, 0x005D, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_sadd, OC_1|OC_2|OC_3|OC_4, 0x50E4, 0, 0, 0 },
|
||||
{ m32rx_sat, OC_1|OC_3, 0x0086, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
#if 0
|
||||
{ m32rx_divh, OC_1|OC_3, 0x0090, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
#endif
|
||||
{ m32rx_mulhi, OC_1|OC_3, 0x0038, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_mullo, OC_1|OC_3, 0x0039, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_machi, OC_1|OC_3, 0x003C, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_maclo, OC_1|OC_3, 0x003D, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_mvfachi, OC_1|OC_3|OC_4, 0x05F4, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32rx_mvfaclo, OC_1|OC_3|OC_4, 0x05F5, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32rx_mvfacmi, OC_1|OC_3|OC_4, 0x05F6, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32rx_mvtachi, OC_1|OC_3|OC_4, 0x0574, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32rx_mvtaclo, OC_1|OC_3|OC_4, 0x0575, OP_REG|OP_S4|OP_O4, 0, 0 },
|
||||
{ m32rx_sc, OC_1|OC_2|OC_3|OC_4, 0x7401, 0, 0, 0 },
|
||||
{ m32rx_snc, OC_1|OC_2|OC_3|OC_4, 0x7501, 0, 0, 0 },
|
||||
{ m32rx_jc, OC_1|OC_2|OC_3, 0x01CC, OP_REG|OP_S4|OP_O12, 0, 0 },
|
||||
{ m32rx_jnc, OC_1|OC_2|OC_3, 0x01DC, OP_REG|OP_S4|OP_O12, 0, 0 },
|
||||
{ m32rx_mulwhi, OC_1|OC_3, 0x003A, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_mulwlo, OC_1|OC_3, 0x003B, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_macwhi, OC_1|OC_3, 0x003E, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_macwlo, OC_1|OC_3, 0x003F, OP_REG|OP_S4|OP_O4, OP_REG|OP_S4|OP_O12, 0 },
|
||||
{ m32rx_pcmpbz, OC_1|OC_2|OC_3, 0x0037, OP_REG|OP_S4|OP_O12, 0, 0 }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// get size of this operand (in bits)
|
||||
static int get_size(int op)
|
||||
{
|
||||
if ( op & OP_S4 )
|
||||
return 4;
|
||||
if ( op & OP_S8 )
|
||||
return 8;
|
||||
if ( op & OP_S16 )
|
||||
return 16;
|
||||
if ( op & OP_S24 )
|
||||
return 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// get size of this instruction (in bits)
|
||||
static int get_insn_size(const opcode *oc)
|
||||
{
|
||||
int s = 0;
|
||||
|
||||
if ( oc->opcode_flags & OC_1 )
|
||||
s += 4;
|
||||
if ( oc->opcode_flags & OC_2 )
|
||||
s += 4;
|
||||
if ( oc->opcode_flags & OC_3 )
|
||||
s += 4;
|
||||
if ( oc->opcode_flags & OC_4 )
|
||||
s += 4;
|
||||
|
||||
if ( oc->op1 != 0 )
|
||||
s += get_size(oc->op1);
|
||||
if ( oc->op2 != 0 )
|
||||
s += get_size(oc->op2);
|
||||
if ( oc->op3 != 0 )
|
||||
s += get_size(oc->op3);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// get value of target operand in target operation code
|
||||
static int get_offset(int word, int word2, int size, int op)
|
||||
{
|
||||
if ( op & OP_O4 )
|
||||
{
|
||||
switch ( size )
|
||||
{
|
||||
case 4: return (word & 0x0F00) >> 8;
|
||||
default: INTERR(10195);
|
||||
}
|
||||
}
|
||||
if ( op & OP_O8 )
|
||||
{
|
||||
switch ( size )
|
||||
{
|
||||
case 4: return (word & 0x00F0) >> 4;
|
||||
case 8: return word & 0x00FF;
|
||||
case 24: return ((word & 0x00FF) << 16) + (word2 & 0xFFFF);
|
||||
default: INTERR(10196);
|
||||
}
|
||||
}
|
||||
if ( op & OP_O12 )
|
||||
{
|
||||
switch ( size )
|
||||
{
|
||||
case 4: return word & 0x000F;
|
||||
default: INTERR(10197);
|
||||
}
|
||||
}
|
||||
if ( op & OP_O16 )
|
||||
{
|
||||
switch ( size )
|
||||
{
|
||||
case 16: return word2 & 0xFFFF;
|
||||
default: INTERR(10198);
|
||||
}
|
||||
}
|
||||
|
||||
INTERR(10199);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// return the corresponding dt_xxx element for a specified size (in bits)
|
||||
static inline uchar bits2dt(int size)
|
||||
{
|
||||
switch ( size )
|
||||
{
|
||||
case 4: return dt_byte;
|
||||
case 8: return dt_byte;
|
||||
case 16: return dt_word;
|
||||
case 24: return dt_dword;
|
||||
}
|
||||
|
||||
INTERR(10200);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// swap 2 opcodes (o1 <=> o2)
|
||||
static inline void swap_op(op_t &o1, op_t &o2)
|
||||
{
|
||||
op_t tmp = o1;
|
||||
o1 = o2;
|
||||
o2 = tmp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// convert a general-purpose register to a control register
|
||||
static uint16 r2cr(int reg)
|
||||
{
|
||||
switch ( reg )
|
||||
{
|
||||
case rR0: return rCR0;
|
||||
case rR1: return rCR1;
|
||||
case rR2: return rCR2;
|
||||
case rR3: return rCR3;
|
||||
case rR6: return rCR6;
|
||||
case rR7: return rCR7;
|
||||
}
|
||||
return ushort(-1);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// initialize a register operand
|
||||
inline void set_reg(op_t &op, uint16 reg)
|
||||
{
|
||||
op.type = o_reg;
|
||||
op.reg = reg;
|
||||
// all m32r registers are 32 bits long
|
||||
op.dtype = dt_word;
|
||||
}
|
||||
|
||||
#define sign_extend(x) ( ( ( signed ) ( (x) << 8 ) ) >> 8 )
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// fill a target insn-operand structure with fresh data
|
||||
static void set_arg(const insn_t &insn, int word, int word2, op_t &op, int oc)
|
||||
{
|
||||
int size = get_size(oc);
|
||||
int val = get_offset(word, word2, size, oc);
|
||||
|
||||
if ( oc & OP_REG )
|
||||
{
|
||||
set_reg(op, (uint16)val);
|
||||
}
|
||||
else if ( oc & OP_IMM )
|
||||
{
|
||||
op.type = o_imm;
|
||||
switch ( size )
|
||||
{
|
||||
case 4:
|
||||
case 8:
|
||||
op.value = (signed char) val;
|
||||
break;
|
||||
case 16:
|
||||
op.value = (signed short) val;
|
||||
break;
|
||||
case 24:
|
||||
op.value = val & 0x00ffffff;
|
||||
break;
|
||||
default:
|
||||
INTERR(10201);
|
||||
}
|
||||
op.dtype = bits2dt(size);
|
||||
}
|
||||
else if ( oc & OP_ADDR )
|
||||
{
|
||||
op.type = o_near;
|
||||
switch ( size )
|
||||
{
|
||||
case 8:
|
||||
op.addr = (signed char) val;
|
||||
break;
|
||||
case 16:
|
||||
op.addr = (signed short) val;
|
||||
break;
|
||||
case 24:
|
||||
op.addr = sign_extend(val);
|
||||
break;
|
||||
default:
|
||||
INTERR(10202);
|
||||
}
|
||||
op.addr <<= 2;
|
||||
op.addr += insn.ip & 0xfffffffc;
|
||||
op.dtype = dt_code;
|
||||
}
|
||||
else if ( oc & OP_PHRASE1 ) // @R
|
||||
{
|
||||
op.type = o_phrase;
|
||||
op.specflag1 = fRI;
|
||||
op.reg = uint16(val);
|
||||
}
|
||||
else if ( oc & OP_PHRASE2 ) // @R+
|
||||
{
|
||||
op.type = o_phrase;
|
||||
op.specflag1 = fRIBA;
|
||||
op.reg = uint16(val);
|
||||
}
|
||||
else if ( oc & OP_DISPL_A ) // reg in @(imm, reg )
|
||||
{
|
||||
op.type = o_displ;
|
||||
op.reg = uint16(val);
|
||||
}
|
||||
else if ( oc & OP_DISPL_B ) // imm in @(imm, reg )
|
||||
{
|
||||
op.type = o_displ;
|
||||
op.addr = (signed short) val;
|
||||
}
|
||||
else if ( oc & OP_PHRASE4 ) // @+R
|
||||
{
|
||||
op.type = o_phrase;
|
||||
op.specflag1 = fRIAA;
|
||||
op.reg = uint16(val);
|
||||
}
|
||||
else if ( oc & OP_PHRASE5 ) // @-R
|
||||
{
|
||||
op.type = o_phrase;
|
||||
op.specflag1 = fRIAS;
|
||||
op.reg = uint16(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
INTERR(10203);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static int get_code(const opcode *op, int word)
|
||||
{
|
||||
int code = 0;
|
||||
|
||||
if ( op->opcode_flags & OC_1 )
|
||||
code = (code << 4) + ((word & 0xF000) >> 12);
|
||||
if ( op->opcode_flags & OC_2 )
|
||||
code = (code << 4) + ((word & 0x0F00) >> 8);
|
||||
if ( op->opcode_flags & OC_3 )
|
||||
code = (code << 4) + ((word & 0x00F0) >> 4);
|
||||
if ( op->opcode_flags & OC_4 )
|
||||
code = (code << 4) + ((word & 0x000F) >> 0);
|
||||
return code;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// from the first picked word, scan the opcode table and return the corresponding entry (if exists)
|
||||
const opcode *m32r_t::get_opcode(int word) const
|
||||
{
|
||||
for ( int i = 0; i < qnumber(opcodes); i++ )
|
||||
if ( opcodes[i].opcode_value == get_code(&opcodes[i], word) )
|
||||
return &opcodes[i];
|
||||
|
||||
if ( ptype == prc_m32rx )
|
||||
{
|
||||
for ( int i = 0; i < qnumber(ext_opcodes); i++ )
|
||||
{
|
||||
if ( ext_opcodes[i].opcode_value == get_code(&ext_opcodes[i], word) )
|
||||
return &ext_opcodes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// analyze a special instruction
|
||||
bool m32r_t::ana_special(insn_t &insn, int word, int *s) const
|
||||
{
|
||||
bool special = false;
|
||||
|
||||
// srli, srai, and slli are 3 special instructions, with this kind of opcode format :
|
||||
// 0101 dest 000 imm5 (SRLI)
|
||||
// 0101 dest 001 imm5 (SRAI)
|
||||
// 0101 dest 010 imm5 (SLLI)
|
||||
if ( ((word & 0xF000) >> 12) == 5 )
|
||||
{
|
||||
int imm5 = word & 0x1F;
|
||||
uint16 reg = (word & 0x0F00) >> 8;
|
||||
switch ( (word & /*0x0070*/ 0x00F0) >> 5 )
|
||||
{
|
||||
case 0:
|
||||
special = true;
|
||||
insn.itype = m32r_srli;
|
||||
break;
|
||||
case 1:
|
||||
special = true;
|
||||
insn.itype = m32r_srai;
|
||||
break;
|
||||
case 2:
|
||||
special = true;
|
||||
insn.itype = m32r_slli;
|
||||
break;
|
||||
}
|
||||
if ( special )
|
||||
{
|
||||
insn.Op1.type = o_reg;
|
||||
insn.Op1.reg = reg;
|
||||
insn.Op2.type = o_imm;
|
||||
insn.Op2.value = imm5;
|
||||
*s = 16;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// detect m32rx rac/rach instructions
|
||||
if ( ptype == prc_m32rx )
|
||||
{
|
||||
int v = (word & 0x00F0) >> 4;
|
||||
uint16 itype = (v == 9 ? m32rx_rac : v == 8 ? m32rx_rach : -1);
|
||||
|
||||
if ( itype == uint16(-1) )
|
||||
return false;
|
||||
|
||||
switch ( word & 0xFF0F )
|
||||
{
|
||||
// rac[h] a1
|
||||
case 0x5400:
|
||||
set_reg(insn.Op1, rA1);
|
||||
special = true;
|
||||
break;
|
||||
|
||||
// rac[h] a0, a1
|
||||
case 0x5004:
|
||||
set_reg(insn.Op1, rA0);
|
||||
set_reg(insn.Op2, rA1);
|
||||
special = true;
|
||||
break;
|
||||
|
||||
// rac[h] a1, a1
|
||||
case 0x5404:
|
||||
set_reg(insn.Op1, rA1);
|
||||
set_reg(insn.Op2, rA1);
|
||||
special = true;
|
||||
break;
|
||||
|
||||
// rac[h] a0, a1, #2
|
||||
case 0x5005:
|
||||
set_reg(insn.Op1, rA0);
|
||||
set_reg(insn.Op2, rA1);
|
||||
insn.Op3.type = o_imm;
|
||||
insn.Op3.value = 2;
|
||||
insn.Op3.dtype = dt_byte;
|
||||
special = true;
|
||||
break;
|
||||
|
||||
// rac[h] a1, a0, #2
|
||||
case 0x5401:
|
||||
set_reg(insn.Op1, rA1);
|
||||
set_reg(insn.Op2, rA0);
|
||||
insn.Op3.type = o_imm;
|
||||
insn.Op3.value = 2;
|
||||
insn.Op3.dtype = dt_byte;
|
||||
special = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( special )
|
||||
{
|
||||
insn.itype = itype;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int m32r_t::parse_fp_insn(insn_t &insn, int word)
|
||||
{
|
||||
static const ushort fp_itypes[] =
|
||||
{
|
||||
m32r_fadd, m32r_fmul, m32r_fdiv, m32r_fmadd, // 0
|
||||
m32r_itof, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 1
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 2
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 3
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_fsub, m32r_null, m32r_null, m32r_fmsub, // 4
|
||||
m32r_utof, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 5
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 6
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 7
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 8
|
||||
m32r_ftoi, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // 9
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // A
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // B
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_fcmp, m32r_null, m32r_null, m32r_null, // C
|
||||
m32r_ftos, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_fcmpe,m32r_null, m32r_null, m32r_null, // D
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // E
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null, // F
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
m32r_null, m32r_null, m32r_null, m32r_null,
|
||||
};
|
||||
int word2 = insn.get_next_word();
|
||||
int idx = (word2 & 0x00F0) | (word2 >> 12);
|
||||
if ( idx >= qnumber(fp_itypes) ) //-V547 always false
|
||||
return 0;
|
||||
insn.itype = fp_itypes[idx];
|
||||
if ( insn.itype == m32r_null )
|
||||
return 0;
|
||||
set_reg(insn.Op1, (word2 >> 8) & 0xF);
|
||||
set_reg(insn.Op2, (word >> 8) & 0xF);
|
||||
int f = insn.get_canon_feature(ph);
|
||||
if ( (f & CF_USE3) == 0 )
|
||||
{
|
||||
if ( (word & 0xF) != 0 )
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_reg(insn.Op3, word & 0xF);
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// decode an instruction
|
||||
int m32r_t::ana(insn_t *_insn)
|
||||
{
|
||||
insn_t &insn = *_insn;
|
||||
|
||||
//#define CHECK_OPCODES
|
||||
#ifdef CHECK_OPCODES
|
||||
for ( int i=0; i < qnumber(opcodes); i++ )
|
||||
{
|
||||
int s = get_insn_size(&opcodes[i]);
|
||||
if ( s != 16 && s != 32 )
|
||||
error("wrong opcode template %d", i);
|
||||
}
|
||||
#endif
|
||||
|
||||
int word, word2 = 0, s = 0;
|
||||
|
||||
word = insn.get_next_word();
|
||||
|
||||
// if the MSB if 1 and the current address NOT divisible by 4, then remove the MSB
|
||||
if ( ((word & 0x8000) >> 15) == 1 )
|
||||
{
|
||||
if ( insn.ea % 4 != 0 )
|
||||
{
|
||||
word &= 0x7FFF;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (word & 0xF0F0) == 0xD000 )
|
||||
return parse_fp_insn(insn, word);
|
||||
|
||||
bool special = ana_special(insn, word, &s);
|
||||
|
||||
if ( !special )
|
||||
{
|
||||
// retrieve the corresponding opcode struct entry
|
||||
const opcode *oc = get_opcode(word);
|
||||
if ( oc == NULL )
|
||||
return 0;
|
||||
|
||||
// fill the insn name
|
||||
insn.itype = (uint16)oc->instruction;
|
||||
|
||||
// compute the size of our operation code
|
||||
s = get_insn_size(oc);
|
||||
|
||||
// size must be either 16 or 32 bits long
|
||||
if ( s != 16 && s != 32 )
|
||||
INTERR(10204);
|
||||
|
||||
// 32 bits ? we need to pick an another word
|
||||
if ( s == 32 )
|
||||
word2 = insn.get_next_word();
|
||||
|
||||
// those '16-bit' instructions are always followed by an another word
|
||||
// (which is specified in the array).
|
||||
// this code will check if the next word has the right value, according
|
||||
// to the current instruction.
|
||||
|
||||
struct doubleword_insn_t
|
||||
{
|
||||
uint16 insn;
|
||||
uint16 word;
|
||||
};
|
||||
static const doubleword_insn_t sinsn[] =
|
||||
{
|
||||
{ m32r_div, 0x0000 },
|
||||
{ m32r_divu, 0x0000 },
|
||||
{ m32r_rem, 0x0000 },
|
||||
{ m32r_remu, 0x0000 },
|
||||
{ m32rx_sat, 0x0000 },
|
||||
{ m32rx_satb, 0x0300 },
|
||||
{ m32rx_sath, 0x0200 },
|
||||
{ m32rx_divh, 0x0010 },
|
||||
};
|
||||
|
||||
if ( s == 16 )
|
||||
{
|
||||
for ( int i = 0; i < qnumber(sinsn); i++ )
|
||||
{
|
||||
if ( sinsn[i].insn != insn.itype )
|
||||
continue;
|
||||
|
||||
word2 = get_word(insn.ea + 2);
|
||||
if ( word2 != sinsn[i].word )
|
||||
{
|
||||
// second chance for div
|
||||
if ( insn.itype == m32r_div )
|
||||
{
|
||||
insn.itype = m32rx_divh;
|
||||
continue;
|
||||
}
|
||||
|
||||
// second chance for sat
|
||||
if ( insn.itype == m32rx_sat )
|
||||
{
|
||||
insn.itype = m32rx_satb;
|
||||
continue;
|
||||
}
|
||||
|
||||
// second chance for satb
|
||||
if ( insn.itype == m32rx_satb )
|
||||
{
|
||||
insn.itype = m32rx_sath;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
word2 = insn.get_next_word();
|
||||
s += 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fill the appropriate operands of the insn structure
|
||||
if ( oc->op1 != 0 )
|
||||
set_arg(insn, word, word2, insn.Op1, oc->op1);
|
||||
if ( oc->op2 != 0 )
|
||||
set_arg(insn, word, word2, insn.Op2, oc->op2);
|
||||
if ( oc->op3 != 0 )
|
||||
{
|
||||
// @(imm, reg) : fill the second operand
|
||||
if ( oc->op3 & OP_DISPL_B )
|
||||
set_arg(insn, word, word2, insn.Op2, oc->op3);
|
||||
else
|
||||
set_arg(insn, word, word2, insn.Op3, oc->op3);
|
||||
}
|
||||
|
||||
// Additionnal code
|
||||
switch ( oc->instruction )
|
||||
{
|
||||
// instructions mvfc - mvtc uses control registers
|
||||
case m32r_mvtc:
|
||||
swap_op(insn.Op1, insn.Op2);
|
||||
// no break
|
||||
case m32r_mvfc:
|
||||
insn.Op2.reg = r2cr(insn.Op2.reg);
|
||||
if ( insn.Op2.reg == ushort(-1) )
|
||||
return 0;
|
||||
break;
|
||||
|
||||
// some of the m32rx instructions uses accumulator registers
|
||||
case m32rx_mulhi:
|
||||
case m32rx_mullo:
|
||||
case m32rx_machi:
|
||||
case m32rx_maclo:
|
||||
case m32rx_mvfachi:
|
||||
case m32rx_mvfaclo:
|
||||
case m32rx_mvfacmi:
|
||||
case m32rx_mvtachi:
|
||||
case m32rx_mvtaclo:
|
||||
case m32rx_mulwhi:
|
||||
case m32rx_mulwlo:
|
||||
case m32rx_macwhi:
|
||||
case m32rx_macwlo:
|
||||
insn.Op3.type = o_reg;
|
||||
insn.Op3.reg = rA1; // this is the default
|
||||
insn.Op3.dtype = dt_dword;
|
||||
break;
|
||||
|
||||
// synthetic instructions
|
||||
case m32r_bc:
|
||||
case m32r_bl:
|
||||
case m32r_bnc:
|
||||
case m32r_bra:
|
||||
case m32r_ldi:
|
||||
insn.segpref |= (s == 16 ? SYNTHETIC_SHORT : SYNTHETIC_LONG);
|
||||
break;
|
||||
|
||||
case m32r_st:
|
||||
if ( insn.Op2.specflag1 == fRIAS && insn.Op2.reg == rSP )
|
||||
{
|
||||
insn.itype = (use_synthetic_insn() ? m32r_push : m32r_st);
|
||||
insn.Op2.type = (use_synthetic_insn() ? o_void : o_phrase);
|
||||
}
|
||||
break;
|
||||
case m32r_ld:
|
||||
if ( insn.Op2.specflag1 == fRIBA && insn.Op2.reg == rSP )
|
||||
{
|
||||
insn.itype = (use_synthetic_insn() ? m32r_pop : m32r_ld);
|
||||
insn.Op2.type = (use_synthetic_insn() ? o_void : o_phrase);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// detect parallel NOP / DSP instructions
|
||||
if ( s == 16 && (insn.ea % 4) == 0 )
|
||||
{
|
||||
int b = get_word(insn.ea + insn.size);
|
||||
|
||||
if ( ((b & 0x8FFF) >> 15) == 1 )
|
||||
{
|
||||
// next opcode is NOP
|
||||
if ( b == 0xF000 )
|
||||
{
|
||||
insn.size += 2;
|
||||
insn.segpref |= NEXT_INSN_PARALLEL_NOP;
|
||||
}
|
||||
// this opcode is NOP, the next should be a DSP insn
|
||||
else if ( word == 0x7000 )
|
||||
{
|
||||
// recall the analyzer (and therefore erase the current NOP)
|
||||
ana(&insn);
|
||||
// flag the DSP instruction
|
||||
insn.segpref |= NEXT_INSN_PARALLEL_DSP;
|
||||
}
|
||||
else
|
||||
{
|
||||
insn_t insn2;
|
||||
decode_insn(&insn2, insn.ea + insn.size);
|
||||
if ( insn2.size == 2 )
|
||||
insn.segpref |= NEXT_INSN_PARALLEL_OTHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
return insn.size;
|
||||
}
|
||||
393
idasdk76/module/m32r/emu.cpp
Normal file
393
idasdk76/module/m32r/emu.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
|
||||
#include "m32r.hpp"
|
||||
|
||||
// handle immediate values
|
||||
static void handle_imm(const insn_t &insn)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// handle the custom switch format
|
||||
// ....
|
||||
// bl.s next || nop <- insn_ea
|
||||
// next:
|
||||
// add lr, R0
|
||||
// jmp lr
|
||||
// si.jumps:
|
||||
// bra.s case0 || nop
|
||||
// bra.l case1
|
||||
// ...
|
||||
int m32r_create_switch_xrefs(ea_t insn_ea, const switch_info_t &si)
|
||||
{
|
||||
if ( (si.flags & SWI_CUSTOM) != 0 )
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, insn_ea);
|
||||
ea_t ea = si.jumps;
|
||||
for ( int i = 0; i < si.ncases; i++, ea += insn.size )
|
||||
{
|
||||
add_cref(insn_ea, ea, fl_JN);
|
||||
decode_insn(&insn, ea);
|
||||
if ( insn.Op1.type == o_near )
|
||||
{
|
||||
ea_t target = to_ea(insn.cs, insn.Op1.addr);
|
||||
// xrefs are from "bl" -> branch target.
|
||||
add_cref(insn_ea, target, fl_JN);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1; // ok
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int m32r_calc_switch_cases(casevec_t *casevec, eavec_t *targets, ea_t insn_ea, const switch_info_t &si)
|
||||
{
|
||||
if ( (si.flags & SWI_CUSTOM) == 0 )
|
||||
return 0;
|
||||
|
||||
insn_t insn;
|
||||
decode_insn(&insn, insn_ea);
|
||||
|
||||
ea_t ea = si.jumps;
|
||||
svalvec_t vals;
|
||||
vals.push_back(0); // add one item
|
||||
for ( int i=0; i < si.ncases; i++, ea += insn.size )
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
if ( targets != NULL )
|
||||
{
|
||||
if ( insn.itype == m32r_bra && insn.Op1.type == o_near )
|
||||
targets->push_back(insn.Op1.addr);
|
||||
else
|
||||
targets->push_back(insn.ea);
|
||||
}
|
||||
if ( casevec != NULL )
|
||||
{
|
||||
vals[0] = i;
|
||||
casevec->push_back(vals);
|
||||
}
|
||||
}
|
||||
return 1; // ok
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool handle_switch(const insn_t &insn)
|
||||
{
|
||||
switch_info_t si;
|
||||
bool was_switch = (get_flags(insn.ea) & FF_JUMP) != 0
|
||||
&& get_switch_info(&si, insn.ea) > 0;
|
||||
// do not overwrite the existing switch
|
||||
// FIXME: reanalyze non user defined switches
|
||||
if ( was_switch )
|
||||
return true;
|
||||
|
||||
// ldi8 R1, #0x21 ; '!'
|
||||
// cmpu R1, R0
|
||||
// bc.l loc_67F8C
|
||||
// slli R0, #2
|
||||
// addi R0, #4
|
||||
// bl.s next || nop
|
||||
// next:
|
||||
// add lr, R0
|
||||
// jmp lr
|
||||
// bra.s loc_67CDC || nop
|
||||
// bra.s loc_67D34 || nop
|
||||
// bra.l loc_67F8C
|
||||
// ...
|
||||
if ( insn.itype != m32r_bl )
|
||||
return false;
|
||||
|
||||
// bl should be to next address
|
||||
ea_t tgt = to_ea(insn.cs, insn.Op1.addr);
|
||||
if ( tgt != insn.ea + insn.size )
|
||||
return false;
|
||||
|
||||
insn_t insn2;
|
||||
// check for add lr, R0; jmp lr
|
||||
if ( decode_insn(&insn2, tgt) == 0
|
||||
|| insn2.itype != m32r_add
|
||||
|| !insn2.Op1.is_reg(rLR)
|
||||
|| insn2.Op2.type != o_reg )
|
||||
{
|
||||
BAD_MATCH:
|
||||
return false;
|
||||
}
|
||||
|
||||
int switch_reg = insn2.Op2.reg;
|
||||
|
||||
// jmp lr
|
||||
if ( decode_insn(&insn2, insn2.ea + insn2.size) == 0
|
||||
|| insn2.itype != m32r_jmp
|
||||
|| !insn2.Op1.is_reg(rLR) )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
// addi R0, #4
|
||||
if ( decode_prev_insn(&insn2, insn.ea) == BADADDR
|
||||
|| insn2.itype != m32r_addi
|
||||
|| !insn2.Op1.is_reg(switch_reg)
|
||||
|| insn2.Op2.type != o_imm )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
ea_t jumps = insn.ea + insn.size + insn2.Op2.value;
|
||||
|
||||
// slli R0, #2
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_slli
|
||||
|| !insn2.Op1.is_reg(switch_reg)
|
||||
|| !insn2.Op2.is_imm(2) )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
// bc.l default
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_bc )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
ea_t defea = to_ea(insn2.cs, insn2.Op1.addr);
|
||||
|
||||
// cmpu R1, R0
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_cmpu
|
||||
|| !insn2.Op2.is_reg(switch_reg)
|
||||
|| insn2.Op1.type != o_reg )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
int cmpreg = insn2.Op1.reg;
|
||||
|
||||
// ldi8 R1, #max
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_ldi
|
||||
|| !insn2.Op1.is_reg(cmpreg)
|
||||
|| insn2.Op2.type != o_imm )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
// looks good
|
||||
|
||||
si.flags |= SWI_CUSTOM | SWI_J32;
|
||||
si.ncases = insn2.Op2.value + 1;
|
||||
si.jumps = jumps;
|
||||
si.lowcase = 0;
|
||||
si.startea = insn2.ea;
|
||||
si.set_expr(switch_reg, dt_dword);
|
||||
si.defjump = defea;
|
||||
set_switch_info(insn.ea, si);
|
||||
create_switch_table(insn.ea, si);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// emulate operand
|
||||
void m32r_t::handle_operand(const insn_t &insn, const op_t &op, bool loading)
|
||||
{
|
||||
flags_t F = get_flags(insn.ea);
|
||||
switch ( op.type )
|
||||
{
|
||||
// Address
|
||||
case o_near:
|
||||
// branch label - create code reference (call or jump
|
||||
// according to the instruction)
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, op.addr);
|
||||
cref_t ftype = fl_JN;
|
||||
if ( insn.itype == m32r_bl && !handle_switch(insn) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, op.offb, ftype);
|
||||
}
|
||||
break;
|
||||
|
||||
// Immediate
|
||||
case o_imm:
|
||||
QASSERT(10135, loading);
|
||||
handle_imm(insn);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, dr_O, OOFW_IMM|OOF_SIGNED);
|
||||
|
||||
// create a comment if this immediate is represented in the .cfg file
|
||||
{
|
||||
const ioport_t *port = find_sym(op.value);
|
||||
if ( port != NULL && !has_cmt(F) )
|
||||
set_cmt(insn.ea, port->cmt.c_str(), false);
|
||||
}
|
||||
break;
|
||||
|
||||
// Displ
|
||||
case o_displ:
|
||||
handle_imm(insn);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, loading ? dr_R : dr_W, OOF_SIGNED|OOF_ADDR|OOFW_32);
|
||||
|
||||
// create stack variables if required
|
||||
if ( may_create_stkvars() && !is_defarg(F, op.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL && (op.reg == rFP || op.reg == rSP) && pfn->flags & FUNC_FRAME )
|
||||
{
|
||||
if ( insn.create_stkvar(op, op.addr, STKVAR_VALID_SIZE) )
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
/* create stack variables if required */
|
||||
if ( op.specflag1 == fRI && may_create_stkvars() && !is_defarg(F, op.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL
|
||||
&& (op.reg == rFP || op.reg == rSP)
|
||||
&& (pfn->flags & FUNC_FRAME) != 0 )
|
||||
{
|
||||
if ( insn.create_stkvar(op, 0, STKVAR_VALID_SIZE) )
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Phrase - register - void : do nothing
|
||||
case o_reg:
|
||||
case o_void:
|
||||
break;
|
||||
|
||||
// Others types should never be called
|
||||
default:
|
||||
INTERR(10136);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// emulate an instruction
|
||||
int m32r_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
flow = ((feature & CF_STOP) == 0);
|
||||
|
||||
if ( feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
||||
if ( feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
|
||||
if ( feature & CF_USE3 ) handle_operand(insn, insn.Op3, true);
|
||||
|
||||
if ( feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
|
||||
if ( feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
|
||||
if ( feature & CF_CHG3 ) handle_operand(insn, insn.Op3, false);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
if ( pfn == NULL )
|
||||
return 0;
|
||||
|
||||
ea_t ea = pfn->start_ea;
|
||||
insn_t insn[4];
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
decode_insn(&insn[i], ea);
|
||||
ea += insn[i].size;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
ushort regsize = 0; // number of saved registers
|
||||
|
||||
// first insn is not either push fp OR st fp, @-sp
|
||||
if ( (insn[i].itype != m32r_push
|
||||
|| insn[i].Op1.reg != rFP)
|
||||
&& (insn[i].itype != m32r_st
|
||||
|| insn[i].Op1.reg != rFP
|
||||
|| insn[i].Op2.reg != rSP
|
||||
|| insn[i].Op2.specflag1 != fRIAS) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
regsize += 4;
|
||||
i++;
|
||||
|
||||
// next insn is push lr OR st lr, @-sp
|
||||
if ( (insn[i].itype == m32r_push
|
||||
&& insn[i].Op1.reg == rLR)
|
||||
|| (insn[i].itype == m32r_st
|
||||
&& insn[i].Op1.reg == rFP
|
||||
&& insn[i].Op2.reg == rLR
|
||||
&& insn[i].Op2.specflag1 != fRIAS) )
|
||||
{
|
||||
regsize += 4;
|
||||
i++;
|
||||
}
|
||||
|
||||
// next insn is not addi sp, #imm
|
||||
if ( insn[i].itype != m32r_addi || insn[i].Op1.reg != rSP )
|
||||
return 0;
|
||||
|
||||
sval_t offset = - (sval_t) insn[i].Op2.value;
|
||||
|
||||
// toggle to the negative sign of the immediate operand of the addi insn
|
||||
if ( !is_invsign(insn[i].ea, get_flags(insn[i].ea), 2) )
|
||||
toggle_sign(insn[i].ea, 2);
|
||||
|
||||
i++;
|
||||
|
||||
// next insn is not mv fp, sp
|
||||
if ( insn[i].itype != m32r_mv || insn[i].Op1.reg != rFP || insn[i].Op2.reg != rSP )
|
||||
return 0;
|
||||
|
||||
pfn->flags |= (FUNC_FRAME | FUNC_BOTTOMBP);
|
||||
return add_frame(pfn, offset, regsize, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// should always returns 0
|
||||
int idaapi m32r_get_frame_retsize(const func_t *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// check is the specified operand is relative to the SP register
|
||||
int idaapi is_sp_based(const insn_t &/*insn*/, const op_t &op)
|
||||
{
|
||||
return OP_SP_ADD | (op.reg == rSP ? OP_SP_BASED : OP_FP_BASED);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool idaapi can_have_type(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
case o_displ:
|
||||
return 1;
|
||||
|
||||
case o_phrase:
|
||||
if ( x.specflag1 == fRI )
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
151
idasdk76/module/m32r/ins.cpp
Normal file
151
idasdk76/module/m32r/ins.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
|
||||
#include "m32r.hpp"
|
||||
|
||||
// m32r instructions definition
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
{ "", 0 }, // Null instruction
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // Add
|
||||
{ "add3", CF_USE2|CF_USE3|CF_CHG1 }, // Add 3-operand
|
||||
{ "addi", CF_USE1|CF_USE2|CF_CHG1 }, // Add immediate
|
||||
{ "addv", CF_USE1|CF_USE2|CF_CHG1 }, // Add with overflow checking
|
||||
{ "addv3", CF_USE2|CF_USE3|CF_CHG1 }, // Add 3-operand with overflow checking
|
||||
{ "addx", CF_USE1|CF_USE2|CF_CHG1 }, // Add with carry
|
||||
{ "and", CF_USE1|CF_USE2|CF_CHG1 }, // AND
|
||||
{ "and3", CF_USE2|CF_USE3|CF_CHG1 }, // AND 3-operand
|
||||
{ "bc", CF_USE1 }, // Branch on C-bit
|
||||
{ "beq", CF_USE1|CF_USE2|CF_USE3 }, // Branch on equal
|
||||
{ "beqz", CF_USE1|CF_USE2 }, // Branch on equal zero
|
||||
{ "bgez", CF_USE1|CF_USE2 }, // Branch on greater than or equal zero
|
||||
{ "bgtz", CF_USE1|CF_USE2 }, // Branch on greater than zero
|
||||
{ "bl", CF_USE1|CF_CALL }, // Branch and link
|
||||
{ "blez", CF_USE1|CF_USE2 }, // Branch on less than or equal zero
|
||||
{ "bltz", CF_USE1|CF_USE2 }, // Branch on less than zero
|
||||
{ "bnc", CF_USE1 }, // Branch on not C-bit
|
||||
{ "bne", CF_USE1|CF_USE2|CF_USE3 }, // Branch on not equal
|
||||
{ "bnez", CF_USE1|CF_USE2 }, // Branch on not equal zero
|
||||
{ "bra", CF_USE1|CF_STOP }, // Branch
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // Compare
|
||||
{ "cmpi", CF_USE1|CF_USE2 }, // Compare immediate
|
||||
{ "cmpu", CF_USE1|CF_USE2 }, // Compare unsigned
|
||||
{ "cmpui", CF_USE1|CF_USE2 }, // Compare unsigned immediate
|
||||
{ "div", CF_USE1|CF_USE2|CF_CHG1 }, // Divide
|
||||
{ "divu", CF_USE1|CF_USE2|CF_CHG1 }, // Divide unsigned
|
||||
{ "jl", CF_USE1|CF_CALL|CF_JUMP }, // Jump and link
|
||||
{ "jmp", CF_USE1|CF_JUMP|CF_STOP }, // Jump
|
||||
{ "ld", CF_USE2|CF_CHG1 }, // Load
|
||||
{ "ld24", CF_USE2|CF_CHG1 }, // Load 24-bit immediate
|
||||
{ "ldb", CF_USE2|CF_CHG1 }, // Load byte
|
||||
{ "ldh", CF_USE2|CF_CHG1 }, // Load halfword
|
||||
{ "ldi", CF_USE2|CF_CHG1 }, // Load immediate
|
||||
{ "ldub", CF_USE2|CF_CHG1 }, // Load unsigned byte
|
||||
{ "lduh", CF_USE2|CF_CHG1 }, // Load unsigned halfword
|
||||
{ "lock", CF_USE2|CF_CHG1 }, // Load locked
|
||||
{ "machi", CF_USE1|CF_USE2 }, // Multiply-accumulate high-order halfwords
|
||||
{ "maclo", CF_USE1|CF_USE2 }, // Multiply-accumulate low-order halfwords
|
||||
{ "macwhi", CF_USE1|CF_USE2 }, // Multiply-accumulate word and high-order halfword
|
||||
{ "macwlo", CF_USE1|CF_USE2 }, // Multiply-accumulate word and low-order halfword
|
||||
{ "mul", CF_USE1|CF_USE2|CF_CHG1 }, // Multiply
|
||||
{ "mulhi", CF_USE1|CF_USE2 }, // Multiply high-order halfwords
|
||||
{ "mullo", CF_USE1|CF_USE2 }, // Multiply low-order halfwords
|
||||
{ "mulwhi", CF_USE1|CF_USE2 }, // Multiply word high-order halfwords
|
||||
{ "mulwlo", CF_USE1|CF_USE2 }, // Multiply word low-order halfwords
|
||||
{ "mv", CF_USE2|CF_CHG1 }, // Move register
|
||||
{ "mvfachi", CF_CHG1 }, // Move from accumulator high-order word
|
||||
{ "mvfaclo", CF_CHG1 }, // Move from accumulator low-order word
|
||||
{ "mvfacmi", CF_CHG1 }, // Move from accumulator middle-order word
|
||||
{ "mvfc", CF_USE2|CF_CHG1 }, // Move from control register
|
||||
{ "mvtachi", CF_USE1 }, // Move to accumulator high-order word
|
||||
{ "mvtaclo", CF_USE1 }, // Move to accumulator low-order word
|
||||
{ "mvtc", CF_USE2|CF_CHG1 }, // Move to control register
|
||||
{ "neg", CF_USE2|CF_CHG1 }, // Negate
|
||||
{ "nop", 0 }, // No operation
|
||||
{ "not", CF_USE2|CF_CHG1 }, // Logical NOT
|
||||
{ "or", CF_USE1|CF_USE2|CF_CHG1 }, // OR
|
||||
{ "or3", CF_USE2|CF_USE3|CF_CHG1 }, // OR 3-operand
|
||||
{ "push", CF_USE1 }, // Push, mnem for st reg, @-sp
|
||||
{ "pop", CF_CHG1 }, // Pop, mnem for ld reg, @sp+
|
||||
{ "rac", 0 }, // Round accumulator
|
||||
{ "rach", 0 }, // Round accumulator halfword
|
||||
{ "rem", CF_USE1|CF_USE2|CF_CHG1 }, // Remainder
|
||||
{ "remu", CF_USE1|CF_USE2|CF_CHG1 }, // Remainder unsigned
|
||||
{ "rte", CF_STOP }, // Return from EIT
|
||||
{ "seth", CF_USE2|CF_CHG1 }, // Set high-order 16-bit
|
||||
{ "sll", CF_USE1|CF_USE2|CF_CHG1 }, // Shift left logical
|
||||
{ "sll3", CF_USE2|CF_USE3|CF_CHG1 }, // Shift left logical 3-operand
|
||||
{ "slli", CF_USE1|CF_USE2|CF_CHG1 }, // Shift left logical immediate
|
||||
{ "sra", CF_USE1|CF_USE2|CF_CHG1 }, // Shirt right arithmetic
|
||||
{ "sra3", CF_USE2|CF_USE3|CF_CHG1 }, // Shirt right arithmetic 3-operand
|
||||
{ "srai", CF_USE1|CF_USE2|CF_CHG1 }, // Shirt right arithmetic immediate
|
||||
{ "srl", CF_USE1|CF_USE2|CF_CHG1 }, // Shift right logical
|
||||
{ "srl3", CF_USE2|CF_USE3|CF_CHG1 }, // Shift right logical 3-operand
|
||||
{ "srli", CF_USE1|CF_USE2|CF_CHG1 }, // Shift right logical immediate
|
||||
{ "st", CF_USE1|CF_USE2|CF_CHG1 }, // Store
|
||||
{ "stb", CF_USE1|CF_CHG2 }, // Store byte
|
||||
{ "sth", CF_USE1|CF_CHG2 }, // Store halfword
|
||||
{ "sub", CF_USE1|CF_USE2|CF_CHG1 }, // Substract
|
||||
{ "subv", CF_USE1|CF_USE2|CF_CHG1 }, // Substract with overflow checking
|
||||
{ "subx", CF_USE1|CF_USE2|CF_CHG1 }, // Substract with borrow
|
||||
{ "trap", CF_USE1 }, // Trap
|
||||
{ "unlock", CF_USE1|CF_CHG2 }, // Store unlocked
|
||||
{ "xor", CF_USE1|CF_USE2|CF_CHG1 }, // Exclusive OR
|
||||
{ "xor3", CF_USE2|CF_USE3|CF_CHG1 }, // Exclusive OR 3-operand
|
||||
|
||||
// M32RX :
|
||||
|
||||
{ "bcl", CF_USE1 },
|
||||
{ "bncl", CF_USE1 },
|
||||
{ "cmpeq", CF_USE1|CF_USE2 },
|
||||
{ "cmpz", CF_USE1 },
|
||||
{ "divh", CF_USE1|CF_USE2|CF_CHG1 },
|
||||
{ "jc", CF_USE1 },
|
||||
{ "jnc", CF_USE1 },
|
||||
{ "machi", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'machi' 3-operand
|
||||
{ "maclo", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'maclo' 3-operand
|
||||
{ "macwhi", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'macwhi' 3-operand
|
||||
{ "macwlo", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'macwlo' 3-operand
|
||||
{ "mulhi", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'mulhi' 3-operand
|
||||
{ "mullo", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'mullo' 3-operand
|
||||
{ "mulwhi", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'mulwhi' 3-operand
|
||||
{ "mulwlo", CF_USE1|CF_USE2|CF_USE3|CF_CHG3 }, // 'mulwlo' 3-operand
|
||||
{ "mvfachi", CF_USE2|CF_CHG1 }, // 'mvfachi' 3-operand
|
||||
{ "mvfaclo", CF_USE2|CF_CHG1 }, // 'mvfaclo' 3-operand
|
||||
{ "mvfacmi", CF_USE2|CF_CHG1 }, // 'mvfacmi' 3-operand
|
||||
{ "mvtachi", CF_USE1|CF_CHG2 }, // 'mvtachi' 3-operand
|
||||
{ "mvtaclo", CF_USE1|CF_CHG2 }, // 'mvtaclo' 3-operand
|
||||
{ "rac", CF_USE2|CF_CHG1 }, // 'rac' 3 operand
|
||||
{ "rach", CF_USE2|CF_CHG1 }, // 'rach' 3 operand
|
||||
{ "satb", CF_USE2|CF_CHG1 },
|
||||
{ "sath", CF_USE2|CF_CHG1 },
|
||||
{ "sat", CF_USE2|CF_CHG1 },
|
||||
{ "pcmpbz", CF_USE1 },
|
||||
{ "sadd", 0 },
|
||||
{ "macwu1", CF_USE1|CF_USE2 },
|
||||
{ "msblo", CF_USE1|CF_USE2 },
|
||||
{ "mulwu1", CF_USE1|CF_USE2 },
|
||||
{ "maclh1", CF_USE1|CF_USE2 },
|
||||
{ "sc", 0 },
|
||||
{ "snc", 0 },
|
||||
|
||||
// Floating point
|
||||
{ "fadd", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point add
|
||||
{ "fsub", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point subtract
|
||||
{ "fmul", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point multiply
|
||||
{ "fdiv", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point divede
|
||||
{ "fmadd", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point multiply and add
|
||||
{ "fmsub", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point multiply and subtract
|
||||
{ "itof", CF_CHG1|CF_USE2 }, // Integer to float
|
||||
{ "utof", CF_CHG1|CF_USE2 }, // Unsigned integer to float
|
||||
{ "ftoi", CF_CHG1|CF_USE2 }, // Float to integer
|
||||
{ "ftos", CF_CHG1|CF_USE2 }, // Float to short
|
||||
{ "fcmp", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point compare
|
||||
{ "fcmpe", CF_CHG1|CF_USE2|CF_USE3 }, // Floating-point compare with exeption if unordered
|
||||
// Bit Operation Instructions
|
||||
{ "bset", CF_USE1|CF_CHG2 }, // Bit set
|
||||
{ "bclr", CF_USE1|CF_CHG2 }, // Bit clear
|
||||
{ "btst", CF_USE1|CF_USE2 }, // Bit test
|
||||
{ "setpsw", CF_USE1 }, // Set PSW
|
||||
{ "clrpsw", CF_USE1 }, // Clear PSW
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == m32r_last);
|
||||
158
idasdk76/module/m32r/ins.hpp
Normal file
158
idasdk76/module/m32r/ins.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
// exporting the ins.cpp array
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
// m32r instructions declaration
|
||||
enum nameNum ENUM_SIZE(uint16)
|
||||
{
|
||||
m32r_null = 0, // Null instruction
|
||||
m32r_add, // Add
|
||||
m32r_add3, // Add 3-operand
|
||||
m32r_addi, // Add immediate
|
||||
m32r_addv, // Add with overflow checking
|
||||
m32r_addv3, // Add 3-operand with overflow checking
|
||||
m32r_addx, // Add with carry
|
||||
m32r_and, // AND
|
||||
m32r_and3, // AND 3-operand
|
||||
m32r_bc, // Branch on C-bit
|
||||
m32r_beq, // Branch on equal
|
||||
m32r_beqz, // Branch on equal zero
|
||||
m32r_bgez, // Branch on greater than or equal zero
|
||||
m32r_bgtz, // Branch on greater than zero
|
||||
m32r_bl, // Branch and link
|
||||
m32r_blez, // Branch on less than or equal zero
|
||||
m32r_bltz, // Branch on less than zero
|
||||
m32r_bnc, // Branch on not C-bit
|
||||
m32r_bne, // Branch on not equal
|
||||
m32r_bnez, // Branch on not equal zero
|
||||
m32r_bra, // Branch
|
||||
m32r_cmp, // Compare
|
||||
m32r_cmpi, // Compare immediate
|
||||
m32r_cmpu, // Compare unsigned
|
||||
m32r_cmpui, // Compare unsigned immediate
|
||||
m32r_div, // Divide
|
||||
m32r_divu, // Divide unsigned
|
||||
m32r_jl, // Jump and link
|
||||
m32r_jmp, // Jump
|
||||
m32r_ld, // Load
|
||||
m32r_ld24, // Load 24-bit immediate
|
||||
m32r_ldb, // Load byte
|
||||
m32r_ldh, // Load halfword
|
||||
m32r_ldi, // Load immediate
|
||||
m32r_ldub, // Load unsigned byte
|
||||
m32r_lduh, // Load unsigned halfword
|
||||
m32r_lock, // Load locked
|
||||
m32r_machi, // Multiply-accumulate high-order halfwords
|
||||
m32r_maclo, // Multiply-accumulate low-order halfwords
|
||||
m32r_macwhi, // Multiply-accumulate word and high-order halfword
|
||||
m32r_macwlo, // Multiply-accumulate word and low-order halfword
|
||||
m32r_mul, // Multiply
|
||||
m32r_mulhi, // Multiply high-order halfwords
|
||||
m32r_mullo, // Multiply low-order halfwords
|
||||
m32r_mulwhi, // Multiply word high-order halfwords
|
||||
m32r_mulwlo, // Multiply word low-order halfwords
|
||||
m32r_mv, // Move register
|
||||
m32r_mvfachi, // Move from accumulator high-order word
|
||||
m32r_mvfaclo, // Move from accumulator low-order word
|
||||
m32r_mvfacmi, // Move from accumulator middle-order word
|
||||
m32r_mvfc, // Move from control register
|
||||
m32r_mvtachi, // Move to accumulator high-order word
|
||||
m32r_mvtaclo, // Move to accumulator low-order word
|
||||
m32r_mvtc, // Move to control register
|
||||
m32r_neg, // Negate
|
||||
m32r_nop, // No operation
|
||||
m32r_not, // Logical NOT
|
||||
m32r_or, // OR
|
||||
m32r_or3, // OR 3-operand
|
||||
m32r_push, // Push, mnem for st reg, @-sp
|
||||
m32r_pop, // Pop, mnem for ld reg, @sp+
|
||||
m32r_rac, // Round accumulator
|
||||
m32r_rach, // Round accumulator halfword
|
||||
m32r_rem, // Remainder
|
||||
m32r_remu, // Remainder unsigned
|
||||
m32r_rte, // Return from EIT
|
||||
m32r_seth, // Set high-order 16-bit
|
||||
m32r_sll, // Shift left logical
|
||||
m32r_sll3, // Shift left logical 3-operand
|
||||
m32r_slli, // Shift left logical immediate
|
||||
m32r_sra, // Shirt right arithmetic
|
||||
m32r_sra3, // Shirt right arithmetic 3-operand
|
||||
m32r_srai, // Shirt right arithmetic immediate
|
||||
m32r_srl, // Shift right logical
|
||||
m32r_srl3, // Shift right logical 3-operand
|
||||
m32r_srli, // Shift right logical immediate
|
||||
m32r_st, // Store
|
||||
m32r_stb, // Store byte
|
||||
m32r_sth, // Store halfword
|
||||
m32r_sub, // Substract
|
||||
m32r_subv, // Substract with overflow checking
|
||||
m32r_subx, // Substract with borrow
|
||||
m32r_trap, // Trap
|
||||
m32r_unlock, // Store unlocked
|
||||
m32r_xor, // Exclusive OR
|
||||
m32r_xor3, // Exclusive OR 3-operand
|
||||
|
||||
// M32RX :
|
||||
|
||||
m32rx_bcl,
|
||||
m32rx_bncl,
|
||||
m32rx_cmpeq,
|
||||
m32rx_cmpz,
|
||||
m32rx_divh,
|
||||
m32rx_jc,
|
||||
m32rx_jnc,
|
||||
m32rx_machi, // 'machi' 3-operand
|
||||
m32rx_maclo, // 'maclo' 3-operand
|
||||
m32rx_macwhi, // 'macwhi' 3-operand
|
||||
m32rx_macwlo, // 'macwlo' 3-operand
|
||||
m32rx_mulhi, // 'mulhi' 3-operand
|
||||
m32rx_mullo, // 'mullo' 3-operand
|
||||
m32rx_mulwhi, // 'mulwhi' 3-operand
|
||||
m32rx_mulwlo, // 'mulwlo' 3-operand
|
||||
m32rx_mvfachi, // 'mvfachi' 3-operand
|
||||
m32rx_mvfaclo, // 'mvfaclo' 3-operand
|
||||
m32rx_mvfacmi, // 'mvfacmi' 3-operand
|
||||
m32rx_mvtachi, // 'mvtachi' 3-operand
|
||||
m32rx_mvtaclo, // 'mvtaclo' 3-operand
|
||||
m32rx_rac, // 'rac' 3 operand
|
||||
m32rx_rach, // 'rach' 3 operand
|
||||
m32rx_satb,
|
||||
m32rx_sath,
|
||||
m32rx_sat,
|
||||
m32rx_pcmpbz,
|
||||
m32rx_sadd,
|
||||
m32rx_macwu1,
|
||||
m32rx_msblo,
|
||||
m32rx_mulwu1,
|
||||
m32rx_maclh1,
|
||||
m32rx_sc,
|
||||
m32rx_snc,
|
||||
|
||||
// Floating point
|
||||
m32r_fadd, // Floating-point add
|
||||
m32r_fsub, // Floating-point subtract
|
||||
m32r_fmul, // Floating-point multiply
|
||||
m32r_fdiv, // Floating-point divede
|
||||
m32r_fmadd, // Floating-point multiply and add
|
||||
m32r_fmsub, // Floating-point multiply and subtract
|
||||
m32r_itof, // Integer to float
|
||||
m32r_utof, // Unsigned integer to float
|
||||
m32r_ftoi, // Float to integer
|
||||
m32r_ftos, // Float to short
|
||||
m32r_fcmp, // Floating-point compare
|
||||
m32r_fcmpe, // Floating-point compare with exeption if unordered
|
||||
// Bit Operation Instructions
|
||||
m32r_bset, // Bit set
|
||||
m32r_bclr, // Bit clear
|
||||
m32r_btst, // Bit test
|
||||
m32r_setpsw, // Set PSW
|
||||
m32r_clrpsw, // Clear PSW
|
||||
|
||||
m32r_last
|
||||
};
|
||||
|
||||
#endif /* __INSTRS_HPP */
|
||||
|
||||
28730
idasdk76/module/m32r/m32r.cfg
Normal file
28730
idasdk76/module/m32r/m32r.cfg
Normal file
File diff suppressed because it is too large
Load Diff
190
idasdk76/module/m32r/m32r.hpp
Normal file
190
idasdk76/module/m32r/m32r.hpp
Normal file
@@ -0,0 +1,190 @@
|
||||
|
||||
#ifndef _M32R_HPP
|
||||
#define _M32R_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include <frame.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
#define PROCMOD_NAME m32r
|
||||
#define PROCMOD_NODE_NAME "$ m32r"
|
||||
|
||||
// Flags for operand specflag1
|
||||
|
||||
#define NEXT_INSN_PARALLEL_NOP 0x0001 // next insn is a // nop
|
||||
#define NEXT_INSN_PARALLEL_DSP 0x0002 // next insn is a // dsp
|
||||
#define NEXT_INSN_PARALLEL_OTHER 0x0004 // next insn is an other // insn
|
||||
|
||||
#define SYNTHETIC_SHORT 0x0010 // insn is synthetic short (ex bc.s)
|
||||
#define SYNTHETIC_LONG 0x0020 // insn is synthetic long (ex bc.l)
|
||||
|
||||
#define HAS_MSB 0x0100 // insn _has_ its MSB to 1
|
||||
|
||||
// Synthetic instructions list:
|
||||
|
||||
/*
|
||||
m32r :
|
||||
|
||||
bc.s label bc label [8-bit offset]
|
||||
bc.l label bc label [24-bit offset]
|
||||
bl.s label bl label [8-bit offset]
|
||||
bl.l label bl label [24-bit offset]
|
||||
bnc.s label bnc label [8-bit offset]
|
||||
bnc.l label bnc label [24-bit offset]
|
||||
bra.s label bra label [8-bit offset]
|
||||
bra.l label bra label [24-bit offset]
|
||||
ldi8 reg, #const ldi reg, #const [8-bit constant]
|
||||
ldi16 reg, #const ldi reg, #const [16-bit constant]
|
||||
push reg st reg, @-sp
|
||||
pop reg ld reg, @sp+
|
||||
|
||||
m32rx :
|
||||
|
||||
bcl.s label bcl label [8 bit offset]
|
||||
bcl.l label bcl label [24 bit offset]
|
||||
bncl.s label bncl label [8 bit offset]
|
||||
bncl.l label bncl label [24 bit offset]
|
||||
*/
|
||||
|
||||
// Register aliases list:
|
||||
|
||||
/*
|
||||
m32r :
|
||||
|
||||
r13 fp
|
||||
r14 lr
|
||||
r15 sp
|
||||
|
||||
cr0 psw
|
||||
cr1 cbr
|
||||
cr2 spi
|
||||
cr3 spu
|
||||
cr6 bpc
|
||||
|
||||
m32rx :
|
||||
|
||||
cr8 bbpsw
|
||||
cr14 bbpc
|
||||
*/
|
||||
|
||||
// define some shortcuts
|
||||
#define rFP rR13
|
||||
#define rLR rR14
|
||||
#define rSP rR15
|
||||
#define rPSW rCR0
|
||||
#define rCBR rCR1
|
||||
#define rSPI rCR2
|
||||
#define rSPU rCR3
|
||||
#define rBPC rCR6
|
||||
#define rFPSR rCR7
|
||||
|
||||
// m32rx only
|
||||
#define rBBPSW rCR8
|
||||
#define rBBPC rCR14
|
||||
|
||||
// m32r registers
|
||||
enum m32r_registers
|
||||
{
|
||||
// General-purpose registers
|
||||
rR0, rR1, rR2, rR3, rR4,
|
||||
rR5, rR6, rR7, rR8, rR9,
|
||||
rR10, rR11, rR12, rR13, rR14, rR15,
|
||||
|
||||
// Control registers
|
||||
rCR0, rCR1, rCR2, rCR3, rCR6,
|
||||
|
||||
// Program counter
|
||||
rPC,
|
||||
|
||||
// m32rx special registers
|
||||
|
||||
rA0, rA1, // Accumulators
|
||||
rCR4, rCR5, rCR7, rCR8, rCR9, // Add. control registers
|
||||
rCR10, rCR11, rCR12, rCR13, rCR14, rCR15,
|
||||
|
||||
rVcs, rVds // these 2 registers are required by the IDA kernel
|
||||
};
|
||||
|
||||
// m32r indirect addressing mode
|
||||
enum m32r_phrases
|
||||
{
|
||||
fRI, // @R Register indirect
|
||||
fRIBA, // @R+ Register indirect update before add
|
||||
fRIAA, // @+R Register indirect update after add
|
||||
fRIAS // @-R Register indirect update after sub
|
||||
};
|
||||
|
||||
// this module supports 2 processors: m32r and m32rx
|
||||
enum processor_subtype_t
|
||||
{
|
||||
prc_m32r = 0,
|
||||
prc_m32rx = 1
|
||||
};
|
||||
|
||||
// exporting our routines
|
||||
void idaapi m32r_footer(outctx_t &ctx);
|
||||
void idaapi m32r_segstart(outctx_t &ctx, segment_t *seg);
|
||||
int idaapi emu(const insn_t &insn);
|
||||
bool idaapi create_func_frame(func_t *pfn);
|
||||
int idaapi m32r_get_frame_retsize(const func_t *pfn);
|
||||
int idaapi is_sp_based(const insn_t &insn, const op_t &op);
|
||||
bool idaapi can_have_type(const op_t &op);
|
||||
int m32r_create_switch_xrefs(ea_t insn_ea, const switch_info_t &si);
|
||||
int m32r_calc_switch_cases(casevec_t *casevec, eavec_t *targets, ea_t insn_ea, const switch_info_t &si);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct opcode;
|
||||
|
||||
struct m32r_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct m32r_t ±
|
||||
m32r_iohandler_t(m32r_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual void get_cfg_filename(char *buf, size_t bufsize) override;
|
||||
};
|
||||
|
||||
struct m32r_t : public procmod_t
|
||||
{
|
||||
// altval(-1) -> idpflags
|
||||
// supstr(-1) -> device
|
||||
netnode helper;
|
||||
m32r_iohandler_t ioh = m32r_iohandler_t(*this, helper);
|
||||
|
||||
#define IDP_SYNTHETIC 0x0001 // use synthetic instructions
|
||||
#define IDP_REG_ALIASES 0x0002 // use register aliases
|
||||
uint32 idpflags = IDP_SYNTHETIC | IDP_REG_ALIASES;
|
||||
inline bool use_synthetic_insn(void) { return (idpflags & IDP_SYNTHETIC) != 0; }
|
||||
inline bool use_reg_aliases(void) { return (idpflags & IDP_REG_ALIASES) != 0; }
|
||||
|
||||
// Current processor type (prc_m32r or prc_m32rx)
|
||||
processor_subtype_t ptype = prc_m32r;
|
||||
bool flow = false;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool idb_loaded);
|
||||
void handle_new_flags(bool save=true);
|
||||
const ioport_t *find_sym(ea_t address);
|
||||
|
||||
int ana(insn_t *_insn);
|
||||
const opcode *get_opcode(int word) const;
|
||||
bool ana_special(insn_t &insn, int word, int *s) const;
|
||||
int parse_fp_insn(insn_t &insn, int word);
|
||||
|
||||
void m32r_header(outctx_t &ctx);
|
||||
inline const char *ptype_str(void) const;
|
||||
|
||||
void handle_operand(const insn_t &insn, const op_t &op, bool loading);
|
||||
int emu(const insn_t &insn);
|
||||
|
||||
void save_idpflags() { helper.altset(-1, idpflags); }
|
||||
void load_from_idb();
|
||||
};
|
||||
extern int data_id;
|
||||
|
||||
#endif /* _M32R_HPP */
|
||||
57
idasdk76/module/m32r/makefile
Normal file
57
idasdk76/module/m32r/makefile
Normal file
@@ -0,0 +1,57 @@
|
||||
PROC=m32r
|
||||
CONFIGS=m32r.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 ins.hpp m32r.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 ins.hpp m32r.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 \
|
||||
ins.cpp ins.hpp m32r.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 \
|
||||
ins.hpp m32r.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)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
ins.hpp m32r.hpp reg.cpp
|
||||
251
idasdk76/module/m32r/out.cpp
Normal file
251
idasdk76/module/m32r/out.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
|
||||
#include "m32r.hpp"
|
||||
#include <diskio.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_m32r_t : public outctx_t
|
||||
{
|
||||
out_m32r_t(void) = delete; // not used
|
||||
m32r_t &pm() { return *static_cast<m32r_t *>(procmod); }
|
||||
public:
|
||||
void outreg(int n) { out_register(ph.reg_names[n]); }
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
void out_proc_mnem(void);
|
||||
};
|
||||
CASSERT(sizeof(out_m32r_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS(out_m32r_t)
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
inline const char *m32r_t::ptype_str(void) const
|
||||
{
|
||||
switch ( ptype )
|
||||
{
|
||||
case prc_m32r: return "m32r";
|
||||
case prc_m32rx: return "m32rx";
|
||||
}
|
||||
return NULL; //lint !e527 statement is unreachable
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// generate header
|
||||
void m32r_t::m32r_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
|
||||
|
||||
char buf[MAXSTR];
|
||||
const char *n = ptype_str();
|
||||
|
||||
// print the processor directive .m32r, or .m32rx
|
||||
if ( n != NULL )
|
||||
{
|
||||
qsnprintf(buf, sizeof(buf), COLSTR(".%s", SCOLOR_ASMDIR), n);
|
||||
ctx.flush_buf(buf,0);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// generate footer
|
||||
void idaapi m32r_footer(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// output an operand
|
||||
bool out_m32r_t::out_operand(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
// register
|
||||
case o_reg:
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
// immediate
|
||||
case o_imm:
|
||||
{
|
||||
const ioport_t *port = pm().find_sym(x.value);
|
||||
|
||||
// this immediate is represented in the .cfg file
|
||||
if ( port != NULL )
|
||||
{
|
||||
// output the port name instead of the numeric value
|
||||
out_line(port->name.c_str(), COLOR_IMPNAME);
|
||||
}
|
||||
// otherwise, simply print the value
|
||||
else
|
||||
{
|
||||
out_symbol('#');
|
||||
out_value(x, OOFW_IMM|OOF_SIGNED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// displ @(imm, reg)
|
||||
case o_displ:
|
||||
out_symbol('@');
|
||||
out_symbol('(');
|
||||
out_value(x, OOF_SIGNED | OOF_ADDR | OOFW_32);
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
outreg(x.reg);
|
||||
out_symbol(')');
|
||||
break;
|
||||
|
||||
// address
|
||||
case o_near:
|
||||
if ( !out_name_expr(x, to_ea(insn.cs, x.addr), x.addr) )
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
|
||||
break;
|
||||
|
||||
// phrase
|
||||
case o_phrase:
|
||||
switch ( x.specflag1 )
|
||||
{
|
||||
// @R
|
||||
case fRI:
|
||||
out_symbol('@');
|
||||
if ( is_defarg(F, x.n) )
|
||||
{
|
||||
out_symbol('(');
|
||||
out_value(x, 0); // will print 0
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
outreg(x.reg);
|
||||
out_symbol(')');
|
||||
}
|
||||
else
|
||||
{
|
||||
outreg(x.reg);
|
||||
}
|
||||
break;
|
||||
|
||||
// @R+
|
||||
case fRIBA:
|
||||
out_symbol('@');
|
||||
outreg(x.reg);
|
||||
out_symbol('+');
|
||||
break;
|
||||
|
||||
// @+R
|
||||
case fRIAA:
|
||||
out_symbol('@');
|
||||
out_symbol('+');
|
||||
outreg(x.reg);
|
||||
break;
|
||||
|
||||
// @-R
|
||||
case fRIAS:
|
||||
out_symbol('@');
|
||||
out_symbol('-');
|
||||
outreg(x.reg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void out_m32r_t::out_proc_mnem(void)
|
||||
{
|
||||
char postfix[3]; // postfix to eventually insert after the insn name
|
||||
postfix[0] = '\0'; // postfix is null by default
|
||||
|
||||
// use synthetic option is selected
|
||||
if ( pm().use_synthetic_insn() )
|
||||
{
|
||||
if ( insn.segpref & SYNTHETIC_SHORT )
|
||||
qstrncpy(postfix, (insn.itype == m32r_ldi ? "8" : ".s"), sizeof(postfix));
|
||||
if ( insn.segpref & SYNTHETIC_LONG )
|
||||
qstrncpy(postfix, (insn.itype == m32r_ldi ? "16" : ".l"), sizeof(postfix));
|
||||
}
|
||||
|
||||
out_mnem(8, postfix);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// output an instruction and its operands
|
||||
void out_m32r_t::out_insn(void)
|
||||
{
|
||||
// if this DSP instruction in executed in parallel with a NOP instruction
|
||||
// (example: nop || machi r1, r2), first print the NOP.
|
||||
if ( insn.segpref & NEXT_INSN_PARALLEL_DSP )
|
||||
{
|
||||
out_line("nop", COLOR_INSN);
|
||||
out_char(' ');
|
||||
out_symbol('|');
|
||||
out_symbol('|');
|
||||
out_char(' ');
|
||||
}
|
||||
|
||||
out_mnemonic();
|
||||
|
||||
out_one_operand(0); // output the first operand
|
||||
|
||||
if ( insn.Op2.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(1); // output the second operand
|
||||
}
|
||||
|
||||
if ( insn.Op3.type != o_void )
|
||||
{
|
||||
out_symbol(',');
|
||||
out_char(' ');
|
||||
out_one_operand(2); // output the third operand
|
||||
}
|
||||
|
||||
// output a character representation of the immediate values
|
||||
// embedded in the instruction as comments
|
||||
out_immchar_cmts();
|
||||
|
||||
// print a parallel NOP instruction unless the current instruction
|
||||
// is either push or pop (in this special case, nop cannot be executed in //)
|
||||
if ( (insn.itype != m32r_push && insn.itype != m32r_pop)
|
||||
&& insn.segpref & NEXT_INSN_PARALLEL_NOP )
|
||||
{
|
||||
// don't print NOP if the instruction was ld/st reg, fp, and has been converted to ld/st reg, @(arg, fp)
|
||||
// (in other words, in the second operand is a stack variable).
|
||||
// because the o_displ form of ld/st insn is 32 bits, and cannot handle a parallel nop.
|
||||
if ( (insn.itype != m32r_ld && insn.itype != m32r_st) || !is_stkvar1(F) )
|
||||
{
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_char(' ');
|
||||
out_symbol('|');
|
||||
out_symbol('|');
|
||||
out_char(' ');
|
||||
out_line("nop", COLOR_INSN);
|
||||
}
|
||||
}
|
||||
|
||||
if ( insn.segpref & NEXT_INSN_PARALLEL_OTHER )
|
||||
{
|
||||
if ( insn.Op1.type != o_void )
|
||||
out_char(' ');
|
||||
out_symbol('|');
|
||||
out_symbol('|');
|
||||
out_symbol('\\');
|
||||
}
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// generate segment header
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void idaapi m32r_segstart(outctx_t &ctx, segment_t *Sarea)
|
||||
{
|
||||
qstring sname;
|
||||
get_visible_segm_name(&sname, Sarea);
|
||||
char *segname = sname.begin();
|
||||
|
||||
if ( !sname.empty() && *segname == '_' )
|
||||
*segname = '.';
|
||||
|
||||
ctx.gen_printf(0, COLSTR(".section %s", SCOLOR_ASMDIR), sname.c_str());
|
||||
}
|
||||
475
idasdk76/module/m32r/reg.cpp
Normal file
475
idasdk76/module/m32r/reg.cpp
Normal file
@@ -0,0 +1,475 @@
|
||||
|
||||
#include "m32r.hpp"
|
||||
#include <ieee.h>
|
||||
int data_id;
|
||||
|
||||
// m32r register names
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"R0", "R1", "R2", "R3", "R4",
|
||||
"R5", "R6", "R7", "R8", "R9",
|
||||
"R10", "R11", "R12", "R13", "R14", "R15",
|
||||
"CR0", "CR1", "CR2", "CR3", "CR6",
|
||||
"PC",
|
||||
"A0", "A1",
|
||||
"CR4", "CR5", "CR7", "CR8", "CR9",
|
||||
"CR10", "CR11", "CR12", "CR13", "CR14", "CR15",
|
||||
"cs", "ds" // required by IDA kernel
|
||||
};
|
||||
static const char *const RegNames_alias[] =
|
||||
{
|
||||
"R0", "R1", "R2", "R3", "R4",
|
||||
"R5", "R6", "R7", "R8", "R9",
|
||||
"R10", "R11", "R12", "fp", "lr", "sp",
|
||||
"psw", "cbr", "spi", "spu", "bpc",
|
||||
"PC",
|
||||
"A0", "A1",
|
||||
"CR4", "CR5", "fpsr", "CR8", "CR9",
|
||||
"CR10", "CR11", "CR12", "CR13", "CR14", "CR15",
|
||||
"cs", "ds" // required by IDA kernel
|
||||
};
|
||||
|
||||
static char const cfgname[] = "m32r.cfg";
|
||||
|
||||
void m32r_iohandler_t::get_cfg_filename(char *buf, size_t bufsize)
|
||||
{
|
||||
qstrncpy(buf, cfgname, bufsize);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static int idaapi choose_device(int, form_actions_t &fa)
|
||||
{
|
||||
m32r_t &pm = *(m32r_t *)fa.get_ud();
|
||||
// we do not respect the IDB_LOADED flag at this point
|
||||
// should we fix it?
|
||||
if ( choose_ioport_device(&pm.ioh.device, cfgname) )
|
||||
pm.ioh.set_device_name(pm.ioh.device.c_str(), IORESP_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// read all procmod data from the idb
|
||||
void m32r_t::load_from_idb()
|
||||
{
|
||||
idpflags = (uint32)helper.altval(-1);
|
||||
handle_new_flags(/*save*/ false);
|
||||
ioh.restore_device();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void m32r_t::handle_new_flags(bool save)
|
||||
{
|
||||
// patch the RegNames[] array according to the use_reg_aliases parameter
|
||||
if ( use_reg_aliases() )
|
||||
ph.reg_names = RegNames_alias;
|
||||
else
|
||||
ph.reg_names = RegNames;
|
||||
if ( save )
|
||||
save_idpflags();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// This function (called when opening the module related configuration in
|
||||
// the general options) will create a dialog box asking the end-user if he
|
||||
// wants to use synthetic instructions and register aliases.
|
||||
const char *m32r_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool idb_loaded)
|
||||
{
|
||||
short opt_subs = 0;
|
||||
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
|
||||
if ( use_synthetic_insn() )
|
||||
opt_subs |= 1;
|
||||
if ( use_reg_aliases() )
|
||||
opt_subs |= 2;
|
||||
|
||||
static const char form[] =
|
||||
"HELP\n"
|
||||
"Mitsubishi 32-Bit (m32r) related options :\n"
|
||||
"\n"
|
||||
" Use synthetic instructions\n"
|
||||
"\n"
|
||||
" If this option is on, IDA will simplify instructions and replace\n"
|
||||
" them by synthetic pseudo-instructions.\n"
|
||||
"\n"
|
||||
" For example,\n"
|
||||
"\n"
|
||||
" bc label1 ; 8 bits offset \n"
|
||||
" bc label2 ; 24 bits offset \n"
|
||||
" ldi r1, #0xF \n"
|
||||
" ldi r2, #0x123456 \n"
|
||||
" st r3, @-sp \n"
|
||||
" ld r4, @sp+ \n"
|
||||
"\n"
|
||||
" will be replaced by\n"
|
||||
"\n"
|
||||
" bc.s label1 \n"
|
||||
" bc.l label2 \n"
|
||||
" ldi8 r1, #0xF \n"
|
||||
" ldi24 r2, #0x123456 \n"
|
||||
" push r3 \n"
|
||||
" pop r4 \n"
|
||||
"\n"
|
||||
" Use registers aliases\n"
|
||||
"\n"
|
||||
" If checked, IDA will use aliases names for the following registers :\n"
|
||||
"\n"
|
||||
" r13 -> fp \n"
|
||||
" r14 -> lr \n"
|
||||
" r15 -> sp \n"
|
||||
" cr0 -> psw \n"
|
||||
" cr1 -> cbr \n"
|
||||
" cr2 -> spi \n"
|
||||
" cr3 -> spu \n"
|
||||
" cr6 -> bpc \n"
|
||||
"\n"
|
||||
"ENDHELP\n"
|
||||
"m32r related options\n"
|
||||
"%*\n"
|
||||
"<##Substitutions"
|
||||
"#For example, use bc.s instead of 8-Bit bc instructions#Use ~s~ynthetic instructions:C>"
|
||||
"<#For example, use fp instead or r14#Use registers ~a~liases:C>>\n\n\n\n"
|
||||
"<~C~hoose device name:B:0::>"
|
||||
"\n\n\n";
|
||||
|
||||
ask_form(form, this, &opt_subs, choose_device);
|
||||
|
||||
idpflags = 0; // reset the configuration
|
||||
if ( opt_subs & 1 )
|
||||
idpflags |= IDP_SYNTHETIC;
|
||||
if ( opt_subs & 2 )
|
||||
idpflags |= IDP_REG_ALIASES;
|
||||
|
||||
handle_new_flags(idb_loaded);
|
||||
// DEVICE was saved in choose_device()
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
// returns a pointer to a ioport_t object if address was found in the config file.
|
||||
// otherwise, returns NULL.
|
||||
const ioport_t *m32r_t::find_sym(ea_t address)
|
||||
{
|
||||
return find_ioport(ioh.ports, address);
|
||||
}
|
||||
|
||||
// GNU Assembler description
|
||||
static const asm_t gnu_asm =
|
||||
{
|
||||
AS_COLON
|
||||
|ASH_HEXF3 // hex 0x123 format
|
||||
|ASB_BINF3 // bin 0b010 format
|
||||
// don't display the final 0 in string declarations
|
||||
|AS_ASCIIZ | AS_ASCIIC | AS_1TEXT,
|
||||
0,
|
||||
"m32r GNU Assembler",
|
||||
0,
|
||||
NULL, // no headers
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".string", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".short", // word directive
|
||||
".word", // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
|
||||
// Although the M32R/X/D has no hardware floating point,
|
||||
// the '.float' and '.double' directives generate IEEE-format
|
||||
// floating-point values for compatibility with other development tools.
|
||||
|
||||
".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
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
".global", // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"!", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
0, // flag2 ???
|
||||
NULL, // comment close string
|
||||
NULL, // low8 op
|
||||
NULL, // high8 op
|
||||
"LOW(%s)", // low16 op
|
||||
"HIGH(%s)" // high16 op
|
||||
};
|
||||
|
||||
// As this time, we only support the GNU assembler.
|
||||
static const asm_t *const asms[] = { &gnu_asm, NULL };
|
||||
|
||||
// Short and long names for our module
|
||||
#define FAMILY "Mitsubishi 32-BIT family:"
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"m32r",
|
||||
"m32rx",
|
||||
NULL
|
||||
};
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Mitsubishi 32-BIT family",
|
||||
"Mitsubishi 32-BIT family (extended)",
|
||||
NULL
|
||||
};
|
||||
|
||||
// Opcodes of "return" instructions. This information will be used in 2 ways:
|
||||
// - if an instruction has the "return" opcode, its autogenerated label
|
||||
// will be "locret" rather than "loc".
|
||||
// - IDA will use the first "return" opcode to create empty subroutines.
|
||||
|
||||
static const uchar retcode_1[] = { 0x1F, 0xCE }; // jmp lr
|
||||
static const uchar retcode_2[] = { 0x10, 0xD6 }; // rte
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// 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(m32r_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ssize_t idaapi m32r_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
helper.create(PROCMOD_NODE_NAME);
|
||||
// this processor is big endian
|
||||
inf_set_be(true);
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
clr_module_data(data_id);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
if ( choose_ioport_device(&ioh.device, cfgname) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
handle_new_flags();
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
ptype = processor_subtype_t(va_arg(va, int));
|
||||
// msg("ptype = %s\n", ptype == prc_m32r ? "m32r" : ptype == prc_m32rx ? "m32rx" : "???");
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
// restore ptype
|
||||
ptype = processor_subtype_t(ph.get_proc_index());
|
||||
//fall through
|
||||
case processor_t::ev_oldfile:
|
||||
load_from_idb();
|
||||
break;
|
||||
|
||||
case processor_t::ev_create_switch_xrefs:
|
||||
{
|
||||
ea_t insn_ea = va_arg(va, ea_t);
|
||||
switch_info_t *si = va_arg(va, switch_info_t *);
|
||||
return m32r_create_switch_xrefs(insn_ea, *si);
|
||||
}
|
||||
|
||||
case processor_t::ev_calc_switch_cases:
|
||||
{
|
||||
casevec_t *casevec = va_arg(va, casevec_t *);
|
||||
eavec_t *targets = va_arg(va, eavec_t *);
|
||||
ea_t insn_ea = va_arg(va, ea_t);
|
||||
switch_info_t *si = va_arg(va, switch_info_t *);
|
||||
return m32r_calc_switch_cases(casevec, targets, insn_ea, *si);
|
||||
}
|
||||
|
||||
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 *);
|
||||
m32r_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
m32r_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 *);
|
||||
m32r_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_can_have_type:
|
||||
{
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return can_have_type(*op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_is_sp_based:
|
||||
{
|
||||
int *mode = va_arg(va, int *);
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
*mode = is_sp_based(*insn, *op);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_create_func_frame:
|
||||
{
|
||||
func_t *pfn = va_arg(va, func_t *);
|
||||
create_func_frame(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_get_frame_retsize:
|
||||
{
|
||||
int *frsize = va_arg(va, int *);
|
||||
const func_t *pfn = va_arg(va, const func_t *);
|
||||
*frsize = m32r_get_frame_retsize(pfn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_M32R, // id
|
||||
// flag
|
||||
PR_RNAMESOK // can use register names for byte names
|
||||
| PR_BINMEM // The module creates RAM/ROM segments for binary files
|
||||
// (the kernel shouldn't ask the user about their sizes and addresses)
|
||||
| PR_USE32
|
||||
| PR_DEFSEG32,
|
||||
// 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,m32r_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
|
||||
m32r_rte, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
};
|
||||
Reference in New Issue
Block a user