From 4f992bf5416fd1e3840d6211712983efa92da4ef Mon Sep 17 00:00:00 2001 From: kub Date: Mon, 2 Dec 2019 22:31:14 +0100 Subject: [PATCH] sh2 drc, tentative MIPS32/64 Release 2 support --- cpu/drc/emit_arm64.c | 23 +++--- cpu/drc/emit_mips.c | 144 ++++++++++++++++++++++++++++---------- cpu/drc/emit_riscv.c | 4 +- platform/common/dismips.c | 75 +++++++++++++++++--- 4 files changed, 186 insertions(+), 60 deletions(-) diff --git a/cpu/drc/emit_arm64.c b/cpu/drc/emit_arm64.c index 7a832747..c827fe2c 100644 --- a/cpu/drc/emit_arm64.c +++ b/cpu/drc/emit_arm64.c @@ -221,10 +221,15 @@ enum { XT_UXTW=0x4, XT_UXTX=0x6, XT_LSL=0x7, XT_SXTW=0xc, XT_SXTX=0xe }; #define A64_ROR_IMM(rd, rn, bits) /* EXTR */ \ A64_INSN(0x9,0x0,0x6,_,rn,_,bits,rn,rd) -#define A64_SXT_IMM(rd, rn, bits) \ - A64_INSN(0x9,0x0,0x4,0,0,_,bits-1,rn,rd) -#define A64_UXT_IMM(rd, rn, bits) \ - A64_INSN(0x9,0x2,0x4,0,0,_,bits-1,rn,rd) +#define A64_SXT_IMM(rd, rn, bits) /* SBFM */ \ + A64_INSN(0x9,0x0,0x4,_,0,_,bits-1,rn,rd) +#define A64_UXT_IMM(rd, rn, bits) /* UBFM */ \ + A64_INSN(0x9,0x2,0x4,_,0,_,bits-1,rn,rd) + +#define A64_BFX_IMM(rd, rn, lsb, bits) /* UBFM */ \ + A64_INSN(0x9,0x2,0x4,_,lsb,_,bits-1,rn,rd) +#define A64_BFI_IMM(rd, rn, lsb, bits) /* BFM */ \ + A64_INSN(0x9,0x1,0x4,_,(32-lsb)&31,_,bits-1,rn,rd) // multiplication @@ -1302,8 +1307,7 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode) EMITH_SJMP_START(DCOND_EQ); \ /* overflow if top 33 bits of MACH:MACL aren't all 1 or 0 */ \ /* to check: add MACL[31] to MACH. this is 0 if no overflow */ \ - emith_lsr(rn, ml, 31); \ - emith_addf_r_r(rn, mh); /* sum = MACH + ((MACL>>31)&1) */ \ + emith_addf_r_r_r_lsr(rn, mh, ml, 31); /* sum = MACH + (MACL>>31) */ \ EMITH_SJMP_START(DCOND_EQ); /* sum != 0 -> overflow */ \ /* XXX: LSB signalling only in SH1, or in SH2 too? */ \ emith_move_r_imm_c(DCOND_NE, mh, 0x00000001); /* LSB of MACH */ \ @@ -1315,11 +1319,8 @@ static void emith_ldst_offs(int sz, int rd, int rn, int o9, int ld, int mode) EMITH_SJMP_END(DCOND_EQ); \ } while (0) -#define emith_write_sr(sr, srcr) do { \ - emith_lsr(sr, sr, 10); \ - emith_or_r_r_r_lsl(sr, sr, srcr, 22); \ - emith_ror(sr, sr, 22); \ -} while (0) +#define emith_write_sr(sr, srcr) \ + EMIT(A64_BFI_IMM(sr, srcr, 0, 10)) #define emith_carry_to_t(srr, is_sub) do { \ emith_lsr(sr, sr, 1); \ diff --git a/cpu/drc/emit_mips.c b/cpu/drc/emit_mips.c index 062737f6..753c3122 100644 --- a/cpu/drc/emit_mips.c +++ b/cpu/drc/emit_mips.c @@ -1,5 +1,5 @@ /* - * Basic macros to emit MIPS II/MIPS32 Release 1 instructions and some utils + * Basic macros to emit MIPS32/MIPS64 Release 1 or 2 instructions and some utils * Copyright (C) 2019 kub * * This work is licensed under the terms of MAME license. @@ -65,9 +65,10 @@ // opcode field (encoded in op) enum { OP__FN=000, OP__RT, OP_J, OP_JAL, OP_BEQ, OP_BNE, OP_BLEZ, OP_BGTZ }; enum { OP_ADDI=010, OP_ADDIU, OP_SLTI, OP_SLTIU, OP_ANDI, OP_ORI, OP_XORI, OP_LUI }; +enum { OP_DADDI=030, OP_DADDIU, OP_LDL, OP_LDR, OP__FN2=034, OP__FN3=037 }; enum { OP_LB=040, OP_LH, OP_LWL, OP_LW, OP_LBU, OP_LHU, OP_LWR, OP_LWU }; enum { OP_SB=050, OP_SH, OP_SWL, OP_SW, OP_SDL, OP_SDR, OP_SWR }; -enum { OP_DADDI=030, OP_DADDIU, OP_LDL, OP_LDR, OP_SD=067, OP_LD=077 }; +enum { OP_SD=067, OP_LD=077 }; // function field (encoded in fn if opcode = OP__FN) enum { FN_SLL=000, __(01), FN_SRL, FN_SRA, FN_SLLV, __(05), FN_SRLV, FN_SRAV }; enum { FN_JR=010, FN_JALR, FN_MOVZ, FN_MOVN, FN_SYNC=017 }; @@ -76,39 +77,54 @@ enum { FN_MULT=030, FN_MULTU, FN_DIV, FN_DIVU, FN_DMULT, FN_DMULTU, FN_DDIV, FN_ enum { FN_ADD=040, FN_ADDU, FN_SUB, FN_SUBU, FN_AND, FN_OR, FN_XOR, FN_NOR }; enum { FN_SLT=052, FN_SLTU, FN_DADD, FN_DADDU, FN_DSUB, FN_DSUBU }; enum { FN_DSLL=070, __(71), FN_DSRL, FN_DSRA, FN_DSLL32, __(75), FN_DSRL32, FN_DSRA32 }; +// function field (encoded in fn if opcode = OP__FN2) +enum { FN2_MADD=000, FN2_MADDU, FN2_MUL, __(03), FN2_MSUB, FN2_MSUBU }; +enum { FN2_CLZ=040, FN2_CLO, FN2_DCLZ=044, FN2_DCLO }; +// function field (encoded in fn if opcode = OP__FN3) +enum { FN3_EXT=000, FN3_DEXTM, FN3_DEXTU, FN3_DEXT, FN3_INS, FN3_DINSM, FN3_DINSU, FN3_DINS }; +enum { FN3_BSHFL=040, FN3_DBSHFL=044 }; // rt field (encoded in rt if opcode = OP__RT) enum { RT_BLTZ=000, RT_BGEZ, RT_BLTZAL=020, RT_BGEZAL, RT_SYNCI=037 }; +// bit shuffle function (encoded in sa if function = FN3_BSHFL) +enum { BS_SBH=002, BS_SHD=005, BS_SEB=020, BS_SEH=030 }; +// r (rotate) bit function (encoded in rs/sa if function = FN_SRL/FN_SRLV) +enum { RB_SRL=0, RB_ROTR=1 }; + #define MIPS_NOP 000 // null operation: SLL r0, r0, #0 // arithmetic/logical -#define MIPS_OP_REG(op, rd, rs, rt) \ - MIPS_INSN(OP__FN, rs, rt, rd, _, op) // R-type, SPECIAL +#define MIPS_OP_REG(op, sa, rd, rs, rt) \ + MIPS_INSN(OP__FN, rs, rt, rd, sa, op) // R-type, SPECIAL +#define MIPS_OP2_REG(op, sa, rd, rs, rt) \ + MIPS_INSN(OP__FN2, rs, rt, rd, sa, op) // R-type, SPECIAL2 +#define MIPS_OP3_REG(op, sa, rd, rs, rt) \ + MIPS_INSN(OP__FN3, rs, rt, rd, sa, op) // R-type, SPECIAL3 #define MIPS_OP_IMM(op, rt, rs, imm) \ MIPS_INSN(op, rs, rt, _, _, (u16)(imm)) // I-type // rd = rs OP rt #define MIPS_ADD_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_ADDU, rd, rs, rt) + MIPS_OP_REG(FN_ADDU,_, rd, rs, rt) #define MIPS_DADD_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_DADDU, rd, rs, rt) + MIPS_OP_REG(FN_DADDU,_, rd, rs, rt) #define MIPS_SUB_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_SUBU, rd, rs, rt) + MIPS_OP_REG(FN_SUBU,_, rd, rs, rt) #define MIPS_DSUB_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_DSUBU, rd, rs, rt) + MIPS_OP_REG(FN_DSUBU,_, rd, rs, rt) #define MIPS_NEG_REG(rd, rt) \ MIPS_SUB_REG(rd, Z0, rt) #define MIPS_XOR_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_XOR, rd, rs, rt) + MIPS_OP_REG(FN_XOR,_, rd, rs, rt) #define MIPS_OR_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_OR, rd, rs, rt) + MIPS_OP_REG(FN_OR,_, rd, rs, rt) #define MIPS_AND_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_AND, rd, rs, rt) + MIPS_OP_REG(FN_AND,_, rd, rs, rt) #define MIPS_NOR_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_NOR, rd, rs, rt) + MIPS_OP_REG(FN_NOR,_, rd, rs, rt) #define MIPS_MOVE_REG(rd, rs) \ MIPS_OR_REG(rd, rs, Z0) @@ -117,17 +133,29 @@ enum { RT_BLTZ=000, RT_BGEZ, RT_BLTZAL=020, RT_BGEZAL, RT_SYNCI=037 }; // rd = rt SHIFT rs #define MIPS_LSL_REG(rd, rt, rs) \ - MIPS_OP_REG(FN_SLLV, rd, rs, rt) + MIPS_OP_REG(FN_SLLV,_, rd, rs, rt) #define MIPS_LSR_REG(rd, rt, rs) \ - MIPS_OP_REG(FN_SRLV, rd, rs, rt) + MIPS_OP_REG(FN_SRLV,RB_SRL, rd, rs, rt) #define MIPS_ASR_REG(rd, rt, rs) \ - MIPS_OP_REG(FN_SRAV, rd, rs, rt) + MIPS_OP_REG(FN_SRAV,_, rd, rs, rt) +#define MIPS_ROR_REG(rd, rt, rs) \ + MIPS_OP_REG(FN_SRLV,RB_ROTR, rd, rs, rt) + +#define MIPS_SEB_REG(rd, rt) \ + MIPS_OP3_REG(FN3_BSHFL, BS_SEB, rd, _, rt) +#define MIPS_SEH_REG(rd, rt) \ + MIPS_OP3_REG(FN3_BSHFL, BS_SEH, rd, _, rt) + +#define MIPS_EXT_IMM(rt, rs, lsb, sz) \ + MIPS_OP3_REG(FN3_EXT, lsb, (sz)-1, rs, rt) +#define MIPS_INS_IMM(rt, rs, lsb, sz) \ + MIPS_OP3_REG(FN3_INS, lsb, (lsb)+(sz)-1, rs, rt) // rd = (rs < rt) #define MIPS_SLT_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_SLT, rd, rs, rt) + MIPS_OP_REG(FN_SLT,_, rd, rs, rt) #define MIPS_SLTU_REG(rd, rs, rt) \ - MIPS_OP_REG(FN_SLTU, rd, rs, rt) + MIPS_OP_REG(FN_SLTU,_, rd, rs, rt) // rt = rs OP imm16 #define MIPS_ADD_IMM(rt, rs, imm16) \ @@ -152,9 +180,11 @@ enum { RT_BLTZ=000, RT_BGEZ, RT_BLTZAL=020, RT_BGEZAL, RT_SYNCI=037 }; #define MIPS_LSL_IMM(rd, rt, bits) \ MIPS_INSN(OP__FN, _, rt, rd, bits, FN_SLL) #define MIPS_LSR_IMM(rd, rt, bits) \ - MIPS_INSN(OP__FN, _, rt, rd, bits, FN_SRL) + MIPS_INSN(OP__FN, RB_SRL, rt, rd, bits, FN_SRL) #define MIPS_ASR_IMM(rd, rt, bits) \ MIPS_INSN(OP__FN, _, rt, rd, bits, FN_SRA) +#define MIPS_ROR_IMM(rd, rt, bits) \ + MIPS_INSN(OP__FN, RB_ROTR, rt, rd, bits, FN_SRL) #define MIPS_DLSL_IMM(rd, rt, bits) \ MIPS_INSN(OP__FN, _, rt, rd, bits, FN_DSLL) @@ -170,13 +200,17 @@ enum { RT_BLTZ=000, RT_BGEZ, RT_BLTZAL=020, RT_BGEZAL, RT_SYNCI=037 }; // multiplication #define MIPS_MULT(rt, rs) \ - MIPS_OP_REG(FN_MULT, _, rs, rt) + MIPS_OP_REG(FN_MULT,_, _, rs, rt) #define MIPS_MULTU(rt, rs) \ - MIPS_OP_REG(FN_MULTU, _, rs, rt) + MIPS_OP_REG(FN_MULTU,_, _, rs, rt) +#define MIPS_MADD(rt, rs) \ + MIPS_OP2_REG(FN_MADD,_, _, rs, rt) +#define MIPS_MADDU(rt, rs) \ + MIPS_OP2_REG(FN_MADDU,_, _, rs, rt) #define MIPS_MFLO(rd) \ - MIPS_OP_REG(FN_MFLO, rd, _, _) + MIPS_OP_REG(FN_MFLO,_, rd, _, _) #define MIPS_MFHI(rd) \ - MIPS_OP_REG(FN_MFHI, rd, _, _) + MIPS_OP_REG(FN_MFHI,_, rd, _, _) // branching @@ -185,9 +219,9 @@ enum { RT_BLTZ=000, RT_BGEZ, RT_BLTZAL=020, RT_BGEZAL, RT_SYNCI=037 }; #define MIPS_JAL(abs26) \ MIPS_INSN(OP_JAL, _,_,_,_, (abs26) >> 2) #define MIPS_JR(rs) \ - MIPS_OP_REG(FN_JR,_,rs,_) + MIPS_OP_REG(FN_JR,_, _,rs,_) #define MIPS_JALR(rd, rs) \ - MIPS_OP_REG(FN_JALR,rd,rs,_) + MIPS_OP_REG(FN_JALR,_, rd,rs,_) // conditional branches; no condition code, these compare rs against rt or Z0 #define MIPS_BEQ (OP_BEQ << 5) // rs == rt (rt in lower 5 bits) @@ -234,7 +268,7 @@ enum { RT_BLTZ=000, RT_BGEZ, RT_BLTZAL=020, RT_BGEZAL, RT_SYNCI=037 }; // pointer operations -#if __mips == 4 || __mips == 64 +#if _MIPS_SZPTR == 64 #define OP_LP OP_LD #define OP_SP OP_SD #define OP_PADDIU OP_DADDIU @@ -524,8 +558,8 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm) #define emith_add_r_r_r_lsl_ptr(d, s1, s2, simm) do { \ if (simm) { \ EMIT(MIPS_LSL_IMM(AT, s2, simm)); \ - EMIT(MIPS_OP_REG(FN_PADDU, d, s1, AT)); \ - } else EMIT(MIPS_OP_REG(FN_PADDU, d, s1, s2)); \ + EMIT(MIPS_OP_REG(FN_PADDU,_, d, s1, AT)); \ + } else EMIT(MIPS_OP_REG(FN_PADDU,_, d, s1, s2)); \ } while (0) #define emith_add_r_r_r_lsl(d, s1, s2, simm) do { \ if (simm) { \ @@ -544,10 +578,10 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm) #define emith_addf_r_r_r_lsl_ptr(d, s1, s2, simm) do { \ if (simm) { \ EMIT(MIPS_LSL_IMM(AT, s2, simm)); \ - EMIT(MIPS_OP_REG(FN_PADDU, FNZ, s1, AT)); \ + EMIT(MIPS_OP_REG(FN_PADDU,_, FNZ, s1, AT)); \ emith_set_arith_flags(d, s1, AT, 0, 0); \ } else { \ - EMIT(MIPS_OP_REG(FN_PADDU, FNZ, s1, s2)); \ + EMIT(MIPS_OP_REG(FN_PADDU,_, FNZ, s1, s2)); \ emith_set_arith_flags(d, s1, s2, 0, 0); \ } \ } while (0) @@ -752,7 +786,7 @@ static void emith_set_compare_flags(int rs, int rt, s32 imm) // move immediate static void emith_move_imm(int r, uintptr_t imm) { -#if __mips == 4 || __mips == 64 +#if _MIPS_SZPTR == 64 if ((s32)imm != imm) { emith_move_imm(r, imm >> 32); if (imm & 0xffff0000) { @@ -803,10 +837,10 @@ static void emith_add_imm(int ptr, int rd, int rs, u32 imm) EMIT(MIPS_OP_IMM(ptr ? OP_PADDIU:OP_ADDIU, rd,rs,imm)); } else if ((s32)imm < 0) { emith_move_r_imm(AT, -imm); - EMIT(MIPS_OP_REG((ptr ? FN_PSUBU:FN_SUBU), rd,rs,AT)); + EMIT(MIPS_OP_REG((ptr ? FN_PSUBU:FN_SUBU),_, rd,rs,AT)); } else { emith_move_r_imm(AT, imm); - EMIT(MIPS_OP_REG((ptr ? FN_PADDU:FN_ADDU), rd,rs,AT)); + EMIT(MIPS_OP_REG((ptr ? FN_PADDU:FN_ADDU),_, rd,rs,AT)); } } @@ -881,7 +915,7 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm) { if (imm >> 16) { emith_move_r_imm(AT, imm); - EMIT(MIPS_OP_REG(FN_AND + (op-OP_ANDI), rd, rs, AT)); + EMIT(MIPS_OP_REG(FN_AND + (op-OP_ANDI),_, rd, rs, AT)); } else if (op == OP_ANDI || imm || rd != rs) EMIT(MIPS_OP_IMM(op, rd, rs, imm)); } @@ -936,20 +970,31 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm) #define emith_asr(d, s, cnt) \ EMIT(MIPS_ASR_IMM(d, s, cnt)) -// NB: mips32r2 has ROT (SLR with R bit set) +#if defined(__mips_isa_rev) && __mips_isa_rev >= 2 +#define emith_ror(d, s, cnt) do { \ + EMIT(MIPS_ROR_IMM(d, s, cnt)); \ +} while (0) +#else #define emith_ror(d, s, cnt) do { \ EMIT(MIPS_LSL_IMM(AT, s, 32-(cnt))); \ EMIT(MIPS_LSR_IMM(d, s, cnt)); \ EMIT(MIPS_OR_REG(d, d, AT)); \ } while (0) +#endif #define emith_ror_c(cond, d, s, cnt) \ emith_ror(d, s, cnt) +#if defined(__mips_isa_rev) && __mips_isa_rev >= 2 +#define emith_rol(d, s, cnt) do { \ + EMIT(MIPS_ROR_IMM(d, s, 32-(cnt))); \ +} while (0) +#else #define emith_rol(d, s, cnt) do { \ EMIT(MIPS_LSR_IMM(AT, s, 32-(cnt))); \ EMIT(MIPS_LSL_IMM(d, s, cnt)); \ EMIT(MIPS_OR_REG(d, d, AT)); \ } while (0) +#endif #define emith_rorc(d) do { \ emith_lsr(d, d, 1); \ @@ -963,7 +1008,6 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm) } while (0) // NB: all flag setting shifts make V undefined -// NB: mips32r2 has EXT (useful for extracting C) #define emith_lslf(d, s, cnt) do { \ int _s = s; \ if ((cnt) > 1) { \ @@ -1040,7 +1084,10 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm) } while (0) // signed/unsigned extend -// NB: mips32r2 has EXT and INS +#if defined(__mips_isa_rev) && __mips_isa_rev >= 2 +#define emith_clear_msb(d, s, count) /* bits to clear */ \ + EMIT(MIPS_EXT_IMM(d, s, 0, 32-(count))) +#else #define emith_clear_msb(d, s, count) /* bits to clear */ do { \ u32 t; \ if ((count) >= 16) { \ @@ -1052,14 +1099,27 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm) emith_lsr(d, d, count); \ } \ } while (0) +#endif #define emith_clear_msb_c(cond, d, s, count) \ emith_clear_msb(d, s, count) -// NB: mips32r2 has SE[BH]H +#if defined(__mips_isa_rev) && __mips_isa_rev >= 2 +#define emith_sext(d, s, count) /* bits to keep */ do { \ + if (count == 8) \ + EMIT(MIPS_SEB_REG(d, s)); \ + else if (count == 16) \ + EMIT(MIPS_SEH_REG(d, s)); \ + else { \ + emith_lsl(d, s, 32-(count)); \ + emith_asr(d, d, 32-(count)); \ + } \ +} while (0) +#else #define emith_sext(d, s, count) /* bits to keep */ do { \ emith_lsl(d, s, 32-(count)); \ emith_asr(d, d, 32-(count)); \ } while (0) +#endif // multiply Rd = Rn*Rm (+ Ra); NB: next 2 insns after MFLO/MFHI mustn't be MULT static u8 *last_lohi; @@ -1658,16 +1718,26 @@ static int emith_cond_check(int cond, int *r) EMITH_SJMP_END(DCOND_EQ); \ } while (0) +#if defined(__mips_isa_rev) && __mips_isa_rev >= 2 +#define emith_write_sr(sr, srcr) \ + EMIT(MIPS_INS_IMM(sr, srcr, 0, 10)) +#else #define emith_write_sr(sr, srcr) do { \ emith_lsr(sr, sr , 10); emith_lsl(sr, sr, 10); \ emith_lsl(AT, srcr, 22); emith_lsr(AT, AT, 22); \ emith_or_r_r(sr, AT); \ } while (0) +#endif +#if defined(__mips_isa_rev) && __mips_isa_rev >= 2 +#define emith_carry_to_t(sr, is_sub) \ + EMIT(MIPS_INS_IMM(sr, FC, 0, 1)) +#else #define emith_carry_to_t(sr, is_sub) do { \ emith_and_r_imm(sr, 0xfffffffe); \ emith_or_r_r(sr, FC); \ } while (0) +#endif #define emith_t_to_carry(sr, is_sub) do { \ emith_and_r_r_imm(FC, sr, 1); \ diff --git a/cpu/drc/emit_riscv.c b/cpu/drc/emit_riscv.c index 0f614f18..ed45e01c 100644 --- a/cpu/drc/emit_riscv.c +++ b/cpu/drc/emit_riscv.c @@ -1499,10 +1499,10 @@ static int emith_cond_check(int cond, int *r, int *s) emith_tst_r_imm(sr, Q); /* if (Q ^ M) */ \ EMITH_JMP3_START(DCOND_EQ); \ emith_add_r_r_r(rn, t_, rm); \ - EMIT(R5_SLTU_REG(FC, rn, t_)); \ + EMIT(R5_SLTU_REG(FC, rn, t_)); \ EMITH_JMP3_MID(DCOND_EQ); \ emith_sub_r_r_r(rn, t_, rm); \ - EMIT(R5_SLTU_REG(FC, t_, rn)); \ + EMIT(R5_SLTU_REG(FC, t_, rn)); \ EMITH_JMP3_END(); \ emith_eor_r_r(sr, FC); /* T ^= carry */ \ rcache_free_tmp(t_); \ diff --git a/platform/common/dismips.c b/platform/common/dismips.c index f9888f2a..61c70bfe 100644 --- a/platform/common/dismips.c +++ b/platform/common/dismips.c @@ -56,13 +56,15 @@ static char *const register_names[32] = { enum insn_type { REG_DTS, REG_TS, // 3, 2, or 1 regs - REG_DS, REG_D, REG_S, + REG_DS, REG_DT, REG_D, REG_S, S_IMM_DT, // 2 regs with shift amount + F_IMM_TS, // 2 regs with bitfield spec B_IMM_S, B_IMM_TS, // pc-relative branches with 1 or 2 regs J_IMM, // region-relative jump - A_IMM_TS, // arithmetic immediate with 1 or 2 regs - L_IMM_T, L_IMM_TS, // logical immediate with 2 regs + A_IMM_TS, // arithmetic immediate with 2 regs + L_IMM_T, L_IMM_TS, // logical immediate with 1 or 2 regs M_IMM_TS, // memory indexed with 2 regs + SR_BIT = 0x80 // shift right with R-bit }; struct insn { @@ -77,10 +79,10 @@ struct insn { #define OP_SPECIAL 0x00 static const struct insn special_insns[] = { {0x00, S_IMM_DT, "sll"}, - {0x02, S_IMM_DT, "srl"}, + {0x02, S_IMM_DT|SR_BIT, "srl\0rotr"}, {0x03, S_IMM_DT, "sra"}, {0x04, REG_DTS, "sllv"}, - {0x06, REG_DTS, "srlv"}, + {0x06, REG_DTS|SR_BIT, "srlv\0rotrv"}, {0x07, REG_DTS, "srav"}, {0x08, REG_S, "jr"}, {0x09, REG_DS, "jalr"}, @@ -94,7 +96,7 @@ static const struct insn special_insns[] = { {0x12, REG_D, "mflo"}, {0x13, REG_S, "mtlo"}, {0x14, REG_DTS, "dsllv"}, - {0x16, REG_DTS, "dslrv"}, + {0x16, REG_DTS|SR_BIT, "dsrlv\0drotrv"}, {0x17, REG_DTS, "dsrav"}, {0x18, REG_TS, "mult"}, {0x19, REG_TS, "multu"}, @@ -125,10 +127,10 @@ static const struct insn special_insns[] = { // {0x34, REG_TS, "teq" }, // {0x36, REG_TS, "tne" }, {0x38, S_IMM_DT, "dsll"}, - {0x3A, S_IMM_DT, "dsrl"}, + {0x3A, S_IMM_DT|SR_BIT, "dsrl\0drotrv"}, {0x3B, S_IMM_DT, "dsra"}, {0x3C, S_IMM_DT, "dsll32"}, - {0x3E, S_IMM_DT, "dsrl32"}, + {0x3E, S_IMM_DT|SR_BIT, "dsrl32\0drotr32"}, {0x3F, S_IMM_DT, "dsra32"}, }; @@ -146,6 +148,32 @@ static const struct insn special2_insns[] = { {0x25, REG_DS, "dclo" }, }; +// instructions with opcode SPECIAL3 (R-type) +#define OP_SPECIAL3 0x1F +static const struct insn special3_insns[] = { + {0x00, F_IMM_TS, "ext" }, + {0x01, F_IMM_TS, "dextm" }, + {0x02, F_IMM_TS, "dextu" }, + {0x03, F_IMM_TS, "dext" }, + {0x04, F_IMM_TS, "ins" }, + {0x05, F_IMM_TS, "dinsm" }, + {0x06, F_IMM_TS, "dinsu" }, + {0x07, F_IMM_TS, "dins" }, +}; + +// instruction with opcode SPECIAL3 and function *BSHFL +#define FN_BSHFL 0x20 +static const struct insn bshfl_insns[] = { + {0x02, REG_DT, "wsbh" }, + {0x10, REG_DT, "seb" }, + {0x18, REG_DT, "seh" }, +}; +#define FN_DBSHFL 0x24 +static const struct insn dbshfl_insns[] = { + {0x02, REG_DT, "dsbh" }, + {0x05, REG_DT, "dshd" }, +}; + // instructions with opcode REGIMM (I-type) #define OP_REGIMM 0x01 static const struct insn regimm_insns[] = { @@ -240,6 +268,20 @@ static const struct insn *decode_insn(uint32_t insn) op = insn & 0x3f; pi = special2_insns; r = ARRAY_SIZE(special2_insns)-1; + } else if (op == OP_SPECIAL3) { + op = insn & 0x3f; + if (op == FN_BSHFL) { + op = (insn >> 6) & 0x1f; + pi = bshfl_insns; + r = ARRAY_SIZE(bshfl_insns)-1; + } else if (op == FN_DBSHFL) { + op = (insn >> 6) & 0x1f; + pi = dbshfl_insns; + r = ARRAY_SIZE(dbshfl_insns)-1; + } else { + pi = special3_insns; + r = ARRAY_SIZE(special3_insns)-1; + } } else if (op == OP_REGIMM) { op = (insn>>16) & 0x1f; pi = regimm_insns; @@ -280,7 +322,7 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, uintptr_t *sy char *rs = register_names[(insn >> 21) & 0x1f]; char *rt = register_names[(insn >> 16) & 0x1f]; char *rd = register_names[(insn >> 11) & 0x1f]; - int sa = (insn >> 6) & 0x1f; + int sa = (insn >> 6) & 0x1f, sb = (insn >> 11) & 0x1f; int imm = (int16_t) insn; *sym = 0; @@ -289,10 +331,12 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, uintptr_t *sy return 0; } - switch (pi->type) { + switch (pi->type & ~SR_BIT) { case REG_DTS: if ((insn & 0x3f) == 0x25 /*OR*/ && (insn & 0x1f0000) == 0 /*zero*/) snprintf(buf, buflen, "move %s, %s", rd, rs); + else if ((pi->type & SR_BIT) && (insn & (1<<6))) + snprintf(buf, buflen, "%s %s, %s, %s", pi->name+strlen(pi->name)+1, rd, rs, rt); else snprintf(buf, buflen, "%s %s, %s, %s", pi->name, rd, rs, rt); break; @@ -302,6 +346,9 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, uintptr_t *sy case REG_DS: snprintf(buf, buflen, "%s %s, %s", pi->name, rd, rs); break; + case REG_DT: + snprintf(buf, buflen, "%s %s, %s", pi->name, rd, rt); + break; case REG_D: snprintf(buf, buflen, "%s %s", pi->name, rd); break; @@ -311,9 +358,17 @@ int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, uintptr_t *sy case S_IMM_DT: if (insn == 0x00000000) snprintf(buf, buflen, "nop"); + else if ((pi->type & SR_BIT) && (insn & (1<<21))) + snprintf(buf, buflen, "%s %s, %s, %d", pi->name+strlen(pi->name)+1, rd, rt, sa); else snprintf(buf, buflen, "%s %s, %s, %d", pi->name, rd, rt, sa); break; + case F_IMM_TS: + if (insn & 0x01) sb+=32; + if (insn & 0x02) sa+=32; + if (insn & 0x04) sb-=sa; + snprintf(buf, buflen, "%s %s, %s, %d, %d", pi->name, rt, rs, sa, sb+1); + break; case B_IMM_S: *sym = b_target(pc, insn); snprintf(buf, buflen, "%s %s, 0x%lx", pi->name, rs, *sym); -- 2.39.2