Message ID | 1412765732-45369-15-git-send-email-leon.alrae@imgtec.com |
---|---|
State | New |
Headers | show |
I have just few minor comments. Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com> regards, Yongbok On 08/10/2014 11:55, Leon Alrae wrote: > Signed-off-by: Leon Alrae <leon.alrae@imgtec.com> > --- > v3: > * use sextract32 instead of open coding the bit field extraction > * replace _i64 with _tl in DAHI, DATI and DAUI > * fix misleading LDPC comment > --- > disas/mips.c | 42 ++++++++++- > target-mips/translate.c | 197 +++++++++++++++++++++++++++++++++++++++++++++--- > 2 files changed, 225 insertions(+), 14 deletions(-) > > diff --git a/disas/mips.c b/disas/mips.c > index 8234369..091f4e2 100644 > --- a/disas/mips.c > +++ b/disas/mips.c > @@ -407,6 +407,12 @@ struct mips_opcode > "+3" UDI immediate bits 6-20 > "+4" UDI immediate bits 6-25 > > + R6 immediates/displacements : > + (adding suffix to 'o' to avoid adding new characters) > + "+o" 9 bits immediate/displacement (shift = 7) > + "+o1" 18 bits immediate/displacement (shift = 0) > + "+o2" 19 bits immediate/displacement (shift = 0) > + > Other: > "()" parens surrounding optional value > "," separates operands > @@ -1217,6 +1223,17 @@ const struct mips_opcode mips_builtin_opcodes[] = > them first. The assemblers uses a hash table based on the > instruction name anyhow. */ > /* name, args, match, mask, pinfo, membership */ > +{"lwpc", "s,+o2", 0xec080000, 0xfc180000, WR_d, 0, I32R6}, > +{"lwupc", "s,+o2", 0xec100000, 0xfc180000, WR_d, 0, I32R6}, I64R6 > +{"ldpc", "s,+o1", 0xec180000, 0xfc1c0000, WR_d, 0, I64R6}, > +{"addiupc", "s,+o2", 0xec000000, 0xfc180000, WR_d, 0, I32R6}, > +{"auipc", "s,u", 0xec1e0000, 0xfc1f0000, WR_d, 0, I32R6}, > +{"aluipc", "s,u", 0xec1f0000, 0xfc1f0000, WR_d, 0, I32R6}, > +{"daui", "s,t,u", 0x74000000, 0xfc000000, RD_s|WR_t, 0, I64R6}, > +{"dahi", "s,u", 0x04060000, 0xfc1f0000, RD_s, 0, I64R6}, > +{"dati", "s,u", 0x041e0000, 0xfc1f0000, RD_s, 0, I64R6}, > +{"lsa", "d,s,t", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, > +{"dlsa", "d,s,t", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, I64R6}, > {"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, > {"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, > {"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, > @@ -1822,6 +1839,7 @@ const struct mips_opcode mips_builtin_opcodes[] = > {"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, > {"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, > {"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, > +{"aui", "s,t,u", 0x3c000000, 0xfc000000, RD_s|WR_t, 0, I32R6}, > {"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, > {"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, > {"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, > @@ -3645,10 +3663,28 @@ print_insn_args (const char *d, > break; > > case 'o': > - delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; > - if (delta & 0x8000) { > - delta |= ~0xffff; > + switch (*(d+1)) { > + case '1': > + d++; > + delta = l & ((1 << 18) - 1); > + if (delta & 0x20000) { > + delta |= ~0x1ffff; > + } > + break; > + case '2': > + d++; > + delta = l & ((1 << 19) - 1); > + if (delta & 0x40000) { > + delta |= ~0x3ffff; > + } > + break; > + default: > + delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; > + if (delta & 0x8000) { > + delta |= ~0xffff; > + } > } > + > (*info->fprintf_func) (info->stream, "%d", delta); > break; > > diff --git a/target-mips/translate.c b/target-mips/translate.c > index 06ececb..6f64c47 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -75,6 +75,7 @@ enum { > OPC_BGTZ = (0x07 << 26), > OPC_BGTZL = (0x17 << 26), > OPC_JALX = (0x1D << 26), /* MIPS 16 only */ > + OPC_DAUI = (0x1D << 26), > OPC_JALXS = OPC_JALX | 0x5, > /* Load and stores */ > OPC_LDL = (0x1A << 26), > @@ -141,8 +142,25 @@ enum { > /* Cache and prefetch */ > OPC_CACHE = (0x2F << 26), > OPC_PREF = (0x33 << 26), > - /* Reserved major opcode */ > - OPC_MAJOR3B_RESERVED = (0x3B << 26), > + /* PC-relative address computation / loads */ > + OPC_PCREL = (0x3B << 26), > +}; > + > +/* PC-relative address computation / loads */ > +#define MASK_OPC_PCREL_TOP2BITS(op) (MASK_OP_MAJOR(op) | (op & (3 << 19))) > +#define MASK_OPC_PCREL_TOP5BITS(op) (MASK_OP_MAJOR(op) | (op & (0x1f << 16))) There must be better name for this macro. It confused me that was looking like 31 and 30 bits. Just naming though... > +enum { > + /* Instructions determined by bits 19 and 20 */ > + OPC_ADDIUPC = OPC_PCREL | (0 << 19), > + R6_OPC_LWPC = OPC_PCREL | (1 << 19), > + OPC_LWUPC = OPC_PCREL | (2 << 19), > + > + /* Instructions determined by bits 16 ... 20 */ > + OPC_AUIPC = OPC_PCREL | (0x1e << 16), > + OPC_ALUIPC = OPC_PCREL | (0x1f << 16), > + > + /* Other */ > + R6_OPC_LDPC = OPC_PCREL | (6 << 18), > }; > > /* MIPS special opcodes */ > @@ -231,7 +249,6 @@ enum { > OPC_SPIM = 0x0E | OPC_SPECIAL, /* unofficial */ > OPC_SYNC = 0x0F | OPC_SPECIAL, > > - OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL, > OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL, > OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL, > OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL, > @@ -266,6 +283,9 @@ enum { > R6_OPC_DCLZ = 0x12 | OPC_SPECIAL, > R6_OPC_DCLO = 0x13 | OPC_SPECIAL, > R6_OPC_SDBBP = 0x0e | OPC_SPECIAL, > + > + OPC_LSA = 0x05 | OPC_SPECIAL, > + OPC_DLSA = 0x15 | OPC_SPECIAL, > }; > > /* Multiplication variants of the vr54xx. */ > @@ -309,6 +329,9 @@ enum { > OPC_TEQI = (0x0C << 16) | OPC_REGIMM, > OPC_TNEI = (0x0E << 16) | OPC_REGIMM, > OPC_SYNCI = (0x1F << 16) | OPC_REGIMM, > + > + OPC_DAHI = (0x06 << 16) | OPC_REGIMM, > + OPC_DATI = (0x1e << 16) | OPC_REGIMM, > }; > > /* Special2 opcodes */ > @@ -2162,8 +2185,15 @@ static void gen_logic_imm(DisasContext *ctx, uint32_t opc, > regnames[rs], uimm); > break; > case OPC_LUI: > - tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); > - MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); > + if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) { > + /* OPC_AUI */ > + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm << 16); > + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); > + MIPS_DEBUG("aui %s, %s, %04x", regnames[rt], regnames[rs], imm); > + } else { > + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); > + MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); > + } > break; > > default: > @@ -2767,6 +2797,77 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) > MIPS_DEBUG("%s %s", opn, regnames[reg]); > } > > +static inline void gen_r6_ld(target_long addr, int reg, int memidx, > + TCGMemOp memop) > +{ > + TCGv t0 = tcg_const_tl(addr); > + tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); > + gen_store_gpr(t0, reg); > + tcg_temp_free(t0); > +} > + > +static inline void gen_pcrel(DisasContext *ctx, int rs, int16_t imm) > +{ > + target_long offset; > + target_long addr; > + > + switch (MASK_OPC_PCREL_TOP2BITS(ctx->opcode)) { > + case OPC_ADDIUPC: > + if (rs != 0) { > + offset = sextract32(ctx->opcode << 2, 0, 21); > + addr = addr_add(ctx, ctx->pc, offset); > + tcg_gen_movi_tl(cpu_gpr[rs], addr); > + } > + break; > + case R6_OPC_LWPC: > + offset = sextract32(ctx->opcode << 2, 0, 21); > + addr = addr_add(ctx, ctx->pc, offset); > + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TESL); > + break; > +#if defined(TARGET_MIPS64) > + case OPC_LWUPC: > + check_mips_64(ctx); > + offset = sextract32(ctx->opcode << 2, 0, 21); > + addr = addr_add(ctx, ctx->pc, offset); > + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUL); > + break; > +#endif > + default: > + switch (MASK_OPC_PCREL_TOP5BITS(ctx->opcode)) { > + case OPC_AUIPC: > + if (rs != 0) { > + offset = imm << 16; > + addr = addr_add(ctx, ctx->pc, offset); > + tcg_gen_movi_tl(cpu_gpr[rs], addr); > + } > + break; > + case OPC_ALUIPC: > + if (rs != 0) { > + offset = imm << 16; > + addr = ~0xFFFF & addr_add(ctx, ctx->pc, offset); > + tcg_gen_movi_tl(cpu_gpr[rs], addr); > + } > + break; > +#if defined(TARGET_MIPS64) > + case R6_OPC_LDPC: /* bits 16 and 17 are part of immediate */ > + case R6_OPC_LDPC + (1 << 16): > + case R6_OPC_LDPC + (2 << 16): > + case R6_OPC_LDPC + (3 << 16): > + check_mips_64(ctx); > + offset = sextract32(ctx->opcode << 3, 0, 21); > + addr = addr_add(ctx, (ctx->pc & ~0x7), offset); > + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEQ); > + break; > +#endif > + default: > + MIPS_INVAL("OPC_PCREL"); > + generate_exception(ctx, EXCP_RI); > + break; > + } > + break; > + } > +} > + > static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) > { > const char *opn = "r6 mul/div"; > @@ -15097,6 +15198,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) > > op1 = MASK_SPECIAL(ctx->opcode); > switch (op1) { > + case OPC_LSA: > + if (rd != 0) { > + int imm2 = extract32(ctx->opcode, 6, 3); > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, rt); > + tcg_gen_shli_tl(t0, t0, imm2 + 1); > + tcg_gen_add_tl(t0, t0, t1); > + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); > + tcg_temp_free(t1); > + tcg_temp_free(t0); > + } > + break; > case OPC_MULT ... OPC_DIVU: > op2 = MASK_R6_MULDIV(ctx->opcode); > switch (op2) { > @@ -15134,6 +15249,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) > generate_exception(ctx, EXCP_DBp); > break; > #if defined(TARGET_MIPS64) > + case OPC_DLSA: > + check_mips_64(ctx); > + if (rd != 0) { > + int imm2 = extract32(ctx->opcode, 6, 3); > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + gen_load_gpr(t0, rs); > + gen_load_gpr(t1, rt); > + tcg_gen_shli_tl(t0, t0, imm2 + 1); > + tcg_gen_add_tl(cpu_gpr[rd], t0, t1); > + tcg_temp_free(t1); > + tcg_temp_free(t0); > + } > + break; > case R6_OPC_DCLO: > case R6_OPC_DCLZ: > if (rt == 0 && sa == 1) { > @@ -15319,13 +15448,18 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) > case OPC_TNE: > gen_trap(ctx, op1, rs, rt, -1); > break; > - case OPC_PMON: /* Pmon entry point, also R4010 selsl */ > + case OPC_LSA: /* OPC_PMON */ > + if (ctx->insn_flags & ISA_MIPS32R6) { > + decode_opc_special_r6(env, ctx); > + } else { > + /* Pmon entry point, also R4010 selsl */ indentation :) > #ifdef MIPS_STRICT_STANDARD > MIPS_INVAL("PMON / selsl"); > generate_exception(ctx, EXCP_RI); > #else > gen_helper_0e0i(pmon, sa); > #endif > + } > break; > case OPC_SYSCALL: > generate_exception(ctx, EXCP_SYSCALL); > @@ -16297,6 +16431,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > check_dsp(ctx); > gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); > break; > +#if defined(TARGET_MIPS64) > + case OPC_DAHI: > + check_insn(ctx, ISA_MIPS32R6); > + check_mips_64(ctx); > + if (rs != 0) { > + tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 32); > + } > + MIPS_DEBUG("dahi %s, %04x", regnames[rs], imm); > + break; > + case OPC_DATI: > + check_insn(ctx, ISA_MIPS32R6); > + check_mips_64(ctx); > + if (rs != 0) { > + tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 48); > + } > + MIPS_DEBUG("dati %s, %04x", regnames[rs], imm); > + break; > +#endif > default: /* Invalid */ > MIPS_INVAL("regimm"); > generate_exception(ctx, EXCP_RI); > @@ -16409,7 +16561,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > gen_slt_imm(ctx, op, rt, rs, imm); > break; > case OPC_ANDI: /* Arithmetic with immediate opcode */ > - case OPC_LUI: > + case OPC_LUI: /* OPC_AUI */ > case OPC_ORI: > case OPC_XORI: > gen_logic_imm(ctx, op, rt, rs, imm); > @@ -16707,14 +16859,37 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > } > break; > #endif > - case OPC_JALX: > - check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); > - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; > - gen_compute_branch(ctx, op, 4, rs, rt, offset); > + case OPC_DAUI: /* OPC_JALX */ > + if (ctx->insn_flags & ISA_MIPS32R6) { > +#if defined(TARGET_MIPS64) > + /* OPC_DAUI */ > + check_mips_64(ctx); > + if (rt != 0) { > + TCGv t0 = tcg_temp_new(); > + gen_load_gpr(t0, rs); > + tcg_gen_addi_tl(cpu_gpr[rt], t0, imm << 16); > + tcg_temp_free(t0); > + } > + MIPS_DEBUG("daui %s, %s, %04x", regnames[rt], regnames[rs], imm); > +#else > + generate_exception(ctx, EXCP_RI); > + MIPS_INVAL("major opcode"); > +#endif > + } else { > + /* OPC_JALX */ > + check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); > + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; > + gen_compute_branch(ctx, op, 4, rs, rt, offset); > + } > break; > case OPC_MDMX: > check_insn(ctx, ASE_MDMX); > /* MDMX: Not implemented. */ > + break; > + case OPC_PCREL: > + check_insn(ctx, ISA_MIPS32R6); > + gen_pcrel(ctx, rs, imm); > + break; > default: /* Invalid */ > MIPS_INVAL("major opcode"); > generate_exception(ctx, EXCP_RI);
Hi Yongbok, On 13/10/2014 14:37, Yongbok Kim wrote: >> + OPC_PCREL = (0x3B << 26), >> +}; >> + >> +/* PC-relative address computation / loads */ >> +#define MASK_OPC_PCREL_TOP2BITS(op) (MASK_OP_MAJOR(op) | (op & (3 << >> 19))) >> +#define MASK_OPC_PCREL_TOP5BITS(op) (MASK_OP_MAJOR(op) | (op & (0x1f >> << 16))) > > There must be better name for this macro. > It confused me that was looking like 31 and 30 bits. > Just naming though... TOP2BITS and TOP5BITS are referring to "TTTTT" bits. R6 PC-relative family encoding: 111011.rs.TTTTT.imm16 Instructions: 111011.rs.00.<-----imm19> ADDIUPC 111011.rs.01.<----disp19> LWPC 111011.rs.10.<----disp19> LWUPC 111011.rs.110.<---disp18> LDPC 111011.rs.1110.<---imm17> reserved 111011.rs.11110.<--imm16> AUIPC 111011.rs.11111.<--imm16> ALUIPC I couldn't come up with better name having reasonable length, any suggestions are welcome. Thanks, Leon
On 08/10/2014 12:55, Leon Alrae wrote: > case OPC_LUI: > - tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); > - MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); > + if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) { > + /* OPC_AUI */ > + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm << 16); > + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); > + MIPS_DEBUG("aui %s, %s, %04x", regnames[rt], regnames[rs], imm); > + } else { > + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); > + MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); > + } > break; Coverity reported a gen_logic_imm(ctx, OPC_LUI, rs, -1, imm); where the -1 probably has to become zero now. Paolo
On 12/11/2014 21:07, Paolo Bonzini wrote: > > > On 08/10/2014 12:55, Leon Alrae wrote: >> case OPC_LUI: >> - tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); >> - MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); >> + if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) { >> + /* OPC_AUI */ >> + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm << 16); >> + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); >> + MIPS_DEBUG("aui %s, %s, %04x", regnames[rt], regnames[rs], imm); >> + } else { >> + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); >> + MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); >> + } >> break; > > Coverity reported a > > gen_logic_imm(ctx, OPC_LUI, rs, -1, imm); > > where the -1 probably has to become zero now. This line is from microMIPS decoder. We don't support microMIPS R6 in QEMU so I think this isn't an issue at the moment as (ctx->insn_flags & ISA_MIPS32R6) should always be false on a CPU with existing implementation of microMIPS. Nevertheless, I agree this should be 0 for safety, I'll correct it in 2.3. Thanks for pointing this out. Regards, Leon
diff --git a/disas/mips.c b/disas/mips.c index 8234369..091f4e2 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -407,6 +407,12 @@ struct mips_opcode "+3" UDI immediate bits 6-20 "+4" UDI immediate bits 6-25 + R6 immediates/displacements : + (adding suffix to 'o' to avoid adding new characters) + "+o" 9 bits immediate/displacement (shift = 7) + "+o1" 18 bits immediate/displacement (shift = 0) + "+o2" 19 bits immediate/displacement (shift = 0) + Other: "()" parens surrounding optional value "," separates operands @@ -1217,6 +1223,17 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"lwpc", "s,+o2", 0xec080000, 0xfc180000, WR_d, 0, I32R6}, +{"lwupc", "s,+o2", 0xec100000, 0xfc180000, WR_d, 0, I32R6}, +{"ldpc", "s,+o1", 0xec180000, 0xfc1c0000, WR_d, 0, I64R6}, +{"addiupc", "s,+o2", 0xec000000, 0xfc180000, WR_d, 0, I32R6}, +{"auipc", "s,u", 0xec1e0000, 0xfc1f0000, WR_d, 0, I32R6}, +{"aluipc", "s,u", 0xec1f0000, 0xfc1f0000, WR_d, 0, I32R6}, +{"daui", "s,t,u", 0x74000000, 0xfc000000, RD_s|WR_t, 0, I64R6}, +{"dahi", "s,u", 0x04060000, 0xfc1f0000, RD_s, 0, I64R6}, +{"dati", "s,u", 0x041e0000, 0xfc1f0000, RD_s, 0, I64R6}, +{"lsa", "d,s,t", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, +{"dlsa", "d,s,t", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, I64R6}, {"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, {"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, {"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, @@ -1822,6 +1839,7 @@ const struct mips_opcode mips_builtin_opcodes[] = {"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, {"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, {"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"aui", "s,t,u", 0x3c000000, 0xfc000000, RD_s|WR_t, 0, I32R6}, {"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, {"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, {"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, @@ -3645,10 +3663,28 @@ print_insn_args (const char *d, break; case 'o': - delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; - if (delta & 0x8000) { - delta |= ~0xffff; + switch (*(d+1)) { + case '1': + d++; + delta = l & ((1 << 18) - 1); + if (delta & 0x20000) { + delta |= ~0x1ffff; + } + break; + case '2': + d++; + delta = l & ((1 << 19) - 1); + if (delta & 0x40000) { + delta |= ~0x3ffff; + } + break; + default: + delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; + if (delta & 0x8000) { + delta |= ~0xffff; + } } + (*info->fprintf_func) (info->stream, "%d", delta); break; diff --git a/target-mips/translate.c b/target-mips/translate.c index 06ececb..6f64c47 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -75,6 +75,7 @@ enum { OPC_BGTZ = (0x07 << 26), OPC_BGTZL = (0x17 << 26), OPC_JALX = (0x1D << 26), /* MIPS 16 only */ + OPC_DAUI = (0x1D << 26), OPC_JALXS = OPC_JALX | 0x5, /* Load and stores */ OPC_LDL = (0x1A << 26), @@ -141,8 +142,25 @@ enum { /* Cache and prefetch */ OPC_CACHE = (0x2F << 26), OPC_PREF = (0x33 << 26), - /* Reserved major opcode */ - OPC_MAJOR3B_RESERVED = (0x3B << 26), + /* PC-relative address computation / loads */ + OPC_PCREL = (0x3B << 26), +}; + +/* PC-relative address computation / loads */ +#define MASK_OPC_PCREL_TOP2BITS(op) (MASK_OP_MAJOR(op) | (op & (3 << 19))) +#define MASK_OPC_PCREL_TOP5BITS(op) (MASK_OP_MAJOR(op) | (op & (0x1f << 16))) +enum { + /* Instructions determined by bits 19 and 20 */ + OPC_ADDIUPC = OPC_PCREL | (0 << 19), + R6_OPC_LWPC = OPC_PCREL | (1 << 19), + OPC_LWUPC = OPC_PCREL | (2 << 19), + + /* Instructions determined by bits 16 ... 20 */ + OPC_AUIPC = OPC_PCREL | (0x1e << 16), + OPC_ALUIPC = OPC_PCREL | (0x1f << 16), + + /* Other */ + R6_OPC_LDPC = OPC_PCREL | (6 << 18), }; /* MIPS special opcodes */ @@ -231,7 +249,6 @@ enum { OPC_SPIM = 0x0E | OPC_SPECIAL, /* unofficial */ OPC_SYNC = 0x0F | OPC_SPECIAL, - OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL, OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL, OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL, OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL, @@ -266,6 +283,9 @@ enum { R6_OPC_DCLZ = 0x12 | OPC_SPECIAL, R6_OPC_DCLO = 0x13 | OPC_SPECIAL, R6_OPC_SDBBP = 0x0e | OPC_SPECIAL, + + OPC_LSA = 0x05 | OPC_SPECIAL, + OPC_DLSA = 0x15 | OPC_SPECIAL, }; /* Multiplication variants of the vr54xx. */ @@ -309,6 +329,9 @@ enum { OPC_TEQI = (0x0C << 16) | OPC_REGIMM, OPC_TNEI = (0x0E << 16) | OPC_REGIMM, OPC_SYNCI = (0x1F << 16) | OPC_REGIMM, + + OPC_DAHI = (0x06 << 16) | OPC_REGIMM, + OPC_DATI = (0x1e << 16) | OPC_REGIMM, }; /* Special2 opcodes */ @@ -2162,8 +2185,15 @@ static void gen_logic_imm(DisasContext *ctx, uint32_t opc, regnames[rs], uimm); break; case OPC_LUI: - tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); - MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); + if (rs != 0 && (ctx->insn_flags & ISA_MIPS32R6)) { + /* OPC_AUI */ + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm << 16); + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + MIPS_DEBUG("aui %s, %s, %04x", regnames[rt], regnames[rs], imm); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); + MIPS_DEBUG("lui %s, " TARGET_FMT_lx, regnames[rt], uimm); + } break; default: @@ -2767,6 +2797,77 @@ static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) MIPS_DEBUG("%s %s", opn, regnames[reg]); } +static inline void gen_r6_ld(target_long addr, int reg, int memidx, + TCGMemOp memop) +{ + TCGv t0 = tcg_const_tl(addr); + tcg_gen_qemu_ld_tl(t0, t0, memidx, memop); + gen_store_gpr(t0, reg); + tcg_temp_free(t0); +} + +static inline void gen_pcrel(DisasContext *ctx, int rs, int16_t imm) +{ + target_long offset; + target_long addr; + + switch (MASK_OPC_PCREL_TOP2BITS(ctx->opcode)) { + case OPC_ADDIUPC: + if (rs != 0) { + offset = sextract32(ctx->opcode << 2, 0, 21); + addr = addr_add(ctx, ctx->pc, offset); + tcg_gen_movi_tl(cpu_gpr[rs], addr); + } + break; + case R6_OPC_LWPC: + offset = sextract32(ctx->opcode << 2, 0, 21); + addr = addr_add(ctx, ctx->pc, offset); + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TESL); + break; +#if defined(TARGET_MIPS64) + case OPC_LWUPC: + check_mips_64(ctx); + offset = sextract32(ctx->opcode << 2, 0, 21); + addr = addr_add(ctx, ctx->pc, offset); + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUL); + break; +#endif + default: + switch (MASK_OPC_PCREL_TOP5BITS(ctx->opcode)) { + case OPC_AUIPC: + if (rs != 0) { + offset = imm << 16; + addr = addr_add(ctx, ctx->pc, offset); + tcg_gen_movi_tl(cpu_gpr[rs], addr); + } + break; + case OPC_ALUIPC: + if (rs != 0) { + offset = imm << 16; + addr = ~0xFFFF & addr_add(ctx, ctx->pc, offset); + tcg_gen_movi_tl(cpu_gpr[rs], addr); + } + break; +#if defined(TARGET_MIPS64) + case R6_OPC_LDPC: /* bits 16 and 17 are part of immediate */ + case R6_OPC_LDPC + (1 << 16): + case R6_OPC_LDPC + (2 << 16): + case R6_OPC_LDPC + (3 << 16): + check_mips_64(ctx); + offset = sextract32(ctx->opcode << 3, 0, 21); + addr = addr_add(ctx, (ctx->pc & ~0x7), offset); + gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEQ); + break; +#endif + default: + MIPS_INVAL("OPC_PCREL"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + } +} + static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt) { const char *opn = "r6 mul/div"; @@ -15097,6 +15198,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { + case OPC_LSA: + if (rd != 0) { + int imm2 = extract32(ctx->opcode, 6, 3); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_shli_tl(t0, t0, imm2 + 1); + tcg_gen_add_tl(t0, t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; case OPC_MULT ... OPC_DIVU: op2 = MASK_R6_MULDIV(ctx->opcode); switch (op2) { @@ -15134,6 +15249,20 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) generate_exception(ctx, EXCP_DBp); break; #if defined(TARGET_MIPS64) + case OPC_DLSA: + check_mips_64(ctx); + if (rd != 0) { + int imm2 = extract32(ctx->opcode, 6, 3); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_shli_tl(t0, t0, imm2 + 1); + tcg_gen_add_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t1); + tcg_temp_free(t0); + } + break; case R6_OPC_DCLO: case R6_OPC_DCLZ: if (rt == 0 && sa == 1) { @@ -15319,13 +15448,18 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) case OPC_TNE: gen_trap(ctx, op1, rs, rt, -1); break; - case OPC_PMON: /* Pmon entry point, also R4010 selsl */ + case OPC_LSA: /* OPC_PMON */ + if (ctx->insn_flags & ISA_MIPS32R6) { + decode_opc_special_r6(env, ctx); + } else { + /* Pmon entry point, also R4010 selsl */ #ifdef MIPS_STRICT_STANDARD MIPS_INVAL("PMON / selsl"); generate_exception(ctx, EXCP_RI); #else gen_helper_0e0i(pmon, sa); #endif + } break; case OPC_SYSCALL: generate_exception(ctx, EXCP_SYSCALL); @@ -16297,6 +16431,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_dsp(ctx); gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); break; +#if defined(TARGET_MIPS64) + case OPC_DAHI: + check_insn(ctx, ISA_MIPS32R6); + check_mips_64(ctx); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 32); + } + MIPS_DEBUG("dahi %s, %04x", regnames[rs], imm); + break; + case OPC_DATI: + check_insn(ctx, ISA_MIPS32R6); + check_mips_64(ctx); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rs], cpu_gpr[rs], (int64_t)imm << 48); + } + MIPS_DEBUG("dati %s, %04x", regnames[rs], imm); + break; +#endif default: /* Invalid */ MIPS_INVAL("regimm"); generate_exception(ctx, EXCP_RI); @@ -16409,7 +16561,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_slt_imm(ctx, op, rt, rs, imm); break; case OPC_ANDI: /* Arithmetic with immediate opcode */ - case OPC_LUI: + case OPC_LUI: /* OPC_AUI */ case OPC_ORI: case OPC_XORI: gen_logic_imm(ctx, op, rt, rs, imm); @@ -16707,14 +16859,37 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) } break; #endif - case OPC_JALX: - check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, op, 4, rs, rt, offset); + case OPC_DAUI: /* OPC_JALX */ + if (ctx->insn_flags & ISA_MIPS32R6) { +#if defined(TARGET_MIPS64) + /* OPC_DAUI */ + check_mips_64(ctx); + if (rt != 0) { + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + tcg_gen_addi_tl(cpu_gpr[rt], t0, imm << 16); + tcg_temp_free(t0); + } + MIPS_DEBUG("daui %s, %s, %04x", regnames[rt], regnames[rs], imm); +#else + generate_exception(ctx, EXCP_RI); + MIPS_INVAL("major opcode"); +#endif + } else { + /* OPC_JALX */ + check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, op, 4, rs, rt, offset); + } break; case OPC_MDMX: check_insn(ctx, ASE_MDMX); /* MDMX: Not implemented. */ + break; + case OPC_PCREL: + check_insn(ctx, ISA_MIPS32R6); + gen_pcrel(ctx, rs, imm); + break; default: /* Invalid */ MIPS_INVAL("major opcode"); generate_exception(ctx, EXCP_RI);
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com> --- v3: * use sextract32 instead of open coding the bit field extraction * replace _i64 with _tl in DAHI, DATI and DAUI * fix misleading LDPC comment --- disas/mips.c | 42 ++++++++++- target-mips/translate.c | 197 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 225 insertions(+), 14 deletions(-)