Repository URL to install this package:
|
Version:
9.0~240925-3.fc42 ▾
|
#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 nullptr;
}
//----------------------------------------------------------------------------
// 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 == nullptr )
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;
}