// SPDX-FileCopyrightText: 2014 Fedor Sakharov <fedor.sakharov@gmail.com>
// SPDX-FileCopyrightText: 2025 Billow <billow.fun@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only

#ifndef RZ_H8300_DISAS_H
#define RZ_H8300_DISAS_H

#include <rz_analysis.h>

enum h8300_4bit_opcodes {
	H8300_MOV_4BIT_2 = 0x2,
	H8300_MOV_4BIT_3 = 0x3,
	H8300_ADD_4BIT_8 = 0x8,
	H8300_ADDX_4BIT = 0x9,
	H8300_CMP_4BIT = 0xA,
	H8300_SUBX_4BIT = 0xB,
	H8300_OR_4BIT = 0xC,
	H8300_XOR_4BIT = 0xD,
	H8300_AND_4BIT = 0xE,
	H8300_MOV_4BIT = 0xF,
};

enum h8300_opcodes {
	H8300_NOP = 0x00,
	H8300_SLEEP = 0x01,
	H8300_STC_B = 0x02,
	H8300_LDC = 0x03,
	H8300_ORC = 0x04,
	H8300_XORC = 0x05,
	H8300_ANDC = 0x06,
	H8300_LDC_2 = 0x07,
	H8300_ADD_B = 0x08,
	H8300_ADD_W = 0x09,
	H8300_INC = 0x0A,
	H8300_ADDS = 0x0B,
	H8300_MOV_1 = 0x0C,
	H8300_MOV_2 = 0x0D,
	H8300_ADDX = 0x0E,
	H8300_DAA = 0x0F,
	H8300_SHL = 0x10,
	H8300_SHR = 0x11,
	H8300_ROTL = 0x12,
	H8300_ROTR = 0x13,
	H8300_OR = 0x14,
	H8300_XOR = 0x15,
	H8300_AND = 0x16,
	H8300_NOT_NEG = 0x17,
	H8300_SUB_1 = 0x18,
	H8300_SUB_W = 0x19,
	H8300_DEC = 0x1A,
	H8300_SUBS = 0x1B,
	H8300_CMP_B = 0x1C,
	H8300_CMP_W = 0x1D,
	H8300_SUBX = 0x1E,
	H8300_DAS = 0x1F,
	H8300_BRA = 0x40,
	H8300_BRN = 0x41,
	H8300_BHI = 0x42,
	H8300_BLS = 0x43,
	H8300_BCC = 0x44,
	H8300_BCS = 0x45,
	H8300_BNE = 0x46,
	H8300_BEQ = 0x47,
	H8300_BVC = 0x48,
	H8300_BVS = 0x49,
	H8300_BPL = 0x4A,
	H8300_BMI = 0x4B,
	H8300_BGE = 0x4C,
	H8300_BLT = 0x4D,
	H8300_BGT = 0x4E,
	H8300_BLE = 0x4F,
	H8300_MULXU_B = 0x50,
	H8300_DIVXU = 0x51,
	H8300_RTS = 0x54,
	H8300_BSR = 0x55,
	H8300_RTE = 0x56,
	H8300_JMP_1 = 0x59,
	H8300_JMP_2 = 0x5A,
	H8300_JMP_3 = 0x5B,
	H8300_JSR_1 = 0x5D,
	H8300_JSR_2 = 0x5E,
	H8300_JSR_3 = 0x5F,
	H8300_BSET_1 = 0x60,
	H8300_BNOT_1 = 0x61,
	H8300_BCLR_R2R8 = 0x62,
	H8300_BTST_R2R8 = 0x63,
	H8300_BST_BIST = 0x67,
	H8300_MOV_R82IND16 = 0x68,
	H8300_MOV_IND162R16 = 0x69,
	H8300_MOV_R82ABS16 = 0x6a,
	H8300_MOV_ABS162R16 = 0x6B,
	H8300_MOV_R82RDEC16 = 0x6C,
	H8300_MOV_INDINC162R16 = 0x6D,
	H8300_MOV_R82DISPR16 = 0x6E,
	H8300_MOV_DISP162R16 = 0x6F,
	H8300_BSET_2 = 0x70,
	H8300_BNOT_2 = 0x71,
	H8300_BCLR_IMM2R8 = 0x72,
	H8300_BTST = 0x73,
	H8300_BOR_BIOR = 0x74,
	H8300_BXOR_BIXOR = 0x75,
	H8300_BAND_BIAND = 0x76,
	H8300_BILD_IMM2R8 = 0x77,
	H8300_MOV_IMM162R16 = 0x79,
	H8300_EEPMOV = 0x7B,
	H8300_BIAND_IMM2IND16 = 0x7C,
	H8300_BCLR_R2IND16 = 0x7D,
	H8300_BIAND_IMM2ABS8 = 0x7E,
	H8300_BCLR_R2ABS8 = 0x7F,
};

