update to ida 7.6, add builds

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

View File

@@ -0,0 +1,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;
}

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

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

View 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

File diff suppressed because it is too large Load Diff

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

View 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

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

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