On Mon, Nov 23, 2009 at 12:50:07PM -0800, Nathan Froyd wrote: > There's no good way to add this incrementally, so we do it all at once. > The only changes to shared code are in handle_delay_slot. We need to > flip ISAMode when doing a jump-and-exchange. We also need to set > ISAMode the low bit of the target address for jump-to-register.
This patch breaks the boot of both MIPS kernel. On little endian, the kernel crashes with the following message: CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 00000000, ra == 80120004 On big endian, it fails before printing a single message on the console. See also my other comments inline. > Signed-off-by: Nathan Froyd <froy...@codesourcery.com> > --- > target-mips/translate.c | 980 > ++++++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 976 insertions(+), 4 deletions(-) > > diff --git a/target-mips/translate.c b/target-mips/translate.c > index 611774b..49d2264 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -83,6 +83,7 @@ enum { > OPC_LH = (0x21 << 26), > OPC_LWL = (0x22 << 26), > OPC_LW = (0x23 << 26), > + OPC_LWPC = OPC_LW | 0x5, > OPC_LBU = (0x24 << 26), > OPC_LHU = (0x25 << 26), > OPC_LWR = (0x26 << 26), > @@ -173,6 +174,7 @@ enum { > /* Jumps */ > OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ > OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ > + OPC_JALRC = OPC_JALR | (0x5 << 6), > /* Traps */ > OPC_TGE = 0x30 | OPC_SPECIAL, > OPC_TGEU = 0x31 | OPC_SPECIAL, > @@ -1074,6 +1076,19 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, > int rt, > opn = "sdr"; > break; > #endif > + case OPC_LWPC: > + save_cpu_state(ctx, 1); > + if (ctx->hflags & MIPS_HFLAG_BMASK) { > + int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4; > + > + tcg_gen_movi_tl(t1, (ctx->pc - branch_bytes) & ~(target_ulong)3); > + } else { > + tcg_gen_movi_tl(t1, ctx->pc & ~(target_ulong)3); > + } > + gen_op_addr_add(ctx, t0, t0, t1); > + op_ldst_lw(t0, t0, ctx); > + gen_store_gpr(t0, rt); > + break; > case OPC_LW: > save_cpu_state(ctx, 0); > op_ldst_lw(t0, t0, ctx); > @@ -2450,11 +2465,13 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > break; > case OPC_J: > case OPC_JAL: > + case OPC_JALX: > /* Jump to immediate */ > btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | > (uint32_t)offset; > break; > case OPC_JR: > case OPC_JALR: > + case OPC_JALRC: > /* Jump to register */ > if (offset != 0 && offset != 16) { > /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the > @@ -2517,18 +2534,29 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > ctx->hflags |= MIPS_HFLAG_B; > MIPS_DEBUG("j " TARGET_FMT_lx, btgt); > break; > + case OPC_JALX: > + ctx->hflags |= MIPS_HFLAG_BX; > + /* Fallthrough */ > case OPC_JAL: > blink = 31; > ctx->hflags |= MIPS_HFLAG_B; > + ctx->hflags |= (ctx->isa_mode > + ? MIPS_HFLAG_BDS16 > + : MIPS_HFLAG_BDS32); > MIPS_DEBUG("jal " TARGET_FMT_lx, btgt); > break; > case OPC_JR: > ctx->hflags |= MIPS_HFLAG_BR; > + if (ctx->isa_mode) > + ctx->hflags |= MIPS_HFLAG_BDS16; > MIPS_DEBUG("jr %s", regnames[rs]); > break; > case OPC_JALR: > + case OPC_JALRC: > blink = rt; > ctx->hflags |= MIPS_HFLAG_BR; > + if (ctx->isa_mode) > + ctx->hflags |= MIPS_HFLAG_BDS16; > MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); > break; > default: > @@ -2625,7 +2653,13 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > > ctx->btarget = btgt; > if (blink > 0) { > - tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 8); > + int post_delay = insn_bytes; > + int lowbit = ctx->isa_mode; > + > + if (opc != OPC_JALRC) > + post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4); > + > + tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); > } > > out: > @@ -7558,10 +7592,17 @@ static void handle_delay_slot (CPUState *env, > DisasContext *ctx, > ctx->bstate = BS_BRANCH; > save_cpu_state(ctx, 0); > /* FIXME: Need to clear can_do_io. */ > - switch (hflags) { > + switch (hflags & MIPS_HFLAG_BMASK_BASE) { > case MIPS_HFLAG_B: > /* unconditional branch */ > MIPS_DEBUG("unconditional branch"); > + if (hflags & MIPS_HFLAG_BX) { > + TCGv_i32 t0 = tcg_temp_new_i32(); > + > + tcg_gen_movi_i32(t0, 1 - ctx->isa_mode); > + tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, > active_tc.ISAMode)); > + tcg_temp_free_i32(t0); > + } > gen_goto_tb(ctx, 0, ctx->btarget); > break; > case MIPS_HFLAG_BL: > @@ -7584,7 +7625,20 @@ static void handle_delay_slot (CPUState *env, > DisasContext *ctx, > case MIPS_HFLAG_BR: > /* unconditional branch to register */ > MIPS_DEBUG("branch to register"); > - tcg_gen_mov_tl(cpu_PC, btarget); > + if (env->insn_flags & ASE_MIPS16) { > + TCGv t0 = tcg_temp_new(); > + TCGv_i32 t1 = tcg_temp_new_i32(); > + > + tcg_gen_andi_tl(t0, btarget, 0x1); > + tcg_gen_trunc_tl_i32(t1, t0); > + tcg_temp_free(t0); > + tcg_gen_st_i32(t1, cpu_env, offsetof(CPUState, > active_tc.ISAMode)); > + tcg_temp_free_i32(t1); > + > + tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1); > + } else { > + tcg_gen_mov_tl(cpu_PC, btarget); > + } > if (ctx->singlestep_enabled) { > save_cpu_state(ctx, 0); > gen_helper_0i(raise_exception, EXCP_DEBUG); > @@ -7712,6 +7766,918 @@ enum { > RR_RY_CNVT_SEW = 0x6, > }; > > +static int xlat (int r) > +{ > + static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; > + > + return map[r]; > +} > + > +static void gen_mips16_save (DisasContext *ctx, > + int xsregs, int aregs, > + int do_ra, int do_s0, int do_s1, > + int framesize) > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + int args, astatic; > + > + switch (aregs) { > + case 0: > + case 1: > + case 2: > + case 3: > + case 11: > + args = 0; > + break; > + case 4: > + case 5: > + case 6: > + case 7: > + args = 1; > + break; > + case 8: > + case 9: > + case 10: > + args = 2; > + break; > + case 12: > + case 13: > + args = 3; > + break; > + case 14: > + args = 4; > + break; > + default: > + generate_exception(ctx, EXCP_RI); > + return; > + } > + > + switch (args) { > + case 4: > + gen_base_offset_addr(ctx, t0, 29, 12); > + gen_load_gpr(t1, 7); > + op_ldst_sw(t1, t0, ctx); > + /* Fall through */ > + case 3: > + gen_base_offset_addr(ctx, t0, 29, 8); > + gen_load_gpr(t1, 6); > + op_ldst_sw(t1, t0, ctx); > + /* Fall through */ > + case 2: > + gen_base_offset_addr(ctx, t0, 29, 4); > + gen_load_gpr(t1, 5); > + op_ldst_sw(t1, t0, ctx); > + /* Fall through */ > + case 1: > + gen_base_offset_addr(ctx, t0, 29, 0); > + gen_load_gpr(t1, 4); > + op_ldst_sw(t1, t0, ctx); > + } > + > + gen_load_gpr(t0, 29); > + > +#define DECR_AND_STORE(reg) do { \ > + tcg_gen_subi_tl(t0, t0, 4); \ > + gen_load_gpr(t1, reg); \ > + op_ldst_sw(t1, t0, ctx); \ > + } while (0) > + > + if (do_ra) { > + DECR_AND_STORE(31); > + } > + > + switch (xsregs) { > + case 7: > + DECR_AND_STORE(30); > + /* Fall through */ > + case 6: > + DECR_AND_STORE(23); > + /* Fall through */ > + case 5: > + DECR_AND_STORE(22); > + /* Fall through */ > + case 4: > + DECR_AND_STORE(21); > + /* Fall through */ > + case 3: > + DECR_AND_STORE(20); > + /* Fall through */ > + case 2: > + DECR_AND_STORE(19); > + /* Fall through */ > + case 1: > + DECR_AND_STORE(18); > + } > + > + if (do_s1) { > + DECR_AND_STORE(17); > + } > + if (do_s0) { > + DECR_AND_STORE(16); > + } > + > + switch (aregs) { > + case 0: > + case 4: > + case 8: > + case 12: > + case 14: > + astatic = 0; > + break; > + case 1: > + case 5: > + case 9: > + case 13: > + astatic = 1; > + break; > + case 2: > + case 6: > + case 10: > + astatic = 2; > + break; > + case 3: > + case 7: > + astatic = 3; > + break; > + case 11: > + astatic = 4; > + break; > + default: > + generate_exception(ctx, EXCP_RI); > + return; > + } > + > + if (astatic > 0) { > + DECR_AND_STORE(7); > + if (astatic > 1) { > + DECR_AND_STORE(6); > + if (astatic > 2) { > + DECR_AND_STORE(5); > + if (astatic > 3) { > + DECR_AND_STORE(4); > + } > + } > + } > + } > +#undef DECR_AND_STORE > + > + tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize); > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > + > +static void gen_mips16_restore (DisasContext *ctx, > + int xsregs, int aregs, > + int do_ra, int do_s0, int do_s1, > + int framesize) > +{ > + int astatic; > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + > + tcg_gen_addi_tl(t0, cpu_gpr[29], framesize); > + > +#define DECR_AND_LOAD(reg) do { \ > + tcg_gen_subi_tl(t0, t0, 4); \ > + op_ldst_lw(t1, t0, ctx); \ > + gen_store_gpr(t1, reg); \ > + } while (0) > + > + if (do_ra) { > + DECR_AND_LOAD(31); > + } > + > + switch (xsregs) { > + case 7: > + DECR_AND_LOAD(30); > + /* Fall through */ > + case 6: > + DECR_AND_LOAD(23); > + /* Fall through */ > + case 5: > + DECR_AND_LOAD(22); > + /* Fall through */ > + case 4: > + DECR_AND_LOAD(21); > + /* Fall through */ > + case 3: > + DECR_AND_LOAD(20); > + /* Fall through */ > + case 2: > + DECR_AND_LOAD(19); > + /* Fall through */ > + case 1: > + DECR_AND_LOAD(18); > + } > + > + if (do_s1) { > + DECR_AND_LOAD(17); > + } > + if (do_s0) { > + DECR_AND_LOAD(16); > + } > + > + switch (aregs) { > + case 0: > + case 4: > + case 8: > + case 12: > + case 14: > + astatic = 0; > + break; > + case 1: > + case 5: > + case 9: > + case 13: > + astatic = 1; > + break; > + case 2: > + case 6: > + case 10: > + astatic = 2; > + break; > + case 3: > + case 7: > + astatic = 3; > + break; > + case 11: > + astatic = 4; > + break; > + default: > + generate_exception(ctx, EXCP_RI); > + return; > + } > + > + if (astatic > 0) { > + DECR_AND_LOAD(7); > + if (astatic > 1) { > + DECR_AND_LOAD(6); > + if (astatic > 2) { > + DECR_AND_LOAD(5); > + if (astatic > 3) { > + DECR_AND_LOAD(4); > + } > + } > + } > + } > +#undef DECR_AND_LOAD > + > + tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize); > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > + > +static void gen_addiupc (DisasContext *ctx, int rx, int imm) > +{ > + TCGv t0 = tcg_temp_new(); > + > + tcg_gen_movi_tl(t0, ctx->pc & ~(target_ulong)3); > + tcg_gen_addi_tl(cpu_gpr[rx], t0, imm); > + > + tcg_temp_free(t0); > +} > + > +static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx, > + int *is_branch) > +{ > + int extend = lduw_code(ctx->pc + 2); > + int op, rx, ry, funct, sa; > + int16_t imm, offset; > + > + ctx->opcode = (ctx->opcode << 16) | extend; > + op = (ctx->opcode >> 11) & 0x1f; > + sa = (ctx->opcode >> 22) & 0x1f; > + funct = (ctx->opcode >> 8) & 0x7; > + rx = xlat((ctx->opcode >> 8) & 0x7); > + ry = xlat((ctx->opcode >> 5) & 0x7); > + offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11 > + | ((ctx->opcode >> 21) & 0x3f) << 5 > + | (ctx->opcode & 0x1f)); > + > + /* The extended opcodes cleverly reuse the opcodes from their 16-bit > + counterparts. */ > + switch (op) { > + case M16_OPC_ADDIUSP: > + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm); > + break; > + case M16_OPC_ADDIUPC: > + gen_addiupc(ctx, rx, imm); > + break; > + case M16_OPC_B: > + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1); > + /* No delay slot, so just process as a normal instruction */ > + break; > + case M16_OPC_BEQZ: > + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1); > + /* No delay slot, so just process as a normal instruction */ > + break; > + case M16_OPC_BNEQZ: > + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1); > + /* No delay slot, so just process as a normal instruction */ > + break; > + case M16_OPC_SHIFT: > + switch (ctx->opcode & 0x3) { > + case 0x0: > + gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa); > + break; > + case 0x1: > +#if defined(TARGET_MIPS64) > + gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa); Shouldn't this generate an exception on 64-bit CPU, but with 64-bit instructions not enabled? The MIPS16e manual is not really clear about that. Same for other instructions below. > +#else > + generate_exception(ctx, EXCP_RI); > +#endif > + break; > + case 0x2: > + gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa); > + break; > + case 0x3: > + gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa); > + break; > + } > + break; > +#if defined(TARGET_MIPS64) > + case M16_OPC_LD: > + gen_ldst(ctx, OPC_LD, ry, rx, offset); > + break; > +#endif > + case M16_OPC_RRIA: > + imm = ctx->opcode & 0xf; > + imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4; > + imm = imm | ((ctx->opcode >> 16) & 0xf) << 11; > + imm = (int16_t) (imm << 1) >> 1; > + if ((ctx->opcode >> 4) & 0x1) { > +#if defined(TARGET_MIPS64) > + gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm); > +#else > + generate_exception(ctx, EXCP_RI); > +#endif > + } else { > + gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm); > + } > + break; > + case M16_OPC_ADDIU8: > + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); > + break; > + case M16_OPC_SLTI: > + gen_slt_imm(env, OPC_SLTI, 24, rx, imm); > + break; > + case M16_OPC_SLTIU: > + gen_slt_imm(env, OPC_SLTIU, 24, rx, imm); > + break; > + case M16_OPC_I8: > + switch (funct) { > + case I8_BTEQZ: > + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1); > + break; > + case I8_BTNEZ: > + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1); > + break; > + case I8_SWRASP: > + gen_ldst(ctx, OPC_SW, 31, 29, imm); > + break; > + case I8_ADJSP: > + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm); > + break; > + case I8_SVRS: > + { > + int xsregs = (ctx->opcode >> 24) & 0x7; > + int aregs = (ctx->opcode >> 16) & 0xf; > + int do_ra = (ctx->opcode >> 6) & 0x1; > + int do_s0 = (ctx->opcode >> 5) & 0x1; > + int do_s1 = (ctx->opcode >> 4) & 0x1; > + int framesize = (((ctx->opcode >> 20) & 0xf) << 4 > + | (ctx->opcode & 0xf)) << 3; > + > + if (ctx->opcode & (1 << 7)) { > + gen_mips16_save(ctx, xsregs, aregs, > + do_ra, do_s0, do_s1, > + framesize); > + } else { > + gen_mips16_restore(ctx, xsregs, aregs, > + do_ra, do_s0, do_s1, > + framesize); > + } > + } > + break; > + default: > + generate_exception(ctx, EXCP_RI); > + break; > + } > + break; > + case M16_OPC_LI: > + tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm); > + break; > + case M16_OPC_CMPI: > + tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm); > + break; > +#if defined(TARGET_MIPS64) > + case M16_OPC_SD: > + gen_ldst(ctx, OPC_SD, ry, rx, offset); > + break; > +#endif > + case M16_OPC_LB: > + gen_ldst(ctx, OPC_LB, ry, rx, offset); > + break; > + case M16_OPC_LH: > + gen_ldst(ctx, OPC_LH, ry, rx, offset); > + break; > + case M16_OPC_LWSP: > + gen_ldst(ctx, OPC_LW, rx, 29, offset); > + break; > + case M16_OPC_LW: > + gen_ldst(ctx, OPC_LW, ry, rx, offset); > + break; > + case M16_OPC_LBU: > + gen_ldst(ctx, OPC_LBU, ry, rx, offset); > + break; > + case M16_OPC_LHU: > + gen_ldst(ctx, OPC_LHU, ry, rx, offset); > + break; > + case M16_OPC_LWPC: > + gen_ldst(ctx, OPC_LWPC, rx, 0, offset); > + break; > +#if defined(TARGET_MIPS64) > + case M16_OPC_LWU: > + gen_ldst(ctx, OPC_LWU, ry, rx, offset); > + break; > +#endif > + case M16_OPC_SB: > + gen_ldst(ctx, OPC_SB, ry, rx, offset); > + break; > + case M16_OPC_SH: > + gen_ldst(ctx, OPC_SH, ry, rx, offset); > + break; > + case M16_OPC_SWSP: > + gen_ldst(ctx, OPC_SW, rx, 29, offset); > + break; > + case M16_OPC_SW: > + gen_ldst(ctx, OPC_SW, ry, rx, offset); > + break; > + default: > + generate_exception(ctx, EXCP_RI); > + break; > + } > + > + return 4; > +} > + > +static int decode_mips16_opc (CPUState *env, DisasContext *ctx, > + int *is_branch) > +{ > + int rx, ry; > + int sa; > + int op, cnvt_op, op1, offset; > + int funct; > + int n_bytes; > + > + op = (ctx->opcode >> 11) & 0x1f; > + sa = (ctx->opcode >> 2) & 0x7; > + sa = sa == 0 ? 8 : sa; > + rx = xlat((ctx->opcode >> 8) & 0x7); > + cnvt_op = (ctx->opcode >> 5) & 0x7; > + ry = xlat((ctx->opcode >> 5) & 0x7); > + op1 = offset = ctx->opcode & 0x1f; > + > + n_bytes = 2; > + > + switch (op) { > + case M16_OPC_ADDIUSP: > + { > + int16_t imm = ((uint8_t) ctx->opcode) << 2; > + > + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm); > + } > + break; > + case M16_OPC_ADDIUPC: > + gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2); > + break; > + case M16_OPC_B: > + offset = (ctx->opcode & 0x7ff) << 1; > + offset = (int16_t)(offset << 4) >> 4; > + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset); > + /* No delay slot, so just process as a normal instruction */ > + break; > + case M16_OPC_JAL: > + offset = lduw_code(ctx->pc + 2); > + offset = (((ctx->opcode & 0x1f) << 21) > + | ((ctx->opcode >> 5) & 0x1f) << 16 > + | offset) << 2; > + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL; > + gen_compute_branch(ctx, op, 4, rx, ry, offset); > + n_bytes = 4; > + *is_branch = 1; > + break; > + case M16_OPC_BEQZ: > + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << > 1); > + /* No delay slot, so just process as a normal instruction */ > + break; > + case M16_OPC_BNEQZ: > + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << > 1); > + /* No delay slot, so just process as a normal instruction */ > + break; > + case M16_OPC_SHIFT: > + switch (ctx->opcode & 0x3) { > + case 0x0: > + gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa); > + break; > + case 0x1: > +#if defined(TARGET_MIPS64) > + gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa); > +#else > + generate_exception(ctx, EXCP_RI); > +#endif > + break; > + case 0x2: > + gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa); > + break; > + case 0x3: > + gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa); > + break; > + } > + break; > +#if defined(TARGET_MIPS64) > + case M16_OPC_LD: > + gen_ldst(ctx, OPC_LD, ry, rx, offset << 3); > + break; > +#endif > + case M16_OPC_RRIA: > + { > + int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4; > + > + if ((ctx->opcode >> 4) & 1) { > +#if defined(TARGET_MIPS64) > + gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm); > +#else > + generate_exception(ctx, EXCP_RI); > +#endif > + } else { > + gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm); > + } > + } > + break; > + case M16_OPC_ADDIU8: > + { > + int16_t imm = (int8_t) ctx->opcode; > + > + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); > + } > + break; > + case M16_OPC_SLTI: > + { > + int16_t imm = (uint8_t) ctx->opcode; > + > + gen_slt_imm(env, OPC_SLTI, 24, rx, imm); > + } > + break; > + case M16_OPC_SLTIU: > + { > + int16_t imm = (uint8_t) ctx->opcode; > + > + gen_slt_imm(env, OPC_SLTIU, 24, rx, imm); > + } > + break; > + case M16_OPC_I8: > + { > + int reg32; > + > + funct = (ctx->opcode >> 8) & 0x7; > + switch (funct) { > + case I8_BTEQZ: > + gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, > + ((int8_t)ctx->opcode) << 1); > + break; > + case I8_BTNEZ: > + gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, > + ((int8_t)ctx->opcode) << 1); > + break; > + case I8_SWRASP: > + gen_ldst(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); > + break; > + case I8_ADJSP: > + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, > + ((int8_t)ctx->opcode) << 3); > + break; > + case I8_SVRS: > + { > + int do_ra = ctx->opcode & (1 << 6); > + int do_s0 = ctx->opcode & (1 << 5); > + int do_s1 = ctx->opcode & (1 << 4); > + int framesize = ctx->opcode & 0xf; > + > + if (framesize == 0) { > + framesize = 128; > + } else { > + framesize = framesize << 3; > + } > + > + if (ctx->opcode & (1 << 7)) { > + gen_mips16_save(ctx, 0, 0, > + do_ra, do_s0, do_s1, framesize); > + } else { > + gen_mips16_restore(ctx, 0, 0, > + do_ra, do_s0, do_s1, framesize); > + } > + } > + break; > + case I8_MOV32R: > + { > + int rz = xlat(ctx->opcode & 0x7); > + > + reg32 = (((ctx->opcode >> 3) & 0x3) << 3) | > + ((ctx->opcode >> 5) & 0x7); > + gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0); > + } > + break; > + case I8_MOVR32: > + reg32 = ctx->opcode & 0x1f; > + gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0); > + break; > + default: > + generate_exception(ctx, EXCP_RI); > + break; > + } > + } > + break; > + case M16_OPC_LI: > + { > + int16_t imm = (uint8_t) ctx->opcode; > + > + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm); > + } > + break; > + case M16_OPC_CMPI: > + { > + int16_t imm = (uint8_t) ctx->opcode; > + > + gen_logic_imm(env, OPC_XORI, 24, rx, imm); > + } > + break; > +#if defined(TARGET_MIPS64) > + case M16_OPC_SD: > + gen_ldst(ctx, OPC_SD, ry, rx, offset << 3); > + break; > +#endif > + case M16_OPC_LB: > + gen_ldst(ctx, OPC_LB, ry, rx, offset); > + break; > + case M16_OPC_LH: > + gen_ldst(ctx, OPC_LH, ry, rx, offset << 1); > + break; > + case M16_OPC_LWSP: > + gen_ldst(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2); > + break; > + case M16_OPC_LW: > + gen_ldst(ctx, OPC_LW, ry, rx, offset << 2); > + break; > + case M16_OPC_LBU: > + gen_ldst(ctx, OPC_LBU, ry, rx, offset); > + break; > + case M16_OPC_LHU: > + gen_ldst(ctx, OPC_LHU, ry, rx, offset << 1); > + break; > + case M16_OPC_LWPC: > + gen_ldst(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); > + break; > +#if defined (TARGET_MIPS64) > + case M16_OPC_LWU: > + gen_ldst(ctx, OPC_LWU, ry, rx, offset << 2); > + break; > +#endif > + case M16_OPC_SB: > + gen_ldst(ctx, OPC_SB, ry, rx, offset); > + break; > + case M16_OPC_SH: > + gen_ldst(ctx, OPC_SH, ry, rx, offset << 1); > + break; > + case M16_OPC_SWSP: > + gen_ldst(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2); > + break; > + case M16_OPC_SW: > + gen_ldst(ctx, OPC_SW, ry, rx, offset << 2); > + break; > + case M16_OPC_RRR: > + { > + int rz = xlat((ctx->opcode >> 2) & 0x7); > + int mips32_op; > + > + switch (ctx->opcode & 0x3) { > + case RRR_ADDU: > + mips32_op = OPC_ADDU; > + break; > + case RRR_SUBU: > + mips32_op = OPC_SUBU; > + break; > +#if defined(TARGET_MIPS64) > + case RRR_DADDU: > + mips32_op = OPC_DADDU; > + break; > + case RRR_DSUBU: > + mips32_op = OPC_DSUBU; > + break; > +#endif > + default: > + generate_exception(ctx, EXCP_RI); > + goto done; > + } > + > + gen_arith(env, ctx, mips32_op, rz, rx, ry); > + done: > + ; > + } > + break; > + case M16_OPC_RR: > + switch (op1) { > + case RR_JR: > + { > + int nd = (ctx->opcode >> 7) & 0x1; > + int link = (ctx->opcode >> 6) & 0x1; > + int ra = (ctx->opcode >> 5) & 0x1; > + > + if (link) { > + op = nd ? OPC_JALRC : OPC_JALR; > + } else { > + op = OPC_JR; > + } > + > + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); > + if (!nd) { > + *is_branch = 1; > + } > + } > + break; > + case RR_SDBBP: > + /* XXX: not clear which exception should be raised > + * when in debug mode... > + */ > + check_insn(env, ctx, ISA_MIPS32); > + if (!(ctx->hflags & MIPS_HFLAG_DM)) { > + generate_exception(ctx, EXCP_DBp); > + } else { > + generate_exception(ctx, EXCP_DBp); > + } > + break; > + case RR_SLT: > + gen_slt(env, OPC_SLT, 24, rx, ry); > + break; > + case RR_SLTU: > + gen_slt(env, OPC_SLTU, 24, rx, ry); > + break; > + case RR_BREAK: > + generate_exception(ctx, EXCP_BREAK); > + break; > + case RR_SLLV: > + gen_shift(env, ctx, OPC_SLLV, ry, rx, ry); > + break; > + case RR_SRLV: > + gen_shift(env, ctx, OPC_SRLV, ry, rx, ry); > + break; > + case RR_SRAV: > + gen_shift(env, ctx, OPC_SRAV, ry, rx, ry); > + break; > +#if defined (TARGET_MIPS64) > + case RR_DSRL: > + gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa); > + break; > +#endif > + case RR_CMP: > + gen_logic(env, OPC_XOR, 24, rx, ry); > + break; > + case RR_NEG: > + gen_arith(env, ctx, OPC_SUBU, rx, 0, ry); > + break; > + case RR_AND: > + gen_logic(env, OPC_AND, rx, rx, ry); > + break; > + case RR_OR: > + gen_logic(env, OPC_OR, rx, rx, ry); > + break; > + case RR_XOR: > + gen_logic(env, OPC_XOR, rx, rx, ry); > + break; > + case RR_NOT: > + gen_logic(env, OPC_NOR, rx, ry, 0); > + break; > + case RR_MFHI: > + gen_HILO(ctx, OPC_MFHI, rx); > + break; > + case RR_CNVT: > + switch (cnvt_op) { > + case RR_RY_CNVT_ZEB: > + tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]); > + break; > + case RR_RY_CNVT_ZEH: > + tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]); > + break; > + case RR_RY_CNVT_SEB: > + tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]); > + break; > + case RR_RY_CNVT_SEH: > + tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]); > + break; > +#if defined (TARGET_MIPS64) > + case RR_RY_CNVT_ZEW: > + tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]); > + break; > + case RR_RY_CNVT_SEW: > + tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); > + break; > +#endif > + default: > + generate_exception(ctx, EXCP_RI); > + break; > + } > + break; > + case RR_MFLO: > + gen_HILO(ctx, OPC_MFLO, rx); > + break; > +#if defined (TARGET_MIPS64) > + case RR_DSRA: > + gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa); > + break; > + case RR_DSLLV: > + gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry); > + case RR_DSRLV: > + gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry); > + break; > + case RR_DSRAV: > + gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry); > + break; > +#endif > + case RR_MULT: > + gen_muldiv(ctx, OPC_MULT, rx, ry); > + break; > + case RR_MULTU: > + gen_muldiv(ctx, OPC_MULTU, rx, ry); > + break; > + case RR_DIV: > + gen_muldiv(ctx, OPC_DIV, rx, ry); > + break; > + case RR_DIVU: > + gen_muldiv(ctx, OPC_DIVU, rx, ry); > + break; > +#if defined (TARGET_MIPS64) > + case RR_DMULT: > + gen_muldiv(ctx, OPC_DMULT, rx, ry); > + break; > + case RR_DMULTU: > + gen_muldiv(ctx, OPC_DMULTU, rx, ry); > + break; > + case RR_DDIV: > + gen_muldiv(ctx, OPC_DDIV, rx, ry); > + break; > + case RR_DDIVU: > + gen_muldiv(ctx, OPC_DDIVU, rx, ry); > + break; > +#endif > + default: > + generate_exception(ctx, EXCP_RI); > + break; > + } > + break; > + case M16_OPC_EXTEND: > + decode_extended_mips16_opc(env, ctx, is_branch); > + n_bytes = 4; > + break; > +#if defined(TARGET_MIPS64) > + case M16_OPC_I64: > + funct = (ctx->opcode >> 8) & 0x7; > + switch (funct) { > + case I64_LDSP: > + gen_ldst(ctx, OPC_LD, ry, 29, offset << 3); > + break; > + case I64_SDSP: > + gen_ldst(ctx, OPC_SD, ry, 29, offset << 3); > + break; > + case I64_SDRASP: > + gen_ldst(ctx, OPC_SD, 31, 29, (ctx->opcode & 0xff) << 3); > + break; > + case I64_DADJSP: > + gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29, > + ((int8_t)ctx->opcode) << 3); > + break; > + case I64_LDPC: > + break; > + case I64_DADDIU: > + gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry, > + ((int8_t)(offset << 3)) >> 3); > + break; > + case I64_DADDIUPC: > + break; > + case I64_DADDIUSP: > + gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29, > + ((int8_t)(offset << 3)) >> 1); > + break; > + } > +#endif > + default: > + generate_exception(ctx, EXCP_RI); > + break; > + } > + > + return n_bytes; > +} > + > /* SmartMIPS extension to MIPS32 */ > > #if defined(TARGET_MIPS64) > @@ -8400,7 +9366,10 @@ static void decode_opc (CPUState *env, DisasContext > *ctx, int *is_branch) > #endif > case OPC_JALX: > check_insn(env, ctx, ASE_MIPS16); > - /* MIPS16: Not implemented. */ > + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; > + gen_compute_branch(ctx, op, 4, rs, rt, offset); > + *is_branch = 1; > + break; > case OPC_MDMX: > check_insn(env, ctx, ASE_MDMX); > /* MDMX: Not implemented. */ > @@ -8490,6 +9459,9 @@ gen_intermediate_code_internal (CPUState *env, > TranslationBlock *tb, > ctx.opcode = ldl_code(ctx.pc); > insn_bytes = 4; > decode_opc(env, &ctx, &is_branch); > + } else if (env->insn_flags & ASE_MIPS16) { > + ctx.opcode = lduw_code(ctx.pc); > + insn_bytes = decode_mips16_opc(env, &ctx, &is_branch); > } else { > generate_exception(&ctx, EXCP_RI); > break; > -- > 1.6.3.2 > > > > -- Aurelien Jarno GPG: 1024D/F1BCDB73 aurel...@aurel32.net http://www.aurel32.net