// SPDX-FileCopyrightText: 2022 Dhruv Maroo <dhruvmaru007@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only

#include "common.h"

// Opcode lookup list
const SHOpRaw sh_op_lookup[] = {
	/* fixed-point transfer instructions */
	{ "mov", SH_OP_MOV, OPCODE(e, N, I, I), 0x0fff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_S), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(9, N, D, D), 0x0fff, SH_SCALING_W, { ADDR(NIB0, SH_PC_RELATIVE_DISP), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(d, N, D, D), 0x0fff, SH_SCALING_L, { ADDR(NIB0, SH_PC_RELATIVE_DISP), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov", SH_OP_MOV, OPCODE(6, N, M, 3), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(2, N, M, 0), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(2, N, M, 1), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(2, N, M, 2), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(6, N, M, 0), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_INDIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(6, N, M, 1), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_INDIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(6, N, M, 2), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_INDIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(2, N, M, 4), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(2, N, M, 5), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(2, N, M, 6), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(6, N, M, 4), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_INDIRECT_I), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(6, N, M, 5), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_INDIRECT_I), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(6, N, M, 6), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_INDIRECT_I), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(8, 0, N, D), 0x00ff, SH_SCALING_B, { PARAM(R0, SH_REG_DIRECT), ADDR(NIB0, SH_REG_INDIRECT_DISP) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(8, 1, N, D), 0x00ff, SH_SCALING_W, { PARAM(R0, SH_REG_DIRECT), ADDR(NIB0, SH_REG_INDIRECT_DISP) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(1, N, M, D), 0x0fff, SH_SCALING_L, { /*dummy values*/ ADDR(NIB0, SH_REG_DIRECT), ADDR(NIB0, SH_REG_INDIRECT_DISP) }, SH_ARCH_COMMON },
	// ^ Just this instruction is kinda weird, so needs to be taken care of specially
	{ "mov.b", SH_OP_MOV, OPCODE(8, 4, M, D), 0x00ff, SH_SCALING_B, { ADDR(NIB0, SH_REG_INDIRECT_DISP), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(8, 5, M, D), 0x00ff, SH_SCALING_W, { ADDR(NIB0, SH_REG_INDIRECT_DISP), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(5, N, M, D), 0x0fff, SH_SCALING_L, { ADDR(NIB0, SH_REG_INDIRECT_DISP), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(0, N, M, 4), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_INDEXED) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(0, N, M, 5), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_INDEXED) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(0, N, M, 6), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_INDEXED) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(0, N, M, c), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_INDIRECT_INDEXED), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(0, N, M, d), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_INDIRECT_INDEXED), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(0, N, M, e), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_INDIRECT_INDEXED), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(c, 0, D, D), 0x00ff, SH_SCALING_B, { PARAM(R0, SH_REG_DIRECT), ADDR(NIB0, SH_GBR_INDIRECT_DISP) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(c, 1, D, D), 0x00ff, SH_SCALING_W, { PARAM(R0, SH_REG_DIRECT), ADDR(NIB0, SH_GBR_INDIRECT_DISP) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(c, 2, D, D), 0x00ff, SH_SCALING_L, { PARAM(R0, SH_REG_DIRECT), ADDR(NIB0, SH_GBR_INDIRECT_DISP) }, SH_ARCH_COMMON },
	{ "mov.b", SH_OP_MOV, OPCODE(c, 4, D, D), 0x00ff, SH_SCALING_B, { ADDR(NIB0, SH_GBR_INDIRECT_DISP), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.w", SH_OP_MOV, OPCODE(c, 5, D, D), 0x00ff, SH_SCALING_W, { ADDR(NIB0, SH_GBR_INDIRECT_DISP), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mov.l", SH_OP_MOV, OPCODE(c, 6, D, D), 0x00ff, SH_SCALING_L, { ADDR(NIB0, SH_GBR_INDIRECT_DISP), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mova", SH_OP_MOV, OPCODE(c, 7, D, D), 0x00ff, SH_SCALING_L, { ADDR(NIB0, SH_PC_RELATIVE_DISP), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "movt", SH_OP_MOVT, OPCODE(0, N, 2, 9), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "swap.b", SH_OP_SWAP, OPCODE(6, N, M, 8), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "swap.w", SH_OP_SWAP, OPCODE(6, N, M, 9), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "xtrct", SH_OP_XTRCT, OPCODE(2, N, M, d), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },

	/* arithmetic operation instructions */
	{ "add", SH_OP_ADD, OPCODE(3, N, M, c), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "add", SH_OP_ADD, OPCODE(7, N, I, I), 0x0fff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_S), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "addc", SH_OP_ADDC, OPCODE(3, N, M, e), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "addv", SH_OP_ADDV, OPCODE(3, N, M, f), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/eq", SH_OP_CMP_EQ, OPCODE(8, 8, I, I), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_S), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/eq", SH_OP_CMP_EQ, OPCODE(3, N, M, 0), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/hs", SH_OP_CMP_HS, OPCODE(3, N, M, 2), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/ge", SH_OP_CMP_GE, OPCODE(3, N, M, 3), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/hi", SH_OP_CMP_HI, OPCODE(3, N, M, 6), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/gt", SH_OP_CMP_GT, OPCODE(3, N, M, 7), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "cmp/pz", SH_OP_CMP_PZ, OPCODE(4, N, 1, 1), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "cmp/pl", SH_OP_CMP_PL, OPCODE(4, N, 1, 5), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "cmp/str", SH_OP_CMP_STR, OPCODE(2, N, M, c), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "div1", SH_OP_DIV1, OPCODE(3, N, M, 4), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "div0s", SH_OP_DIV0S, OPCODE(2, N, M, 7), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "div0u", SH_OP_DIV0U, OPCODE(0, 0, 1, 9), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "dmuls.l", SH_OP_DMULS, OPCODE(3, N, M, d), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "dmulu.l", SH_OP_DMULU, OPCODE(3, N, M, 5), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "dt", SH_OP_DT, OPCODE(4, N, 1, 0), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "exts.b", SH_OP_EXTS, OPCODE(6, N, M, e), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "exts.w", SH_OP_EXTS, OPCODE(6, N, M, f), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "extu.b", SH_OP_EXTU, OPCODE(6, N, M, c), 0x0ff0, SH_SCALING_B, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "extu.w", SH_OP_EXTU, OPCODE(6, N, M, d), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mac.l", SH_OP_MAC, OPCODE(0, N, M, f), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_INDIRECT_I), ADDR(NIB2, SH_REG_INDIRECT_I) }, SH_ARCH_COMMON },
	{ "mac.w", SH_OP_MAC, OPCODE(4, N, M, f), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_INDIRECT_I), ADDR(NIB2, SH_REG_INDIRECT_I) }, SH_ARCH_COMMON },
	{ "mul.l", SH_OP_MUL, OPCODE(0, N, M, 7), 0x0ff0, SH_SCALING_L, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "muls.w", SH_OP_MULS, OPCODE(2, N, M, f), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "mulu.w", SH_OP_MULU, OPCODE(2, N, M, e), 0x0ff0, SH_SCALING_W, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "neg", SH_OP_NEG, OPCODE(6, N, M, b), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "negc", SH_OP_NEGC, OPCODE(6, N, M, a), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "sub", SH_OP_SUB, OPCODE(3, N, M, 8), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "subc", SH_OP_SUBC, OPCODE(3, N, M, a), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "subv", SH_OP_SUBV, OPCODE(3, N, M, b), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },

	/* logic operation instructions */
	{ "and", SH_OP_AND, OPCODE(2, N, M, 9), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "and", SH_OP_AND, OPCODE(c, 9, I, I), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "and.b", SH_OP_AND, OPCODE(c, d, I, I), 0x00ff, SH_SCALING_B, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_GBR_INDIRECT_INDEXED) }, SH_ARCH_COMMON },
	{ "not", SH_OP_NOT, OPCODE(6, N, M, 7), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "or", SH_OP_OR, OPCODE(2, N, M, b), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "or", SH_OP_OR, OPCODE(c, b, I, I), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "or.b", SH_OP_OR, OPCODE(c, f, I, I), 0x00ff, SH_SCALING_B, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_GBR_INDIRECT_INDEXED) }, SH_ARCH_COMMON },
	{ "tas.b", SH_OP_TAS, OPCODE(4, N, 1, b), 0x0f00, SH_SCALING_B, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "tst", SH_OP_TST, OPCODE(2, N, M, 8), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "tst", SH_OP_TST, OPCODE(c, 8, I, I), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "tst.b", SH_OP_TST, OPCODE(c, c, I, I), 0x00ff, SH_SCALING_B, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_GBR_INDIRECT_INDEXED) }, SH_ARCH_COMMON },
	{ "xor", SH_OP_XOR, OPCODE(2, N, M, a), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "xor", SH_OP_XOR, OPCODE(c, a, I, I), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "xor.b", SH_OP_XOR, OPCODE(c, e, I, I), 0x00ff, SH_SCALING_B, { ADDR(NIB0, SH_IMM_U), PARAM(R0, SH_GBR_INDIRECT_INDEXED) }, SH_ARCH_COMMON },

	/* shift instructions */
	{ "rotl", SH_OP_ROTL, OPCODE(4, N, 0, 4), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "rotr", SH_OP_ROTR, OPCODE(4, N, 0, 5), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "rotcl", SH_OP_ROTCL, OPCODE(4, N, 2, 4), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "rotcr", SH_OP_ROTCR, OPCODE(4, N, 2, 5), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shad", SH_OP_SHAD, OPCODE(4, N, M, c), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "shal", SH_OP_SHAL, OPCODE(4, N, 2, 0), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shar", SH_OP_SHAR, OPCODE(4, N, 2, 1), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shld", SH_OP_SHLD, OPCODE(4, N, M, d), 0x0ff0, SH_SCALING_INVALID, { ADDR(NIB1, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "shll", SH_OP_SHLL, OPCODE(4, N, 0, 0), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shlr", SH_OP_SHLR, OPCODE(4, N, 0, 1), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shll2", SH_OP_SHLL2, OPCODE(4, N, 0, 8), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shlr2", SH_OP_SHLR2, OPCODE(4, N, 0, 9), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shll8", SH_OP_SHLL8, OPCODE(4, N, 1, 8), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shlr8", SH_OP_SHLR8, OPCODE(4, N, 1, 9), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shll16", SH_OP_SHLL16, OPCODE(4, N, 2, 8), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "shlr16", SH_OP_SHLR16, OPCODE(4, N, 2, 9), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), NOPARAM }, SH_ARCH_COMMON },

	/* branch instructions */
	{ "bf", SH_OP_BF, OPCODE(8, b, D, D), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_PC_RELATIVE8), NOPARAM }, SH_ARCH_COMMON },
	{ "bf/s", SH_OP_BFS, OPCODE(8, f, D, D), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_PC_RELATIVE8), NOPARAM }, SH_ARCH_COMMON },
	{ "bt", SH_OP_BT, OPCODE(8, 9, D, D), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_PC_RELATIVE8), NOPARAM }, SH_ARCH_COMMON },
	{ "bt/s", SH_OP_BTS, OPCODE(8, d, D, D), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_PC_RELATIVE8), NOPARAM }, SH_ARCH_COMMON },
	{ "bra", SH_OP_BRA, OPCODE(a, D, D, D), 0x0fff, SH_SCALING_INVALID, { ADDR(NIB0, SH_PC_RELATIVE12), NOPARAM }, SH_ARCH_COMMON },
	{ "braf", SH_OP_BRAF, OPCODE(0, N, 2, 3), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_PC_RELATIVE_REG), NOPARAM }, SH_ARCH_COMMON },
	{ "bsr", SH_OP_BSR, OPCODE(b, D, D, D), 0x0fff, SH_SCALING_INVALID, { ADDR(NIB0, SH_PC_RELATIVE12), NOPARAM }, SH_ARCH_COMMON },
	{ "bsrf", SH_OP_BSRF, OPCODE(0, N, 0, 3), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_PC_RELATIVE_REG), NOPARAM }, SH_ARCH_COMMON },
	{ "jmp", SH_OP_JMP, OPCODE(4, N, 2, b), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "jsr", SH_OP_JSR, OPCODE(4, N, 0, b), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "rts", SH_OP_RTS, OPCODE(0, 0, 0, b), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },

	/* system control instructions */
	{ "clrmac", SH_OP_CLRMAC, OPCODE(0, 0, 2, 8), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "clrs", SH_OP_CLRS, OPCODE(0, 0, 4, 8), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "clrt", SH_OP_CLRT, OPCODE(0, 0, 0, 8), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, 0, e), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(SR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, 1, e), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(GBR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, 2, e), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(VBR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, 3, e), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(SSR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, 4, e), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(SPC, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, f, a), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(DBR, SH_REG_DIRECT) }, SH_ARCH_SH4 },
	{ "ldc", SH_OP_LDC, OPCODE(4, M, N, e), 0x0f70, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), ADDRBITS(NIB1, SH_REG_DIRECT, 3) }, SH_ARCH_COMMON },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, 0, 7), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(SR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, 1, 7), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(GBR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, 2, 7), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(VBR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, 3, 7), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(SSR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, 4, 7), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(SPC, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, f, 6), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(DBR, SH_REG_DIRECT) }, SH_ARCH_SH4 },
	{ "ldc.l", SH_OP_LDC, OPCODE(4, M, N, 7), 0x0f70, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), ADDRBITS(NIB1, SH_REG_DIRECT, 3) }, SH_ARCH_COMMON },
	{ "lds", SH_OP_LDS, OPCODE(4, M, 0, a), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(MACH, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "lds", SH_OP_LDS, OPCODE(4, M, 1, a), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(MACL, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "lds", SH_OP_LDS, OPCODE(4, M, 2, a), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_DIRECT), PARAM(PR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "lds.l", SH_OP_LDS, OPCODE(4, M, 0, 6), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(MACH, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "lds.l", SH_OP_LDS, OPCODE(4, M, 1, 6), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(MACL, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "lds.l", SH_OP_LDS, OPCODE(4, M, 2, 6), 0x0f00, SH_SCALING_L, { ADDR(NIB2, SH_REG_INDIRECT_I), PARAM(PR, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "ldtlb", SH_OP_UNIMPL, OPCODE(0, 0, 3, 8), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "movca.l", SH_OP_MOVCA, OPCODE(0, N, c, 3), 0x0f00, SH_SCALING_L, { PARAM(R0, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT) }, SH_ARCH_SH4 },
	{ "nop", SH_OP_NOP, OPCODE(0, 0, 0, 9), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "ocbi", SH_OP_UNIMPL, OPCODE(0, N, 9, 3), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_SH4 },
	{ "ocbp", SH_OP_UNIMPL, OPCODE(0, N, a, 3), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_SH4 },
	{ "ocbwb", SH_OP_UNIMPL, OPCODE(0, N, b, 3), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_SH4 },
	{ "pref", SH_OP_UNIMPL, OPCODE(0, N, 8, 3), 0x0f00, SH_SCALING_INVALID, { ADDR(NIB2, SH_REG_INDIRECT), NOPARAM }, SH_ARCH_COMMON },
	{ "rte", SH_OP_RTE, OPCODE(0, 0, 2, b), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "sets", SH_OP_SETS, OPCODE(0, 0, 5, 8), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "sett", SH_OP_SETT, OPCODE(0, 0, 1, 8), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "sleep", SH_OP_SLEEP, OPCODE(0, 0, 1, b), 0x0000, SH_SCALING_INVALID, { NOPARAM, NOPARAM }, SH_ARCH_COMMON },
	{ "stc", SH_OP_STC, OPCODE(0, M, 0, 2), 0x0f00, SH_SCALING_INVALID, { PARAM(SR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "stc", SH_OP_STC, OPCODE(0, M, 1, 2), 0x0f00, SH_SCALING_INVALID, { PARAM(GBR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "stc", SH_OP_STC, OPCODE(0, M, 2, 2), 0x0f00, SH_SCALING_INVALID, { PARAM(VBR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "stc", SH_OP_STC, OPCODE(0, M, 3, 2), 0x0f00, SH_SCALING_INVALID, { PARAM(SSR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "stc", SH_OP_STC, OPCODE(0, M, 4, 2), 0x0f00, SH_SCALING_INVALID, { PARAM(SPC, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "stc", SH_OP_STC, OPCODE(0, M, 3, a), 0x0f00, SH_SCALING_INVALID, { PARAM(SGR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_SH4 },
	{ "stc", SH_OP_STC, OPCODE(0, M, f, a), 0x0f00, SH_SCALING_INVALID, { PARAM(DBR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_SH4 },
	{ "stc", SH_OP_STC, OPCODE(0, N, M, 2), 0x0f70, SH_SCALING_INVALID, { ADDRBITS(NIB1, SH_REG_DIRECT, 3), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, 0, 3), 0x0f00, SH_SCALING_L, { PARAM(SR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, 1, 3), 0x0f00, SH_SCALING_L, { PARAM(GBR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, 2, 3), 0x0f00, SH_SCALING_L, { PARAM(VBR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, 3, 3), 0x0f00, SH_SCALING_L, { PARAM(SSR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, 4, 3), 0x0f00, SH_SCALING_L, { PARAM(SPC, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, 3, 2), 0x0f00, SH_SCALING_L, { PARAM(SGR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_SH4 },
	{ "stc.l", SH_OP_STC, OPCODE(4, M, f, 2), 0x0f00, SH_SCALING_L, { PARAM(DBR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_SH4 },
	{ "stc.l", SH_OP_STC, OPCODE(4, N, M, 3), 0x0f70, SH_SCALING_L, { ADDRBITS(NIB1, SH_REG_DIRECT, 3), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "sts", SH_OP_STS, OPCODE(0, N, 0, a), 0x0f00, SH_SCALING_INVALID, { PARAM(MACH, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "sts", SH_OP_STS, OPCODE(0, N, 1, a), 0x0f00, SH_SCALING_INVALID, { PARAM(MACL, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "sts", SH_OP_STS, OPCODE(0, N, 2, a), 0x0f00, SH_SCALING_INVALID, { PARAM(PR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_DIRECT) }, SH_ARCH_COMMON },
	{ "sts.l", SH_OP_STS, OPCODE(4, N, 0, 2), 0x0f00, SH_SCALING_L, { PARAM(MACH, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "sts.l", SH_OP_STS, OPCODE(4, N, 1, 2), 0x0f00, SH_SCALING_L, { PARAM(MACL, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "sts.l", SH_OP_STS, OPCODE(4, N, 2, 2), 0x0f00, SH_SCALING_L, { PARAM(PR, SH_REG_DIRECT), ADDR(NIB2, SH_REG_INDIRECT_D) }, SH_ARCH_COMMON },
	{ "trapa", SH_OP_UNIMPL, OPCODE(c, 3, I, I), 0x00ff, SH_SCALING_INVALID, { ADDR(NIB0, SH_IMM_U), NOPARAM }, SH_ARCH_COMMON }

	/* floating-point single-precision instructions */
	// TODO
};

const ut32 OPCODE_NUM = sizeof(sh_op_lookup) / sizeof(SHOpRaw);