#define H8300_INSTR_MAXLEN 16
#define H8300_OPS_MAXLEN   64
#define H8300_OPERAND_MAX  8

enum h8300_opcodes_9bit {
	H8300_BST = 0x6700 >> 7,
	H8300_BIST = 0x6780 >> 7,
	H8300_BOR = 0x7400 >> 7,
	H8300_BIOR = 0x7480 >> 7,
	H8300_BXOR = 0x7500 >> 7,
	H8300_BIXOR = 0x7580 >> 7,
	H8300_BAND = 0x7600 >> 7,
	H8300_BIAND = 0x7680 >> 7,
	H8300_BLD = 0x7700 >> 7,
	H8300_BILD = 0x7780 >> 7,
};

typedef enum h8300_insn_id {
	H8300_INSN_INVALID,
	H8300_INSN_MOV_B,
	H8300_INSN_MOV_W,
	H8300_INSN_MOV_L,
	H8300_INSN_MOVFPE,
	H8300_INSN_MOVTPE,
	H8300_INSN_ADDX,
	H8300_INSN_ADD_B,
	H8300_INSN_ADD_W,
	H8300_INSN_ADD_L,
	H8300_INSN_CMP_B,
	H8300_INSN_CMP_W,
	H8300_INSN_CMP_L,
	H8300_INSN_SUBX,
	H8300_INSN_XOR_B,
	H8300_INSN_XOR_W,
	H8300_INSN_XOR_L,
	H8300_INSN_AND_B,
	H8300_INSN_AND_W,
	H8300_INSN_AND_L,
	H8300_INSN_NOP,
	H8300_INSN_SLEEP,
	H8300_INSN_STC_B,
	H8300_INSN_STC_W,
	H8300_INSN_LDC_B,
	H8300_INSN_LDC_W,
	H8300_INSN_ORC,
	H8300_INSN_XORC,
	H8300_INSN_ANDC,
	H8300_INSN_INC_B,
	H8300_INSN_INC_W,
	H8300_INSN_INC_L,
	H8300_INSN_ADDS,
	H8300_INSN_DAA,
	H8300_INSN_SHAL_B,
	H8300_INSN_SHAR_B,
	H8300_INSN_SHLL_B,
	H8300_INSN_SHLR_B,
	H8300_INSN_ROTL_B,
	H8300_INSN_ROTR_B,
	H8300_INSN_ROTXL_B,
	H8300_INSN_ROTXR_B,
	H8300_INSN_ROTL_W,
	H8300_INSN_ROTR_W,
	H8300_INSN_ROTXL_W,
	H8300_INSN_ROTXR_W,
	H8300_INSN_SHAL_W,
	H8300_INSN_SHAR_W,
	H8300_INSN_SHLL_W,
	H8300_INSN_SHLR_W,
	H8300_INSN_ROTL_L,
	H8300_INSN_ROTR_L,
	H8300_INSN_ROTXL_L,
	H8300_INSN_ROTXR_L,
	H8300_INSN_SHAL_L,
	H8300_INSN_SHAR_L,
	H8300_INSN_SHLL_L,
	H8300_INSN_SHLR_L,
	H8300_INSN_NEG_B,
	H8300_INSN_NOT_B,
	H8300_INSN_OR_B,
	H8300_INSN_NEG_W,
	H8300_INSN_NOT_W,
	H8300_INSN_OR_W,
	H8300_INSN_NEG_L,
	H8300_INSN_NOT_L,
	H8300_INSN_OR_L,
	H8300_INSN_SUB_B,
	H8300_INSN_SUB_W,
	H8300_INSN_SUB_L,
	H8300_INSN_DEC_B,
	H8300_INSN_DEC_W,
	H8300_INSN_DEC_L,
	H8300_INSN_SUBS,
	H8300_INSN_DAS,
	H8300_INSN_BRA,
	H8300_INSN_BRN,
	H8300_INSN_BHI,
	H8300_INSN_BLS,
	H8300_INSN_BCC,
	H8300_INSN_BCS,
	H8300_INSN_BNE,
	H8300_INSN_BEQ,
	H8300_INSN_BVC,
	H8300_INSN_BVS,
	H8300_INSN_BPL,
	H8300_INSN_BMI,
	H8300_INSN_BGE,
	H8300_INSN_BLT,
	H8300_INSN_BGT,
	H8300_INSN_BLE,
	H8300_INSN_MULXU_B,
	H8300_INSN_MULXU_W,
	H8300_INSN_MULXS_B,
	H8300_INSN_MULXS_W,
	H8300_INSN_DIVXU_B,
	H8300_INSN_DIVXU_W,
	H8300_INSN_DIVXS_B,
	H8300_INSN_DIVXS_W,
	H8300_INSN_RTS,
	H8300_INSN_BSR,
	H8300_INSN_RTE,
	H8300_INSN_JMP,
	H8300_INSN_JSR,
	H8300_INSN_BSET,
	H8300_INSN_BNOT,
	H8300_INSN_BCLR,
	H8300_INSN_BTST,
	H8300_INSN_BST,
	H8300_INSN_BXOR,
	H8300_INSN_BAND,
	H8300_INSN_BILD,
	H8300_INSN_EEPMOV_B,
	H8300_INSN_EEPMOV_W,
	H8300_INSN_EXTS_W,
	H8300_INSN_EXTS_L,
	H8300_INSN_EXTU_W,
	H8300_INSN_EXTU_L,
	H8300_INSN_BIAND,
	H8300_INSN_BIST,
	H8300_INSN_BOR,
	H8300_INSN_BIOR,
	H8300_INSN_BIXOR,
	H8300_INSN_BLD,
	H8300_INSN_POP_W,
	H8300_INSN_PUSH_W,
	H8300_INSN_POP_L,
	H8300_INSN_PUSH_L,
	H8300_INSN_TRAPA,
} H8300InsnId;

