/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2014-2021 Paul Cercueil */ #ifndef __DISASSEMBLER_H__ #define __DISASSEMBLER_H__ #include "debug.h" #include "lightrec.h" #ifndef __packed #define __packed __attribute__((packed)) #endif #define BIT(x) (1ULL << (x)) /* Flags for all opcodes */ #define LIGHTREC_NO_DS BIT(0) #define LIGHTREC_UNLOAD_RS BIT(1) #define LIGHTREC_UNLOAD_RT BIT(2) #define LIGHTREC_UNLOAD_RD BIT(3) #define LIGHTREC_SYNC BIT(4) /* Flags for load/store opcodes */ #define LIGHTREC_DIRECT_IO BIT(5) #define LIGHTREC_HW_IO BIT(6) #define LIGHTREC_SMC BIT(7) #define LIGHTREC_NO_INVALIDATE BIT(8) /* Flags for branches */ #define LIGHTREC_EMULATE_BRANCH BIT(5) #define LIGHTREC_LOCAL_BRANCH BIT(6) /* Flags for div/mult opcodes */ #define LIGHTREC_NO_LO BIT(5) #define LIGHTREC_NO_HI BIT(6) #define LIGHTREC_NO_DIV_CHECK BIT(7) struct block; enum standard_opcodes { OP_SPECIAL = 0x00, OP_REGIMM = 0x01, OP_J = 0x02, OP_JAL = 0x03, OP_BEQ = 0x04, OP_BNE = 0x05, OP_BLEZ = 0x06, OP_BGTZ = 0x07, OP_ADDI = 0x08, OP_ADDIU = 0x09, OP_SLTI = 0x0a, OP_SLTIU = 0x0b, OP_ANDI = 0x0c, OP_ORI = 0x0d, OP_XORI = 0x0e, OP_LUI = 0x0f, OP_CP0 = 0x10, OP_CP2 = 0x12, OP_LB = 0x20, OP_LH = 0x21, OP_LWL = 0x22, OP_LW = 0x23, OP_LBU = 0x24, OP_LHU = 0x25, OP_LWR = 0x26, OP_SB = 0x28, OP_SH = 0x29, OP_SWL = 0x2a, OP_SW = 0x2b, OP_SWR = 0x2e, OP_LWC2 = 0x32, OP_SWC2 = 0x3a, OP_META_BEQZ = 0x14, OP_META_BNEZ = 0x15, OP_META_MOV = 0x16, }; enum special_opcodes { OP_SPECIAL_SLL = 0x00, OP_SPECIAL_SRL = 0x02, OP_SPECIAL_SRA = 0x03, OP_SPECIAL_SLLV = 0x04, OP_SPECIAL_SRLV = 0x06, OP_SPECIAL_SRAV = 0x07, OP_SPECIAL_JR = 0x08, OP_SPECIAL_JALR = 0x09, OP_SPECIAL_SYSCALL = 0x0c, OP_SPECIAL_BREAK = 0x0d, OP_SPECIAL_MFHI = 0x10, OP_SPECIAL_MTHI = 0x11, OP_SPECIAL_MFLO = 0x12, OP_SPECIAL_MTLO = 0x13, OP_SPECIAL_MULT = 0x18, OP_SPECIAL_MULTU = 0x19, OP_SPECIAL_DIV = 0x1a, OP_SPECIAL_DIVU = 0x1b, OP_SPECIAL_ADD = 0x20, OP_SPECIAL_ADDU = 0x21, OP_SPECIAL_SUB = 0x22, OP_SPECIAL_SUBU = 0x23, OP_SPECIAL_AND = 0x24, OP_SPECIAL_OR = 0x25, OP_SPECIAL_XOR = 0x26, OP_SPECIAL_NOR = 0x27, OP_SPECIAL_SLT = 0x2a, OP_SPECIAL_SLTU = 0x2b, }; enum regimm_opcodes { OP_REGIMM_BLTZ = 0x00, OP_REGIMM_BGEZ = 0x01, OP_REGIMM_BLTZAL = 0x10, OP_REGIMM_BGEZAL = 0x11, }; enum cp0_opcodes { OP_CP0_MFC0 = 0x00, OP_CP0_CFC0 = 0x02, OP_CP0_MTC0 = 0x04, OP_CP0_CTC0 = 0x06, OP_CP0_RFE = 0x10, }; enum cp2_opcodes { OP_CP2_BASIC = 0x00, }; enum cp2_basic_opcodes { OP_CP2_BASIC_MFC2 = 0x00, OP_CP2_BASIC_CFC2 = 0x02, OP_CP2_BASIC_MTC2 = 0x04, OP_CP2_BASIC_CTC2 = 0x06, }; struct opcode_r { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ u32 zero :6; u32 rs :5; u32 rt :5; u32 rd :5; u32 imm :5; u32 op :6; #else u32 op :6; u32 imm :5; u32 rd :5; u32 rt :5; u32 rs :5; u32 zero :6; #endif } __packed; struct opcode_i { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ u32 op :6; u32 rs :5; u32 rt :5; u32 imm :16; #else u32 imm :16; u32 rt :5; u32 rs :5; u32 op :6; #endif } __packed; struct opcode_j { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ u32 op :6; u32 imm :26; #else u32 imm :26; u32 op :6; #endif } __packed; union code { /* Keep in sync with struct opcode */ u32 opcode; struct opcode_r r; struct opcode_i i; struct opcode_j j; }; struct opcode { /* Keep this union at the first position */ union { union code c; /* Keep in sync with union code */ u32 opcode; struct opcode_r r; struct opcode_i i; struct opcode_j j; }; u16 flags; }; void lightrec_print_disassembly(const struct block *block, const u32 *code); #endif /* __DISASSEMBLER_H__ */