+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
- * Copyright (C) 2014 Paul Cercueil <paul@crapouillou.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * Copyright (C) 2014-2021 Paul Cercueil <paul@crapouillou.net>
*/
#ifndef __DISASSEMBLER_H__
#include "debug.h"
#include "lightrec.h"
+#include "lightrec-config.h"
#ifndef __packed
#define __packed __attribute__((packed))
#endif
-#define LIGHTREC_DIRECT_IO (1 << 0)
-#define LIGHTREC_NO_INVALIDATE (1 << 1)
-#define LIGHTREC_NO_DS (1 << 2)
-#define LIGHTREC_SMC (1 << 3)
-#define LIGHTREC_EMULATE_BRANCH (1 << 4)
-#define LIGHTREC_LOCAL_BRANCH (1 << 5)
-#define LIGHTREC_HW_IO (1 << 6)
-#define LIGHTREC_MULT32 (1 << 7)
+#define BIT(x) (1ULL << (x))
+
+/* Flags for all opcodes */
+#define LIGHTREC_NO_DS BIT(0)
+#define LIGHTREC_SYNC BIT(1)
+
+/* Flags for LUI, ORI, ADDIU */
+#define LIGHTREC_MOVI BIT(2)
+
+/* Flags for load/store opcodes */
+#define LIGHTREC_SMC BIT(2)
+#define LIGHTREC_NO_INVALIDATE BIT(3)
+#define LIGHTREC_NO_MASK BIT(4)
+#define LIGHTREC_LOAD_DELAY BIT(5)
+
+/* I/O mode for load/store opcodes */
+#define LIGHTREC_IO_MODE_LSB 6
+#define LIGHTREC_IO_MODE(x) ((x) << LIGHTREC_IO_MODE_LSB)
+#define LIGHTREC_IO_UNKNOWN 0x0
+#define LIGHTREC_IO_DIRECT 0x1
+#define LIGHTREC_IO_HW 0x2
+#define LIGHTREC_IO_RAM 0x3
+#define LIGHTREC_IO_BIOS 0x4
+#define LIGHTREC_IO_SCRATCH 0x5
+#define LIGHTREC_IO_DIRECT_HW 0x6
+#define LIGHTREC_IO_MASK LIGHTREC_IO_MODE(0x7)
+#define LIGHTREC_FLAGS_GET_IO_MODE(x) \
+ (((x) & LIGHTREC_IO_MASK) >> LIGHTREC_IO_MODE_LSB)
+
+/* Flags for branches */
+#define LIGHTREC_EMULATE_BRANCH BIT(2)
+#define LIGHTREC_LOCAL_BRANCH BIT(3)
+
+/* Flags for div/mult opcodes */
+#define LIGHTREC_NO_LO BIT(2)
+#define LIGHTREC_NO_HI BIT(3)
+#define LIGHTREC_NO_DIV_CHECK BIT(4)
+
+#define LIGHTREC_REG_RS_LSB 26
+#define LIGHTREC_REG_RS(x) ((x) << LIGHTREC_REG_RS_LSB)
+#define LIGHTREC_REG_RS_MASK LIGHTREC_REG_RS(0x3)
+#define LIGHTREC_FLAGS_GET_RS(x) \
+ (((x) & LIGHTREC_REG_RS_MASK) >> LIGHTREC_REG_RS_LSB)
+
+#define LIGHTREC_REG_RT_LSB 28
+#define LIGHTREC_REG_RT(x) ((x) << LIGHTREC_REG_RT_LSB)
+#define LIGHTREC_REG_RT_MASK LIGHTREC_REG_RT(0x3)
+#define LIGHTREC_FLAGS_GET_RT(x) \
+ (((x) & LIGHTREC_REG_RT_MASK) >> LIGHTREC_REG_RT_LSB)
+
+#define LIGHTREC_REG_RD_LSB 30
+#define LIGHTREC_REG_RD(x) ((x) << LIGHTREC_REG_RD_LSB)
+#define LIGHTREC_REG_RD_MASK LIGHTREC_REG_RD(0x3)
+#define LIGHTREC_FLAGS_GET_RD(x) \
+ (((x) & LIGHTREC_REG_RD_MASK) >> LIGHTREC_REG_RD_LSB)
+
+#define LIGHTREC_REG_NOOP 0x0
+#define LIGHTREC_REG_UNLOAD 0x1
+#define LIGHTREC_REG_DISCARD 0x2
+#define LIGHTREC_REG_CLEAN 0x3
struct block;
OP_LWC2 = 0x32,
OP_SWC2 = 0x3a,
- OP_META_REG_UNLOAD = 0x11,
+ OP_META = 0x3c,
- OP_META_BEQZ = 0x14,
- OP_META_BNEZ = 0x15,
-
- OP_META_MOV = 0x16,
- OP_META_SYNC = 0x17,
+ OP_META_MULT2 = 0x19,
+ OP_META_MULTU2 = 0x1a,
+ OP_META_LWU = 0x1b,
+ OP_META_SWU = 0x1c,
};
enum special_opcodes {
enum cp2_opcodes {
OP_CP2_BASIC = 0x00,
+ OP_CP2_RTPS = 0x01,
+ OP_CP2_NCLIP = 0x06,
+ OP_CP2_OP = 0x0c,
+ OP_CP2_DPCS = 0x10,
+ OP_CP2_INTPL = 0x11,
+ OP_CP2_MVMVA = 0x12,
+ OP_CP2_NCDS = 0x13,
+ OP_CP2_CDP = 0x14,
+ OP_CP2_NCDT = 0x16,
+ OP_CP2_NCCS = 0x1b,
+ OP_CP2_CC = 0x1c,
+ OP_CP2_NCS = 0x1e,
+ OP_CP2_NCT = 0x20,
+ OP_CP2_SQR = 0x28,
+ OP_CP2_DCPL = 0x29,
+ OP_CP2_DPCT = 0x2a,
+ OP_CP2_AVSZ3 = 0x2d,
+ OP_CP2_AVSZ4 = 0x2e,
+ OP_CP2_RTPT = 0x30,
+ OP_CP2_GPF = 0x3d,
+ OP_CP2_GPL = 0x3e,
+ OP_CP2_NCCT = 0x3f,
};
enum cp2_basic_opcodes {
OP_CP2_BASIC_CTC2 = 0x06,
};
+enum meta_opcodes {
+ OP_META_MOV = 0x00,
+
+ OP_META_EXTC = 0x01,
+ OP_META_EXTS = 0x02,
+
+ OP_META_COM = 0x03,
+};
+
struct opcode_r {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
u32 zero :6;
#endif
} __packed;
+struct opcode_m {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u32 meta :6;
+ u32 rs :5;
+ u32 rt :5;
+ u32 rd :5;
+ u32 imm :6;
+ u32 op :5;
+#else
+ u32 op :5;
+ u32 imm :6;
+ u32 rd :5;
+ u32 rt :5;
+ u32 rs :5;
+ u32 meta :6;
+#endif
+};
+
union code {
/* Keep in sync with struct opcode */
u32 opcode;
struct opcode_r r;
struct opcode_i i;
struct opcode_j j;
+ struct opcode_m m;
};
struct opcode {
struct opcode_r r;
struct opcode_i i;
struct opcode_j j;
+ struct opcode_m m;
};
- u16 flags;
- u16 offset;
- struct opcode *next;
+ u32 flags;
+};
+
+struct opcode_list {
+ u16 nb_ops;
+ struct opcode ops[];
};
-struct opcode * lightrec_disassemble(struct lightrec_state *state,
- const u32 *src, unsigned int *len);
-void lightrec_free_opcode_list(struct lightrec_state *state,
- struct opcode *list);
+void lightrec_print_disassembly(const struct block *block, const u32 *code);
+
+static inline _Bool op_flag_no_ds(u32 flags)
+{
+ return OPT_SWITCH_DELAY_SLOTS && (flags & LIGHTREC_NO_DS);
+}
+
+static inline _Bool op_flag_sync(u32 flags)
+{
+ return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_SYNC);
+}
+
+static inline _Bool op_flag_smc(u32 flags)
+{
+ return OPT_FLAG_IO && (flags & LIGHTREC_SMC);
+}
+
+static inline _Bool op_flag_no_invalidate(u32 flags)
+{
+ return OPT_FLAG_IO && (flags & LIGHTREC_NO_INVALIDATE);
+}
+
+static inline _Bool op_flag_no_mask(u32 flags)
+{
+ return OPT_FLAG_IO && (flags & LIGHTREC_NO_MASK);
+}
+
+static inline _Bool op_flag_load_delay(u32 flags)
+{
+ return OPT_HANDLE_LOAD_DELAYS && (flags & LIGHTREC_LOAD_DELAY);
+}
+
+static inline _Bool op_flag_emulate_branch(u32 flags)
+{
+ return OPT_DETECT_IMPOSSIBLE_BRANCHES &&
+ (flags & LIGHTREC_EMULATE_BRANCH);
+}
+
+static inline _Bool op_flag_local_branch(u32 flags)
+{
+ return OPT_LOCAL_BRANCHES && (flags & LIGHTREC_LOCAL_BRANCH);
+}
+
+static inline _Bool op_flag_no_lo(u32 flags)
+{
+ return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_LO);
+}
-unsigned int lightrec_cycles_of_opcode(union code code);
+static inline _Bool op_flag_no_hi(u32 flags)
+{
+ return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_HI);
+}
-void lightrec_print_disassembly(const struct block *block,
- const u32 *code, unsigned int length);
+static inline _Bool op_flag_no_div_check(u32 flags)
+{
+ return OPT_FLAG_MULT_DIV && (flags & LIGHTREC_NO_DIV_CHECK);
+}
#endif /* __DISASSEMBLER_H__ */