#ifndef CAPSTONE_RISCV_H
#define CAPSTONE_RISCV_H

/* Capstone Disassembly Engine */
/* RISC-V Backend By Rodrigo Cortes Porto <porto703@gmail.com> &
   Shawn Chang <citypw@gmail.com>, HardenedLinux@2018 */

#ifdef __cplusplus
extern "C" {
#endif

#if !defined(_MSC_VER) || !defined(_KERNEL_MODE)
#include <stdint.h>
#endif

#include "platform.h"
#include "cs_operand.h"

// GCC MIPS toolchain has a default macro called "mips" which breaks
// compilation
//#undef riscv

#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif

//> Operand type for instruction's operands
typedef enum riscv_op_type {
	RISCV_OP_INVALID = CS_OP_INVALID, // = CS_OP_INVALID (Uninitialized).
	RISCV_OP_REG = CS_OP_REG, // = CS_OP_REG (Register operand).
	RISCV_OP_IMM = CS_OP_IMM, // = CS_OP_IMM (Immediate operand).
	RISCV_OP_MEM = CS_OP_MEM, // = CS_OP_MEM (Memory operand).
} riscv_op_type;

// Instruction's operand referring to memory
// This is associated with RISCV_OP_MEM operand type above
typedef struct riscv_op_mem {
	unsigned int base;	// base register
	int64_t disp;	// displacement/offset value
} riscv_op_mem;

// Instruction operand
typedef struct cs_riscv_op {
	riscv_op_type type;	// operand type
	union {
		unsigned int reg;	// register value for REG operand
		int64_t imm;		// immediate value for IMM operand
		riscv_op_mem mem;	// base/disp value for MEM operand
	};
	uint8_t access; ///< How is this operand accessed? (READ, WRITE or READ|WRITE)
} cs_riscv_op;

#define NUM_RISCV_OPS 8

// Instruction structure
typedef struct cs_riscv {
	// Does this instruction need effective address or not.
	bool need_effective_addr;
	// Number of operands of this instruction,
	// or 0 when instruction has no operand.
	uint8_t op_count;
	cs_riscv_op operands[NUM_RISCV_OPS]; // operands for this instruction.
} cs_riscv;

//> RISCV registers
typedef enum riscv_reg {
	RISCV_REG_INVALID = 0,
	//> General purpose registers
	RISCV_REG_X0,			// "zero"
	RISCV_REG_ZERO = RISCV_REG_X0, 	// "zero"
	RISCV_REG_X1, 			// "ra"
	RISCV_REG_RA   = RISCV_REG_X1, 	// "ra"
	RISCV_REG_X2, 			// "sp"
	RISCV_REG_SP   = RISCV_REG_X2, 	// "sp"
	RISCV_REG_X3, 			// "gp"
	RISCV_REG_GP   = RISCV_REG_X3, 	// "gp"
	RISCV_REG_X4, 			// "tp"
	RISCV_REG_TP   = RISCV_REG_X4,	// "tp"
	RISCV_REG_X5, 			// "t0"
	RISCV_REG_T0   = RISCV_REG_X5, 	// "t0"
	RISCV_REG_X6, 			// "t1"
	RISCV_REG_T1   = RISCV_REG_X6, 	// "t1"
	RISCV_REG_X7, 			// "t2"
	RISCV_REG_T2   = RISCV_REG_X7, 	// "t2"
	RISCV_REG_X8, 			// "s0/fp"
	RISCV_REG_S0   = RISCV_REG_X8,	// "s0"
	RISCV_REG_FP   = RISCV_REG_X8,	// "fp"
	RISCV_REG_X9, 			// "s1"
	RISCV_REG_S1   = RISCV_REG_X9, 	// "s1"
	RISCV_REG_X10,			// "a0"
	RISCV_REG_A0   = RISCV_REG_X10,	// "a0"
	RISCV_REG_X11,			// "a1"
	RISCV_REG_A1   = RISCV_REG_X11,	// "a1"
	RISCV_REG_X12,			// "a2"
	RISCV_REG_A2   = RISCV_REG_X12,	// "a2"
	RISCV_REG_X13,			// "a3"
	RISCV_REG_A3   = RISCV_REG_X13,	// "a3"
	RISCV_REG_X14,			// "a4"
	RISCV_REG_A4   = RISCV_REG_X14,	// "a4"
	RISCV_REG_X15,			// "a5"
	RISCV_REG_A5   = RISCV_REG_X15, // "a5"
	RISCV_REG_X16,			// "a6"
	RISCV_REG_A6   = RISCV_REG_X16,	// "a6"
	RISCV_REG_X17,			// "a7"
	RISCV_REG_A7   = RISCV_REG_X17,	// "a7"
	RISCV_REG_X18,			// "s2"
	RISCV_REG_S2   = RISCV_REG_X18,	// "s2"
	RISCV_REG_X19,			// "s3"
	RISCV_REG_S3   = RISCV_REG_X19, // "s3"
	RISCV_REG_X20,			// "s4"
	RISCV_REG_S4   = RISCV_REG_X20,	// "s4"
	RISCV_REG_X21,			// "s5"
	RISCV_REG_S5   = RISCV_REG_X21,	// "s5"
	RISCV_REG_X22,			// "s6"
	RISCV_REG_S6   = RISCV_REG_X22,	// "s6"
	RISCV_REG_X23,			// "s7"
	RISCV_REG_S7   = RISCV_REG_X23,	// "s7"
	RISCV_REG_X24,			// "s8"
	RISCV_REG_S8   = RISCV_REG_X24,	// "s8"
	RISCV_REG_X25,			// "s9"
	RISCV_REG_S9   = RISCV_REG_X25,	// "s9"
	RISCV_REG_X26,			// "s10"
	RISCV_REG_S10  = RISCV_REG_X26,	// "s10"
	RISCV_REG_X27,			// "s11"
	RISCV_REG_S11  = RISCV_REG_X27, // "s11"
	RISCV_REG_X28,			// "t3"
	RISCV_REG_T3   = RISCV_REG_X28,	// "t3"
	RISCV_REG_X29,			// "t4"
	RISCV_REG_T4   = RISCV_REG_X29, // "t4"
	RISCV_REG_X30,			// "t5"
	RISCV_REG_T5   = RISCV_REG_X30,	// "t5"
	RISCV_REG_X31,			// "t6"
	RISCV_REG_T6   = RISCV_REG_X31,	// "t6"

	//> Floating-point registers
	RISCV_REG_F0_32,		// "ft0"
	RISCV_REG_F0_64,		// "ft0"
	RISCV_REG_F1_32,		// "ft1"
	RISCV_REG_F1_64,		// "ft1"
	RISCV_REG_F2_32,		// "ft2"
	RISCV_REG_F2_64,		// "ft2"
	RISCV_REG_F3_32,		// "ft3"
	RISCV_REG_F3_64,		// "ft3"
	RISCV_REG_F4_32,		// "ft4"
	RISCV_REG_F4_64,		// "ft4"
	RISCV_REG_F5_32,		// "ft5"
	RISCV_REG_F5_64,		// "ft5"
	RISCV_REG_F6_32,		// "ft6"
	RISCV_REG_F6_64,		// "ft6"
	RISCV_REG_F7_32,		// "ft7"
	RISCV_REG_F7_64,		// "ft7"
	RISCV_REG_F8_32,		// "fs0"
	RISCV_REG_F8_64,		// "fs0"
	RISCV_REG_F9_32,		// "fs1"
	RISCV_REG_F9_64,		// "fs1"
	RISCV_REG_F10_32,		// "fa0"
	RISCV_REG_F10_64,		// "fa0"
	RISCV_REG_F11_32,		// "fa1"
	RISCV_REG_F11_64,		// "fa1"
	RISCV_REG_F12_32,		// "fa2"
	RISCV_REG_F12_64,		// "fa2"
	RISCV_REG_F13_32,		// "fa3"
	RISCV_REG_F13_64,		// "fa3"
	RISCV_REG_F14_32,		// "fa4"
	RISCV_REG_F14_64,		// "fa4"
	RISCV_REG_F15_32,		// "fa5"
	RISCV_REG_F15_64,		// "fa5"
	RISCV_REG_F16_32,		// "fa6"
	RISCV_REG_F16_64,		// "fa6"
	RISCV_REG_F17_32,		// "fa7"
	RISCV_REG_F17_64,		// "fa7"
	RISCV_REG_F18_32,		// "fs2"
	RISCV_REG_F18_64,		// "fs2"
	RISCV_REG_F19_32,		// "fs3"
	RISCV_REG_F19_64,		// "fs3"
	RISCV_REG_F20_32,		// "fs4"
	RISCV_REG_F20_64,		// "fs4"
	RISCV_REG_F21_32,		// "fs5"
	RISCV_REG_F21_64,		// "fs5"
	RISCV_REG_F22_32,		// "fs6"
	RISCV_REG_F22_64,		// "fs6"
	RISCV_REG_F23_32,		// "fs7"
	RISCV_REG_F23_64,		// "fs7"
	RISCV_REG_F24_32,		// "fs8"
	RISCV_REG_F24_64,		// "fs8"
	RISCV_REG_F25_32,		// "fs9"
	RISCV_REG_F25_64,		// "fs9"
	RISCV_REG_F26_32,		// "fs10"
	RISCV_REG_F26_64,		// "fs10"
	RISCV_REG_F27_32,		// "fs11"
	RISCV_REG_F27_64,		// "fs11"
	RISCV_REG_F28_32,		// "ft8"
	RISCV_REG_F28_64,		// "ft8"
	RISCV_REG_F29_32,		// "ft9"
	RISCV_REG_F29_64,		// "ft9"
	RISCV_REG_F30_32,		// "ft10"
	RISCV_REG_F30_64,		// "ft10"
	RISCV_REG_F31_32,		// "ft11"
	RISCV_REG_F31_64,		// "ft11"

	RISCV_REG_ENDING,		// <-- mark the end of the list or registers
} riscv_reg;

//> RISCV instruction
typedef enum riscv_insn {
  	RISCV_INS_INVALID = 0,

  	RISCV_INS_ADD,
  	RISCV_INS_ADDI,
  	RISCV_INS_ADDIW,
  	RISCV_INS_ADDW,
  	RISCV_INS_AMOADD_D,
  	RISCV_INS_AMOADD_D_AQ,
  	RISCV_INS_AMOADD_D_AQ_RL,
  	RISCV_INS_AMOADD_D_RL,
  	RISCV_INS_AMOADD_W,
  	RISCV_INS_AMOADD_W_AQ,
  	RISCV_INS_AMOADD_W_AQ_RL,
  	RISCV_INS_AMOADD_W_RL,
  	RISCV_INS_AMOAND_D,
  	RISCV_INS_AMOAND_D_AQ,
  	RISCV_INS_AMOAND_D_AQ_RL,
  	RISCV_INS_AMOAND_D_RL,
  	RISCV_INS_AMOAND_W,
  	RISCV_INS_AMOAND_W_AQ,
  	RISCV_INS_AMOAND_W_AQ_RL,
  	RISCV_INS_AMOAND_W_RL,
  	RISCV_INS_AMOMAXU_D,
  	RISCV_INS_AMOMAXU_D_AQ,
  	RISCV_INS_AMOMAXU_D_AQ_RL,
  	RISCV_INS_AMOMAXU_D_RL,
  	RISCV_INS_AMOMAXU_W,
  	RISCV_INS_AMOMAXU_W_AQ,
  	RISCV_INS_AMOMAXU_W_AQ_RL,
  	RISCV_INS_AMOMAXU_W_RL,
  	RISCV_INS_AMOMAX_D,
  	RISCV_INS_AMOMAX_D_AQ,
  	RISCV_INS_AMOMAX_D_AQ_RL,
  	RISCV_INS_AMOMAX_D_RL,
  	RISCV_INS_AMOMAX_W,
  	RISCV_INS_AMOMAX_W_AQ,
  	RISCV_INS_AMOMAX_W_AQ_RL,
  	RISCV_INS_AMOMAX_W_RL,
  	RISCV_INS_AMOMINU_D,
  	RISCV_INS_AMOMINU_D_AQ,
  	RISCV_INS_AMOMINU_D_AQ_RL,
  	RISCV_INS_AMOMINU_D_RL,
  	RISCV_INS_AMOMINU_W,
  	RISCV_INS_AMOMINU_W_AQ,
  	RISCV_INS_AMOMINU_W_AQ_RL,
  	RISCV_INS_AMOMINU_W_RL,
  	RISCV_INS_AMOMIN_D,
  	RISCV_INS_AMOMIN_D_AQ,
  	RISCV_INS_AMOMIN_D_AQ_RL,
  	RISCV_INS_AMOMIN_D_RL,
  	RISCV_INS_AMOMIN_W,
  	RISCV_INS_AMOMIN_W_AQ,
  	RISCV_INS_AMOMIN_W_AQ_RL,
  	RISCV_INS_AMOMIN_W_RL,
  	RISCV_INS_AMOOR_D,
  	RISCV_INS_AMOOR_D_AQ,
  	RISCV_INS_AMOOR_D_AQ_RL,
  	RISCV_INS_AMOOR_D_RL,
  	RISCV_INS_AMOOR_W,
  	RISCV_INS_AMOOR_W_AQ,
  	RISCV_INS_AMOOR_W_AQ_RL,
  	RISCV_INS_AMOOR_W_RL,
  	RISCV_INS_AMOSWAP_D,
  	RISCV_INS_AMOSWAP_D_AQ,
  	RISCV_INS_AMOSWAP_D_AQ_RL,
  	RISCV_INS_AMOSWAP_D_RL,
  	RISCV_INS_AMOSWAP_W,
  	RISCV_INS_AMOSWAP_W_AQ,
  	RISCV_INS_AMOSWAP_W_AQ_RL,
  	RISCV_INS_AMOSWAP_W_RL,
  	RISCV_INS_AMOXOR_D,
  	RISCV_INS_AMOXOR_D_AQ,
  	RISCV_INS_AMOXOR_D_AQ_RL,
  	RISCV_INS_AMOXOR_D_RL,
  	RISCV_INS_AMOXOR_W,
  	RISCV_INS_AMOXOR_W_AQ,
  	RISCV_INS_AMOXOR_W_AQ_RL,
  	RISCV_INS_AMOXOR_W_RL,
  	RISCV_INS_AND,
  	RISCV_INS_ANDI,
  	RISCV_INS_AUIPC,
  	RISCV_INS_BEQ,
  	RISCV_INS_BGE,
  	RISCV_INS_BGEU,
  	RISCV_INS_BLT,
  	RISCV_INS_BLTU,
  	RISCV_INS_BNE,
  	RISCV_INS_CSRRC,
  	RISCV_INS_CSRRCI,
  	RISCV_INS_CSRRS,
  	RISCV_INS_CSRRSI,
 	RISCV_INS_CSRRW,
  	RISCV_INS_CSRRWI,
  	RISCV_INS_C_ADD,
  	RISCV_INS_C_ADDI,
  	RISCV_INS_C_ADDI16SP,
  	RISCV_INS_C_ADDI4SPN,
  	RISCV_INS_C_ADDIW,
  	RISCV_INS_C_ADDW,
  	RISCV_INS_C_AND,
  	RISCV_INS_C_ANDI,
  	RISCV_INS_C_BEQZ,
  	RISCV_INS_C_BNEZ,
  	RISCV_INS_C_EBREAK,
  	RISCV_INS_C_FLD,
  	RISCV_INS_C_FLDSP,
  	RISCV_INS_C_FLW,
  	RISCV_INS_C_FLWSP,
  	RISCV_INS_C_FSD,
  	RISCV_INS_C_FSDSP,
  	RISCV_INS_C_FSW,
  	RISCV_INS_C_FSWSP,
  	RISCV_INS_C_J,
  	RISCV_INS_C_JAL,
  	RISCV_INS_C_JALR,
  	RISCV_INS_C_JR,
  	RISCV_INS_C_LD,
  	RISCV_INS_C_LDSP,
  	RISCV_INS_C_LI,
  	RISCV_INS_C_LUI,
  	RISCV_INS_C_LW,
  	RISCV_INS_C_LWSP,
  	RISCV_INS_C_MV,
  	RISCV_INS_C_NOP,
  	RISCV_INS_C_OR,
  	RISCV_INS_C_SD,
	RISCV_INS_C_SDSP,
  	RISCV_INS_C_SLLI,
  	RISCV_INS_C_SRAI,
  	RISCV_INS_C_SRLI,
  	RISCV_INS_C_SUB,
  	RISCV_INS_C_SUBW,
  	RISCV_INS_C_SW,
  	RISCV_INS_C_SWSP,
  	RISCV_INS_C_UNIMP,
  	RISCV_INS_C_XOR,
  	RISCV_INS_DIV,
  	RISCV_INS_DIVU,
  	RISCV_INS_DIVUW,
  	RISCV_INS_DIVW,
  	RISCV_INS_EBREAK,
  	RISCV_INS_ECALL,
  	RISCV_INS_FADD_D,
  	RISCV_INS_FADD_S,
  	RISCV_INS_FCLASS_D,
  	RISCV_INS_FCLASS_S,
  	RISCV_INS_FCVT_D_L,
  	RISCV_INS_FCVT_D_LU,
  	RISCV_INS_FCVT_D_S,
  	RISCV_INS_FCVT_D_W,
  	RISCV_INS_FCVT_D_WU,
  	RISCV_INS_FCVT_LU_D,
  	RISCV_INS_FCVT_LU_S,
  	RISCV_INS_FCVT_L_D,
  	RISCV_INS_FCVT_L_S,
  	RISCV_INS_FCVT_S_D,
  	RISCV_INS_FCVT_S_L,
  	RISCV_INS_FCVT_S_LU,
  	RISCV_INS_FCVT_S_W,
  	RISCV_INS_FCVT_S_WU,
  	RISCV_INS_FCVT_WU_D,
  	RISCV_INS_FCVT_WU_S,
  	RISCV_INS_FCVT_W_D,
  	RISCV_INS_FCVT_W_S,
  	RISCV_INS_FDIV_D,
  	RISCV_INS_FDIV_S,
  	RISCV_INS_FENCE,
  	RISCV_INS_FENCE_I,
  	RISCV_INS_FENCE_TSO,
  	RISCV_INS_FEQ_D,
  	RISCV_INS_FEQ_S,
  	RISCV_INS_FLD,
  	RISCV_INS_FLE_D,
  	RISCV_INS_FLE_S,
  	RISCV_INS_FLT_D,
  	RISCV_INS_FLT_S,
  	RISCV_INS_FLW,
  	RISCV_INS_FMADD_D,
  	RISCV_INS_FMADD_S,
  	RISCV_INS_FMAX_D,
  	RISCV_INS_FMAX_S,
  	RISCV_INS_FMIN_D,
  	RISCV_INS_FMIN_S,
  	RISCV_INS_FMSUB_D,
  	RISCV_INS_FMSUB_S,
  	RISCV_INS_FMUL_D,
  	RISCV_INS_FMUL_S,
  	RISCV_INS_FMV_D_X,
  	RISCV_INS_FMV_W_X,
  	RISCV_INS_FMV_X_D,
  	RISCV_INS_FMV_X_W,
  	RISCV_INS_FNMADD_D,
  	RISCV_INS_FNMADD_S,
  	RISCV_INS_FNMSUB_D,
  	RISCV_INS_FNMSUB_S,
  	RISCV_INS_FSD,
  	RISCV_INS_FSGNJN_D,
  	RISCV_INS_FSGNJN_S,
  	RISCV_INS_FSGNJX_D,
  	RISCV_INS_FSGNJX_S,
  	RISCV_INS_FSGNJ_D,
  	RISCV_INS_FSGNJ_S,
  	RISCV_INS_FSQRT_D,
  	RISCV_INS_FSQRT_S,
  	RISCV_INS_FSUB_D,
  	RISCV_INS_FSUB_S,
  	RISCV_INS_FSW,
  	RISCV_INS_JAL,
  	RISCV_INS_JALR,
  	RISCV_INS_LB,
  	RISCV_INS_LBU,
  	RISCV_INS_LD,
  	RISCV_INS_LH,
  	RISCV_INS_LHU,
  	RISCV_INS_LR_D,
  	RISCV_INS_LR_D_AQ,
  	RISCV_INS_LR_D_AQ_RL,
  	RISCV_INS_LR_D_RL,
  	RISCV_INS_LR_W,
  	RISCV_INS_LR_W_AQ,
  	RISCV_INS_LR_W_AQ_RL,
  	RISCV_INS_LR_W_RL,
  	RISCV_INS_LUI,
  	RISCV_INS_LW,
  	RISCV_INS_LWU,
  	RISCV_INS_MRET,
  	RISCV_INS_MUL,
  	RISCV_INS_MULH,
  	RISCV_INS_MULHSU,
  	RISCV_INS_MULHU,
  	RISCV_INS_MULW,
  	RISCV_INS_OR,
  	RISCV_INS_ORI,
  	RISCV_INS_REM,
  	RISCV_INS_REMU,
  	RISCV_INS_REMUW,
  	RISCV_INS_REMW,
  	RISCV_INS_SB,
  	RISCV_INS_SC_D,
  	RISCV_INS_SC_D_AQ,
  	RISCV_INS_SC_D_AQ_RL,
  	RISCV_INS_SC_D_RL,
  	RISCV_INS_SC_W,
  	RISCV_INS_SC_W_AQ,
  	RISCV_INS_SC_W_AQ_RL,
  	RISCV_INS_SC_W_RL,
  	RISCV_INS_SD,
  	RISCV_INS_SFENCE_VMA,
  	RISCV_INS_SH,
  	RISCV_INS_SLL,
  	RISCV_INS_SLLI,
  	RISCV_INS_SLLIW,
  	RISCV_INS_SLLW,
  	RISCV_INS_SLT,
  	RISCV_INS_SLTI,
  	RISCV_INS_SLTIU,
  	RISCV_INS_SLTU,
  	RISCV_INS_SRA,
  	RISCV_INS_SRAI,
  	RISCV_INS_SRAIW,
  	RISCV_INS_SRAW,
  	RISCV_INS_SRET,
  	RISCV_INS_SRL,
  	RISCV_INS_SRLI,
  	RISCV_INS_SRLIW,
  	RISCV_INS_SRLW,
  	RISCV_INS_SUB,
  	RISCV_INS_SUBW,
  	RISCV_INS_SW,
  	RISCV_INS_UNIMP,
  	RISCV_INS_URET,
  	RISCV_INS_WFI,
  	RISCV_INS_XOR,
  	RISCV_INS_XORI,

  	RISCV_INS_ENDING,
} riscv_insn;

//> Group of RISCV instructions
typedef enum riscv_insn_group {
  	RISCV_GRP_INVALID = 0, ///< = CS_GRP_INVALID

  	// Generic groups
  	// all jump instructions (conditional+direct+indirect jumps)
  	RISCV_GRP_JUMP,	///< = CS_GRP_JUMP
  	// all call instructions
  	RISCV_GRP_CALL,	///< = CS_GRP_CALL
  	// all return instructions
  	RISCV_GRP_RET,	///< = CS_GRP_RET
  	// all interrupt instructions (int+syscall)
  	RISCV_GRP_INT,	///< = CS_GRP_INT
  	// all interrupt return instructions
  	RISCV_GRP_IRET,	///< = CS_GRP_IRET
  	// all privileged instructions
  	RISCV_GRP_PRIVILEGE,	///< = CS_GRP_PRIVILEGE
  	// all relative branching instructions
  	RISCV_GRP_BRANCH_RELATIVE, ///< = CS_GRP_BRANCH_RELATIVE

  	// Architecture-specific groups
  	RISCV_GRP_ISRV32 = 128,
  	RISCV_GRP_ISRV64,
  	RISCV_GRP_HASSTDEXTA,
  	RISCV_GRP_HASSTDEXTC,
  	RISCV_GRP_HASSTDEXTD,
  	RISCV_GRP_HASSTDEXTF,
  	RISCV_GRP_HASSTDEXTM,
  	RISCV_GRP_ENDING,
} riscv_insn_group;

#ifdef __cplusplus
}
#endif

#endif