typedef enum {
	H8300_INSN_FORMAT_NONE,
	H8300_INSN_FORMAT_IMM,
	H8300_INSN_FORMAT_R8,
	H8300_INSN_FORMAT_R16,
	H8300_INSN_FORMAT_R32,
	H8300_INSN_FORMAT_ABS,
	H8300_INSN_FORMAT_MI8,
	H8300_INSN_FORMAT_PCREL8,
	H8300_INSN_FORMAT_RI,
	H8300_INSN_FORMAT_R8R8,
	H8300_INSN_FORMAT_R8R16,
	H8300_INSN_FORMAT_R8ABS,
	H8300_INSN_FORMAT_ABSR8,
	H8300_INSN_FORMAT_R16R16,
	H8300_INSN_FORMAT_R16R32,
	H8300_INSN_FORMAT_R32R32,
	H8300_INSN_FORMAT_RIR32,
	H8300_INSN_FORMAT_R32RI,
	H8300_INSN_FORMAT_RINCR32,
	H8300_INSN_FORMAT_R32RDEC,
	H8300_INSN_FORMAT_R16ABS,
	H8300_INSN_FORMAT_ABSR16,
	H8300_INSN_FORMAT_ABSR32,
	H8300_INSN_FORMAT_R32ABS,
	H8300_INSN_FORMAT_RD,
	H8300_INSN_FORMAT_RDR32,
	H8300_INSN_FORMAT_R32RD,
	H8300_INSN_FORMAT_RDR16,
	H8300_INSN_FORMAT_R16RD,
	H8300_INSN_FORMAT_RDR8,
	H8300_INSN_FORMAT_R8RD,
	H8300_INSN_FORMAT_R16RDEC,
	H8300_INSN_FORMAT_RINCR16,
	H8300_INSN_FORMAT_R8RDEC,
	H8300_INSN_FORMAT_RPOSTINC,
	H8300_INSN_FORMAT_RPREDEC,
	H8300_INSN_FORMAT_RINCR8,
	H8300_INSN_FORMAT_R16RI,
	H8300_INSN_FORMAT_RIR16,
	H8300_INSN_FORMAT_R8RI,
	H8300_INSN_FORMAT_RIR8,
	H8300_INSN_FORMAT_IMMR8,
	H8300_INSN_FORMAT_IMMR16,
	H8300_INSN_FORMAT_IMMR32,
	H8300_INSN_FORMAT_IMMRI,
	H8300_INSN_FORMAT_IMMABS,
	H8300_INSN_FORMAT_R8IMM,
} H8300InsnFormat;

