+ if (cp == 2) {
+ switch (c.r.op) {
+ case OP_CP2_BASIC:
+ return snprintf(buf, len, "%s%s,%u",
+ cp2_basic_opcodes[c.i.rs],
+ lightrec_reg_name(c.i.rt),
+ c.r.rd);
+ default:
+ return snprintf(buf, len, "%s", cp2_opcodes[c.r.op]);
+ }
+ } else {
+ switch (c.i.rs) {
+ case OP_CP0_MFC0:
+ case OP_CP0_CFC0:
+ case OP_CP0_MTC0:
+ case OP_CP0_CTC0:
+ return snprintf(buf, len, "%s%s,%u",
+ cp0_opcodes[c.i.rs],
+ lightrec_reg_name(c.i.rt),
+ c.r.rd);
+ case OP_CP0_RFE:
+ return snprintf(buf, len, "rfe ");
+ default:
+ return snprintf(buf, len, "unknown (0x%08x)", c.opcode);
+ }
+ }
+}
+
+static int print_op(union code c, u32 pc, char *buf, size_t len,
+ const char * const **flags_ptr, size_t *nb_flags,
+ bool *is_io)
+{
+ if (c.opcode == 0)
+ return snprintf(buf, len, "nop ");
+
+ switch (c.i.op) {
+ case OP_SPECIAL:
+ return print_op_special(c, buf, len, flags_ptr, nb_flags);
+ case OP_REGIMM:
+ *flags_ptr = opcode_branch_flags;
+ *nb_flags = ARRAY_SIZE(opcode_branch_flags);
+ return snprintf(buf, len, "%s%s,0x%x",
+ regimm_opcodes[c.i.rt],
+ lightrec_reg_name(c.i.rs),
+ pc + 4 + ((s16)c.i.imm << 2));
+ case OP_J:
+ case OP_JAL:
+ *flags_ptr = opcode_branch_flags;
+ *nb_flags = ARRAY_SIZE(opcode_branch_flags);
+ return snprintf(buf, len, "%s0x%x",
+ std_opcodes[c.i.op],
+ (pc & 0xf0000000) | (c.j.imm << 2));
+ case OP_BEQ:
+ if (c.i.rs == c.i.rt) {
+ *flags_ptr = opcode_branch_flags;
+ *nb_flags = ARRAY_SIZE(opcode_branch_flags);
+ return snprintf(buf, len, "b 0x%x",
+ pc + 4 + ((s16)c.i.imm << 2));
+ }
+ fallthrough;
+ case OP_BNE:
+ case OP_BLEZ:
+ case OP_BGTZ:
+ *flags_ptr = opcode_branch_flags;
+ *nb_flags = ARRAY_SIZE(opcode_branch_flags);
+ return snprintf(buf, len, "%s%s,%s,0x%x",
+ std_opcodes[c.i.op],
+ lightrec_reg_name(c.i.rs),
+ lightrec_reg_name(c.i.rt),
+ pc + 4 + ((s16)c.i.imm << 2));
+ case OP_ADDI:
+ case OP_ADDIU:
+ case OP_ORI:
+ *flags_ptr = opcode_movi_flags;
+ *nb_flags = ARRAY_SIZE(opcode_movi_flags);
+ fallthrough;
+ case OP_SLTI:
+ case OP_SLTIU:
+ case OP_ANDI:
+ case OP_XORI:
+ return snprintf(buf, len, "%s%s,%s,0x%04hx",
+ std_opcodes[c.i.op],
+ lightrec_reg_name(c.i.rt),
+ lightrec_reg_name(c.i.rs),
+ (u16)c.i.imm);
+
+ case OP_LUI:
+ *flags_ptr = opcode_movi_flags;
+ *nb_flags = ARRAY_SIZE(opcode_movi_flags);
+ return snprintf(buf, len, "%s%s,0x%04hx",
+ std_opcodes[c.i.op],
+ lightrec_reg_name(c.i.rt),
+ (u16)c.i.imm);
+ case OP_CP0:
+ return print_op_cp(c, buf, len, 0);
+ case OP_CP2:
+ return print_op_cp(c, buf, len, 2);
+ case OP_LB:
+ case OP_LH:
+ case OP_LWL:
+ case OP_LW:
+ case OP_LBU:
+ case OP_LHU:
+ case OP_LWR:
+ case OP_SB:
+ case OP_SH:
+ case OP_SWL:
+ case OP_SW:
+ case OP_SWR:
+ case OP_META_LWU:
+ case OP_META_SWU:
+ *flags_ptr = opcode_io_flags;
+ *nb_flags = ARRAY_SIZE(opcode_io_flags);
+ *is_io = true;
+ return snprintf(buf, len, "%s%s,%hd(%s)",
+ std_opcodes[c.i.op],
+ lightrec_reg_name(c.i.rt),
+ (s16)c.i.imm,
+ lightrec_reg_name(c.i.rs));
+ case OP_LWC2:
+ case OP_SWC2:
+ *flags_ptr = opcode_io_flags;
+ *nb_flags = ARRAY_SIZE(opcode_io_flags);
+ return snprintf(buf, len, "%s%s,%hd(%s)",
+ std_opcodes[c.i.op],
+ lightrec_reg_name(c.i.rt),
+ (s16)c.i.imm,
+ lightrec_reg_name(c.i.rs));
+ case OP_META:
+ return snprintf(buf, len, "%s%s,%s",
+ meta_opcodes[c.m.op],
+ lightrec_reg_name(c.m.rd),
+ lightrec_reg_name(c.m.rs));
+ case OP_META_MULT2:
+ case OP_META_MULTU2:
+ *flags_ptr = opcode_multdiv_flags;
+ *nb_flags = ARRAY_SIZE(opcode_multdiv_flags);
+ return snprintf(buf, len, "%s%s,%s,%s,%u",
+ mult2_opcodes[c.i.op == OP_META_MULTU2],
+ lightrec_reg_name(get_mult_div_hi(c)),
+ lightrec_reg_name(get_mult_div_lo(c)),
+ lightrec_reg_name(c.r.rs), c.r.op);
+ default:
+ return snprintf(buf, len, "unknown (0x%08x)", c.opcode);
+ }
+}
+
+void lightrec_print_disassembly(const struct block *block, const u32 *code_ptr)
+{
+ const struct opcode *op;
+ const char * const *flags_ptr;
+ size_t nb_flags, count, count2;
+ char buf[256], buf2[256], buf3[256];