typedef enum {
	H8300_OP_NONE,
	H8300_OP_R8,
	H8300_OP_R16,
	H8300_OP_R32,
	H8300_OP_IMM,
	H8300_OP_ABS,
	H8300_OP_PCREL,
	H8300_OP_MI8,
	H8300_OP_RD,
	H8300_OP_RI,
	H8300_OP_RPOSTINC, ///< Register indirect with post-increment @Rn+
	H8300_OP_RPREDEC, ///< Register indirect with pre-decrement @–Rn
	H8300_OP_CCR,
} H8300OperandType;

/**
 * Register Specification
 * 1. 16 x 8-bit registers: R0H-R7H + E0L-E7L
 * 2. 16 x 16-bit registers: R0-R7 + E0-E7
 * 3. 8 x 32-bit registers: ER0-ER7
 */
typedef enum h8300_registers_t {
	H8300_REG_INVALID = 0,
	H8300_R0H,
	H8300_R1H,
	H8300_R2H,
	H8300_R3H,
	H8300_R4H,
	H8300_R5H,
	H8300_R6H,
	H8300_R7H,
	H8300_R0L,
	H8300_R1L,
	H8300_R2L,
	H8300_R3L,
	H8300_R4L,
	H8300_R5L,
	H8300_R6L,
	H8300_R7L,
#define H8300_REG8_BEGIN H8300_R0H
#define H8300_REG8_END   H8300_E7L
	H8300_R0,
	H8300_R1,
	H8300_R2,
	H8300_R3,
	H8300_R4,
	H8300_R5,
	H8300_R6,
	H8300_R7,
	H8300_E0,
	H8300_E1,
	H8300_E2,
	H8300_E3,
	H8300_E4,
	H8300_E5,
	H8300_E6,
	H8300_E7,
#define H8300_REG16_BEGIN H8300_R0
#define H8300_REG16_END   H8300_E7

	H8300_ER0,
	H8300_ER1,
	H8300_ER2,
	H8300_ER3,
	H8300_ER4,
	H8300_ER5,
	H8300_ER6,
	H8300_ER7,
#define H8300_REG32_BEGIN H8300_ER0
#define H8300_REG32_END   H8300_ER7
#define H8300_SP          H8300_R7
#define H8300H_SP         H8300_ER7
} H8300Register;

typedef struct {
	H8300OperandType typ;
	enum {
		H8300Operand_UNK,
		H8300Operand_8,
		H8300Operand_16,
		H8300Operand_32,
	} width;
	union {
		ut8 reg;
		ut32 imm;
		st32 disp;
		struct {
			ut8 reg;
			st32 disp;
		} rd;
	};
} H8300Operand;

typedef enum {
	CPU_H8300H,
	CPU_H8300,
	CPU_H8300L,
} H8300CpuType;

typedef struct h8300_instruction_t {
	H8300CpuType cpu_type;
	H8300InsnId id;
	H8300InsnFormat fmt;
	H8300Operand ops[H8300_OPERAND_MAX];
	ut8 ops_count;
	ut8 size;
	ut64 pc;
} H8300Instruction;

typedef struct h8300_ops_str_t {
	char instr[H8300_INSTR_MAXLEN];
	char ops_str[H8300_OPS_MAXLEN];
} H8300InstructionStr;

int h8300_analyze_op_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf);
int h8300_analyze_op_il(RzAnalysis *a, RzAnalysisOp *op, H8300Instruction *cmd);
int h8300_decode_command(const ut8 *instr, ut64 len, H8300Instruction *cmd, ut64 pc, const char *cpu);
bool h8300_make_opstr(H8300Instruction *cmd, H8300InstructionStr *ins_str);
RzAnalysisILConfig *h8300_il_config(RzAnalysis *a);
H8300CpuType h8300_cpu_type(const char *cpu);

const char *h8300_get_opcode_name(H8300InsnId id);
const char *h8300_get_register_name(H8300Register id);

#endif /* H8300_DISAS_H */
