diff options
Diffstat (limited to 'target/mips/translate.c')
-rw-r--r-- | target/mips/translate.c | 623 |
1 files changed, 312 insertions, 311 deletions
diff --git a/target/mips/translate.c b/target/mips/translate.c index d05ee67e63..9eff842c39 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -36,6 +36,7 @@ #include "target/mips/trace.h" #include "trace-tcg.h" +#include "exec/translator.h" #include "exec/log.h" #define MIPS_DEBUG_DISAS 0 @@ -1429,17 +1430,16 @@ static TCGv_i64 msa_wr_d[64]; } while(0) typedef struct DisasContext { - struct TranslationBlock *tb; - target_ulong pc, saved_pc; + DisasContextBase base; + target_ulong saved_pc; + target_ulong page_start; uint32_t opcode; - int singlestep_enabled; int insn_flags; int32_t CP0_Config1; /* Routine used to access memory */ int mem_idx; TCGMemOp default_tcg_memop_mask; uint32_t hflags, saved_hflags; - int bstate; target_ulong btarget; bool ulri; int kscrexist; @@ -1460,13 +1460,8 @@ typedef struct DisasContext { bool abs2008; } DisasContext; -enum { - BS_NONE = 0, /* We go out of the TB without reaching a branch or an - * exception condition */ - BS_STOP = 1, /* We want to stop translation for any reason */ - BS_BRANCH = 2, /* We reached a branch condition */ - BS_EXCP = 3, /* We reached an exception condition */ -}; +#define DISAS_STOP DISAS_TARGET_0 +#define DISAS_EXIT DISAS_TARGET_1 static const char * const regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", @@ -1521,8 +1516,9 @@ static const char * const msaregnames[] = { if (MIPS_DEBUG_DISAS) { \ qemu_log_mask(CPU_LOG_TB_IN_ASM, \ TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \ - ctx->pc, ctx->opcode, op, ctx->opcode >> 26, \ - ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ + ctx->base.pc_next, ctx->opcode, op, \ + ctx->opcode >> 26, ctx->opcode & 0x3F, \ + ((ctx->opcode >> 16) & 0x1F)); \ } \ } while (0) @@ -1598,9 +1594,9 @@ static inline void gen_save_pc(target_ulong pc) static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) { LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); - if (do_save_pc && ctx->pc != ctx->saved_pc) { - gen_save_pc(ctx->pc); - ctx->saved_pc = ctx->pc; + if (do_save_pc && ctx->base.pc_next != ctx->saved_pc) { + gen_save_pc(ctx->base.pc_next); + ctx->saved_pc = ctx->base.pc_next; } if (ctx->hflags != ctx->saved_hflags) { tcg_gen_movi_i32(hflags, ctx->hflags); @@ -1639,7 +1635,7 @@ static inline void generate_exception_err(DisasContext *ctx, int excp, int err) gen_helper_raise_exception_err(cpu_env, texcp, terr); tcg_temp_free_i32(terr); tcg_temp_free_i32(texcp); - ctx->bstate = BS_EXCP; + ctx->base.is_jmp = DISAS_NORETURN; } static inline void generate_exception(DisasContext *ctx, int excp) @@ -2130,7 +2126,7 @@ static void gen_base_offset_addr (DisasContext *ctx, TCGv addr, static target_ulong pc_relative_pc (DisasContext *ctx) { - target_ulong pc = ctx->pc; + target_ulong pc = ctx->base.pc_next; if (ctx->hflags & MIPS_HFLAG_BMASK) { int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4; @@ -4279,12 +4275,12 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) { - if (unlikely(ctx->singlestep_enabled)) { + if (unlikely(ctx->base.singlestep_enabled)) { return false; } #ifndef CONFIG_USER_ONLY - return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); + return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); #else return true; #endif @@ -4295,10 +4291,10 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) if (use_goto_tb(ctx, dest)) { tcg_gen_goto_tb(n); gen_save_pc(dest); - tcg_gen_exit_tb((uintptr_t)ctx->tb + n); + tcg_gen_exit_tb((uintptr_t)ctx->base.tb + n); } else { gen_save_pc(dest); - if (ctx->singlestep_enabled) { + if (ctx->base.singlestep_enabled) { save_cpu_state(ctx, 0); gen_helper_raise_exception_debug(cpu_env); } @@ -4321,7 +4317,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS LOG_DISAS("Branch in delay / forbidden slot at PC 0x" - TARGET_FMT_lx "\n", ctx->pc); + TARGET_FMT_lx "\n", ctx->base.pc_next); #endif generate_exception_end(ctx, EXCP_RI); goto out; @@ -4339,7 +4335,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, gen_load_gpr(t1, rt); bcond_compute = 1; } - btgt = ctx->pc + insn_bytes + offset; + btgt = ctx->base.pc_next + insn_bytes + offset; break; case OPC_BGEZ: case OPC_BGEZAL: @@ -4358,7 +4354,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, gen_load_gpr(t0, rs); bcond_compute = 1; } - btgt = ctx->pc + insn_bytes + offset; + btgt = ctx->base.pc_next + insn_bytes + offset; break; case OPC_BPOSGE32: #if defined(TARGET_MIPS64) @@ -4368,13 +4364,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, tcg_gen_andi_tl(t0, cpu_dspctrl, 0x3F); #endif bcond_compute = 1; - btgt = ctx->pc + insn_bytes + offset; + btgt = ctx->base.pc_next + insn_bytes + offset; break; case OPC_J: case OPC_JAL: case OPC_JALX: /* Jump to immediate */ - btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset; + btgt = ((ctx->base.pc_next + insn_bytes) & (int32_t)0xF0000000) | + (uint32_t)offset; break; case OPC_JR: case OPC_JALR: @@ -4420,19 +4417,19 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, /* Handle as an unconditional branch to get correct delay slot checking. */ blink = 31; - btgt = ctx->pc + insn_bytes + delayslot_size; + btgt = ctx->base.pc_next + insn_bytes + delayslot_size; ctx->hflags |= MIPS_HFLAG_B; break; case OPC_BLTZALL: /* 0 < 0 likely */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8); + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 8); /* Skip the instruction in the delay slot */ - ctx->pc += 4; + ctx->base.pc_next += 4; goto out; case OPC_BNEL: /* rx != rx likely */ case OPC_BGTZL: /* 0 > 0 likely */ case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ - ctx->pc += 4; + ctx->base.pc_next += 4; goto out; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; @@ -4544,7 +4541,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int post_delay = insn_bytes + delayslot_size; int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16); - tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); + tcg_gen_movi_tl(cpu_gpr[blink], + ctx->base.pc_next + post_delay + lowbit); } out: @@ -5326,18 +5324,18 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: /* Mark as an IO operation because we read the time. */ - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } gen_helper_mfc0_count(arg, cpu_env); - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_end(); } /* Break the TB to be able to take timer interrupts immediately - after reading count. BS_STOP isn't sufficient, we need to ensure - we break completely out of translated code. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + after reading count. DISAS_STOP isn't sufficient, we need to + ensure we break completely out of translated code. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -5733,7 +5731,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) if (sel != 0) check_insn(ctx, ISA_MIPS32); - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } @@ -5905,7 +5903,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(cpu_env, arg); rn = "PageGrain"; - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 2: CP0_CHECK(ctx->sc); @@ -5966,7 +5964,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "HWREna"; break; default: @@ -6028,30 +6026,30 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: save_cpu_state(ctx, 1); gen_helper_mtc0_status(cpu_env, arg); - /* BS_STOP isn't good enough here, hflags may have changed. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* DISAS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Status"; break; case 1: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_intctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "IntCtl"; break; case 2: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "SRSCtl"; break; case 3: check_insn(ctx, ISA_MIPS32R2); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "SRSMap"; break; default: @@ -6063,11 +6061,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: save_cpu_state(ctx, 1); gen_helper_mtc0_cause(cpu_env, arg); - /* Stop translation as we may have triggered an interrupt. BS_STOP - * isn't sufficient, we need to ensure we break out of translated - * code to check for pending interrupts. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* Stop translation as we may have triggered an interrupt. + * DISAS_STOP isn't sufficient, we need to ensure we break out of + * translated code to check for pending interrupts. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Cause"; break; default: @@ -6105,7 +6103,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_config0(cpu_env, arg); rn = "Config"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 1: /* ignored, read only */ @@ -6115,24 +6113,24 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_config2(cpu_env, arg); rn = "Config2"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 3: gen_helper_mtc0_config3(cpu_env, arg); rn = "Config3"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 4: gen_helper_mtc0_config4(cpu_env, arg); rn = "Config4"; - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 5: gen_helper_mtc0_config5(cpu_env, arg); rn = "Config5"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; /* 6,7 are implementation dependent */ case 6: @@ -6221,35 +6219,35 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ - /* BS_STOP isn't good enough here, hflags may have changed. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* DISAS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Debug"; break; case 1: // gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */ rn = "TraceControl"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; case 2: // gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */ rn = "TraceControl2"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; case 3: /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; // gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */ rn = "UserTraceData"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; goto cp0_unimplemented; case 4: // gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "TraceBPC"; goto cp0_unimplemented; default: @@ -6309,7 +6307,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: gen_helper_mtc0_errctl(cpu_env, arg); - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "ErrCtl"; break; default: @@ -6400,12 +6398,12 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) trace_mips_translate_c0("mtc0", rn, reg, sel); /* For simplicity assume that all writes can cause interrupts. */ - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_end(); - /* BS_STOP isn't sufficient, we need to ensure we break out of + /* DISAS_STOP isn't sufficient, we need to ensure we break out of * translated code to check for pending interrupts. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; } return; @@ -6678,18 +6676,18 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: /* Mark as an IO operation because we read the time. */ - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } gen_helper_mfc0_count(arg, cpu_env); - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_end(); } /* Break the TB to be able to take timer interrupts immediately - after reading count. BS_STOP isn't sufficient, we need to ensure - we break completely out of translated code. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + after reading count. DISAS_STOP isn't sufficient, we need to + ensure we break completely out of translated code. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -7071,7 +7069,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) if (sel != 0) check_insn(ctx, ISA_MIPS64); - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } @@ -7301,7 +7299,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "HWREna"; break; default: @@ -7337,7 +7335,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; } /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 10: switch (sel) { @@ -7360,37 +7358,37 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; } /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 12: switch (sel) { case 0: save_cpu_state(ctx, 1); gen_helper_mtc0_status(cpu_env, arg); - /* BS_STOP isn't good enough here, hflags may have changed. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* DISAS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Status"; break; case 1: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_intctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "IntCtl"; break; case 2: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "SRSCtl"; break; case 3: check_insn(ctx, ISA_MIPS32R2); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "SRSMap"; break; default: @@ -7402,11 +7400,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: save_cpu_state(ctx, 1); gen_helper_mtc0_cause(cpu_env, arg); - /* Stop translation as we may have triggered an intetrupt. BS_STOP - * isn't sufficient, we need to ensure we break out of translated - * code to check for pending interrupts. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* Stop translation as we may have triggered an interrupt. + * DISAS_STOP isn't sufficient, we need to ensure we break out of + * translated code to check for pending interrupts. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Cause"; break; default: @@ -7444,7 +7442,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_config0(cpu_env, arg); rn = "Config"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 1: /* ignored, read only */ @@ -7454,13 +7452,13 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_config2(cpu_env, arg); rn = "Config2"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 3: gen_helper_mtc0_config3(cpu_env, arg); rn = "Config3"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case 4: /* currently ignored */ @@ -7470,7 +7468,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_config5(cpu_env, arg); rn = "Config5"; /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; /* 6,7 are implementation dependent */ default: @@ -7549,33 +7547,33 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ - /* BS_STOP isn't good enough here, hflags may have changed. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* DISAS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; rn = "Debug"; break; case 1: // gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "TraceControl"; goto cp0_unimplemented; case 2: // gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "TraceControl2"; goto cp0_unimplemented; case 3: // gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "UserTraceData"; goto cp0_unimplemented; case 4: // gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "TraceBPC"; goto cp0_unimplemented; default: @@ -7635,7 +7633,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: gen_helper_mtc0_errctl(cpu_env, arg); - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; rn = "ErrCtl"; break; default: @@ -7726,12 +7724,12 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) trace_mips_translate_c0("dmtc0", rn, reg, sel); /* For simplicity assume that all writes can cause interrupts. */ - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_end(); - /* BS_STOP isn't sufficient, we need to ensure we break out of + /* DISAS_STOP isn't sufficient, we need to ensure we break out of * translated code to check for pending interrupts. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; } return; @@ -8142,7 +8140,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, tcg_temp_free_i32(fs_tmp); } /* Stop translation as we may have changed hflags */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; /* COP2: Not implemented. */ case 4: @@ -8301,7 +8299,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, check_insn(ctx, ISA_MIPS2); gen_helper_eret(cpu_env); } - ctx->bstate = BS_EXCP; + ctx->base.is_jmp = DISAS_EXIT; } break; case OPC_DERET: @@ -8316,7 +8314,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, generate_exception_end(ctx, EXCP_RI); } else { gen_helper_deret(cpu_env); - ctx->bstate = BS_EXCP; + ctx->base.is_jmp = DISAS_EXIT; } break; case OPC_WAIT: @@ -8327,11 +8325,11 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, goto die; } /* If we get an exception, we want to restart at next instruction */ - ctx->pc += 4; + ctx->base.pc_next += 4; save_cpu_state(ctx, 1); - ctx->pc -= 4; + ctx->base.pc_next -= 4; gen_helper_wait(cpu_env); - ctx->bstate = BS_EXCP; + ctx->base.is_jmp = DISAS_NORETURN; break; default: die: @@ -8358,7 +8356,7 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, if (cc != 0) check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); - btarget = ctx->pc + 4 + offset; + btarget = ctx->base.pc_next + 4 + offset; switch (op) { case OPC_BC1F: @@ -8461,7 +8459,7 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx - "\n", ctx->pc); + "\n", ctx->base.pc_next); #endif generate_exception_end(ctx, EXCP_RI); goto out; @@ -8470,7 +8468,7 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, gen_load_fpr64(ctx, t0, ft); tcg_gen_andi_i64(t0, t0, 1); - btarget = addr_add(ctx, ctx->pc + 4, offset); + btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); switch (op) { case OPC_BC1EQZ: @@ -8756,7 +8754,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) tcg_temp_free_i32(fs_tmp); } /* Stop translation as we may have changed hflags */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; #if defined(TARGET_MIPS64) case OPC_DMFC1: @@ -10755,19 +10753,19 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) gen_store_gpr(t0, rt); break; case 2: - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } gen_helper_rdhwr_cc(t0, cpu_env); - if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) { + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_end(); } gen_store_gpr(t0, rt); /* Break the TB to be able to take timer interrupts immediately - after reading count. BS_STOP isn't sufficient, we need to ensure + after reading count. DISAS_STOP isn't sufficient, we need to ensure we break completely out of translated code. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; break; case 3: gen_helper_rdhwr_ccres(t0, cpu_env); @@ -10817,7 +10815,7 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel) static inline void clear_branch_hflags(DisasContext *ctx) { ctx->hflags &= ~MIPS_HFLAG_BMASK; - if (ctx->bstate == BS_NONE) { + if (ctx->base.is_jmp == DISAS_NEXT) { save_cpu_state(ctx, 0); } else { /* it is not safe to save ctx->hflags as hflags may be changed @@ -10832,11 +10830,11 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK; /* Branches completion */ clear_branch_hflags(ctx); - ctx->bstate = BS_BRANCH; + ctx->base.is_jmp = DISAS_NORETURN; /* FIXME: Need to clear can_do_io. */ switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) { case MIPS_HFLAG_FBNSLOT: - gen_goto_tb(ctx, 0, ctx->pc + insn_bytes); + gen_goto_tb(ctx, 0, ctx->base.pc_next + insn_bytes); break; case MIPS_HFLAG_B: /* unconditional branch */ @@ -10855,7 +10853,7 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) TCGLabel *l1 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); - gen_goto_tb(ctx, 1, ctx->pc + insn_bytes); + gen_goto_tb(ctx, 1, ctx->base.pc_next + insn_bytes); gen_set_label(l1); gen_goto_tb(ctx, 0, ctx->btarget); } @@ -10878,7 +10876,7 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) } else { tcg_gen_mov_tl(cpu_PC, btarget); } - if (ctx->singlestep_enabled) { + if (ctx->base.singlestep_enabled) { save_cpu_state(ctx, 0); gen_helper_raise_exception_debug(cpu_env); } @@ -10903,7 +10901,7 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx - "\n", ctx->pc); + "\n", ctx->base.pc_next); #endif generate_exception_end(ctx, EXCP_RI); goto out; @@ -10917,10 +10915,10 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, gen_load_gpr(t0, rs); gen_load_gpr(t1, rt); bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); if (rs <= rt && rs == 0) { /* OPC_BEQZALC, OPC_BNEZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 4 + m16_lowbit); } break; case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ @@ -10928,23 +10926,23 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, gen_load_gpr(t0, rs); gen_load_gpr(t1, rt); bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); break; case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ if (rs == 0 || rs == rt) { /* OPC_BLEZALC, OPC_BGEZALC */ /* OPC_BGTZALC, OPC_BLTZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 4 + m16_lowbit); } gen_load_gpr(t0, rs); gen_load_gpr(t1, rt); bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); break; case OPC_BC: case OPC_BALC: - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); break; case OPC_BEQZC: case OPC_BNEZC: @@ -10952,7 +10950,7 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, /* OPC_BEQZC, OPC_BNEZC */ gen_load_gpr(t0, rs); bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); } else { /* OPC_JIC, OPC_JIALC */ TCGv tbase = tcg_temp_new(); @@ -10975,13 +10973,13 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, /* Uncoditional compact branch */ switch (opc) { case OPC_JIALC: - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 4 + m16_lowbit); /* Fallthrough */ case OPC_JIC: ctx->hflags |= MIPS_HFLAG_BR; break; case OPC_BALC: - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 4 + m16_lowbit); /* Fallthrough */ case OPC_BC: ctx->hflags |= MIPS_HFLAG_B; @@ -11606,7 +11604,7 @@ static void decode_i64_mips16 (DisasContext *ctx, static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) { - int extend = cpu_lduw_code(env, ctx->pc + 2); + int extend = cpu_lduw_code(env, ctx->base.pc_next + 2); int op, rx, ry, funct, sa; int16_t imm, offset; @@ -11846,7 +11844,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_JAL: - offset = cpu_lduw_code(env, ctx->pc + 2); + offset = cpu_lduw_code(env, ctx->base.pc_next + 2); offset = (((ctx->opcode & 0x1f) << 21) | ((ctx->opcode >> 5) & 0x1f) << 16 | offset) << 2; @@ -13574,7 +13572,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) gen_helper_di(t0, cpu_env); gen_store_gpr(t0, rs); /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; tcg_temp_free(t0); } break; @@ -13586,10 +13584,10 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rs); - /* BS_STOP isn't sufficient, we need to ensure we break out + /* DISAS_STOP isn't sufficient, we need to ensure we break out of translated code to check for pending interrupts. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; tcg_temp_free(t0); } break; @@ -13944,7 +13942,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) uint32_t op, minor, minor2, mips32_op; uint32_t cond, fmt, cc; - insn = cpu_lduw_code(env, ctx->pc + 2); + insn = cpu_lduw_code(env, ctx->base.pc_next + 2); ctx->opcode = (ctx->opcode << 16) | insn; rt = (ctx->opcode >> 21) & 0x1f; @@ -14745,7 +14743,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) /* SYNCI */ /* Break the TB to be able to sync copied instructions immediately */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; } else { /* TNEI */ mips32_op = OPC_TNEI; @@ -14776,7 +14774,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) check_insn_opc_removed(ctx, ISA_MIPS32R6); /* Break the TB to be able to sync copied instructions immediately */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case BC2F: case BC2T: @@ -15139,16 +15137,16 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ switch ((ctx->opcode >> 16) & 0x1f) { case ADDIUPC_00 ... ADDIUPC_07: - gen_pcrel(ctx, OPC_ADDIUPC, ctx->pc & ~0x3, rt); + gen_pcrel(ctx, OPC_ADDIUPC, ctx->base.pc_next & ~0x3, rt); break; case AUIPC: - gen_pcrel(ctx, OPC_AUIPC, ctx->pc, rt); + gen_pcrel(ctx, OPC_AUIPC, ctx->base.pc_next, rt); break; case ALUIPC: - gen_pcrel(ctx, OPC_ALUIPC, ctx->pc, rt); + gen_pcrel(ctx, OPC_ALUIPC, ctx->base.pc_next, rt); break; case LWPC_08 ... LWPC_0F: - gen_pcrel(ctx, R6_OPC_LWPC, ctx->pc & ~0x3, rt); + gen_pcrel(ctx, R6_OPC_LWPC, ctx->base.pc_next & ~0x3, rt); break; default: generate_exception(ctx, EXCP_RI); @@ -15280,8 +15278,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) uint32_t op; /* make sure instructions are on a halfword boundary */ - if (ctx->pc & 0x1) { - env->CP0_BadVAddr = ctx->pc; + if (ctx->base.pc_next & 0x1) { + env->CP0_BadVAddr = ctx->base.pc_next; generate_exception_end(ctx, EXCP_AdEL); return 2; } @@ -18507,7 +18505,7 @@ static void gen_msa_branch(CPUMIPSState *env, DisasContext *ctx, uint32_t op1) break; } - ctx->btarget = ctx->pc + (s16 << 2) + 4; + ctx->btarget = ctx->base.pc_next + (s16 << 2) + 4; ctx->hflags |= MIPS_HFLAG_BC; ctx->hflags |= MIPS_HFLAG_BDS32; @@ -19528,8 +19526,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) int16_t imm; /* make sure instructions are on a word boundary */ - if (ctx->pc & 0x3) { - env->CP0_BadVAddr = ctx->pc; + if (ctx->base.pc_next & 0x3) { + env->CP0_BadVAddr = ctx->base.pc_next; generate_exception_err(ctx, EXCP_AdEL, EXCP_INST_NOTAVAIL); return; } @@ -19540,7 +19538,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK); - gen_goto_tb(ctx, 1, ctx->pc + 4); + gen_goto_tb(ctx, 1, ctx->base.pc_next + 4); gen_set_label(l1); } @@ -19601,7 +19599,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) check_insn(ctx, ISA_MIPS32R2); /* Break the TB to be able to sync copied instructions immediately */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case OPC_BPOSGE32: /* MIPS DSP branch */ #if defined(TARGET_MIPS64) @@ -19704,17 +19702,17 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) gen_store_gpr(t0, rt); /* Stop translation as we may have switched the execution mode. */ - ctx->bstate = BS_STOP; + ctx->base.is_jmp = DISAS_STOP; break; case OPC_EI: check_insn(ctx, ISA_MIPS32R2); save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rt); - /* BS_STOP isn't sufficient, we need to ensure we break out - of translated code to check for pending interrupts. */ - gen_save_pc(ctx->pc + 4); - ctx->bstate = BS_EXCP; + /* DISAS_STOP isn't sufficient, we need to ensure we break + out of translated code to check for pending interrupts */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; break; default: /* Invalid */ MIPS_INVAL("mfmc0"); @@ -20188,7 +20186,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) break; case OPC_PCREL: check_insn(ctx, ISA_MIPS32R6); - gen_pcrel(ctx, ctx->opcode, ctx->pc, rs); + gen_pcrel(ctx, ctx->opcode, ctx->base.pc_next, rs); break; default: /* Invalid */ MIPS_INVAL("major opcode"); @@ -20197,183 +20195,186 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) } } -void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { + DisasContext *ctx = container_of(dcbase, DisasContext, base); CPUMIPSState *env = cs->env_ptr; - DisasContext ctx; - target_ulong pc_start; - target_ulong next_page_start; - int num_insns; - int max_insns; - int insn_bytes; - int is_slot; - pc_start = tb->pc; - next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - ctx.pc = pc_start; - ctx.saved_pc = -1; - ctx.singlestep_enabled = cs->singlestep_enabled; - ctx.insn_flags = env->insn_flags; - ctx.CP0_Config1 = env->CP0_Config1; - ctx.tb = tb; - ctx.bstate = BS_NONE; - ctx.btarget = 0; - ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff; - ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1; - ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 3; - ctx.bi = (env->CP0_Config3 >> CP0C3_BI) & 1; - ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1; - ctx.PAMask = env->PAMask; - ctx.mvh = (env->CP0_Config5 >> CP0C5_MVH) & 1; - ctx.eva = (env->CP0_Config5 >> CP0C5_EVA) & 1; - ctx.sc = (env->CP0_Config3 >> CP0C3_SC) & 1; - ctx.CP0_LLAddr_shift = env->CP0_LLAddr_shift; - ctx.cmgcr = (env->CP0_Config3 >> CP0C3_CMGCR) & 1; + ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; + ctx->saved_pc = -1; + ctx->insn_flags = env->insn_flags; + ctx->CP0_Config1 = env->CP0_Config1; + ctx->btarget = 0; + ctx->kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff; + ctx->rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1; + ctx->ie = (env->CP0_Config4 >> CP0C4_IE) & 3; + ctx->bi = (env->CP0_Config3 >> CP0C3_BI) & 1; + ctx->bp = (env->CP0_Config3 >> CP0C3_BP) & 1; + ctx->PAMask = env->PAMask; + ctx->mvh = (env->CP0_Config5 >> CP0C5_MVH) & 1; + ctx->eva = (env->CP0_Config5 >> CP0C5_EVA) & 1; + ctx->sc = (env->CP0_Config3 >> CP0C3_SC) & 1; + ctx->CP0_LLAddr_shift = env->CP0_LLAddr_shift; + ctx->cmgcr = (env->CP0_Config3 >> CP0C3_CMGCR) & 1; /* Restore delay slot state from the tb context. */ - ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ - ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; - ctx.ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) || + ctx->hflags = (uint32_t)ctx->base.tb->flags; /* FIXME: maybe use 64 bits? */ + ctx->ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; + ctx->ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) || (env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)); - ctx.vp = (env->CP0_Config5 >> CP0C5_VP) & 1; - ctx.mrp = (env->CP0_Config5 >> CP0C5_MRP) & 1; - ctx.nan2008 = (env->active_fpu.fcr31 >> FCR31_NAN2008) & 1; - ctx.abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; - restore_cpu_state(env, &ctx); + ctx->vp = (env->CP0_Config5 >> CP0C5_VP) & 1; + ctx->mrp = (env->CP0_Config5 >> CP0C5_MRP) & 1; + ctx->nan2008 = (env->active_fpu.fcr31 >> FCR31_NAN2008) & 1; + ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1; + restore_cpu_state(env, ctx); #ifdef CONFIG_USER_ONLY - ctx.mem_idx = MIPS_HFLAG_UM; + ctx->mem_idx = MIPS_HFLAG_UM; #else - ctx.mem_idx = hflags_mmu_index(ctx.hflags); + ctx->mem_idx = hflags_mmu_index(ctx->hflags); #endif - ctx.default_tcg_memop_mask = (ctx.insn_flags & ISA_MIPS32R6) ? - MO_UNALN : MO_ALIGN; - num_insns = 0; - max_insns = tb_cflags(tb) & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } + ctx->default_tcg_memop_mask = (ctx->insn_flags & ISA_MIPS32R6) ? + MO_UNALN : MO_ALIGN; - LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); - gen_tb_start(tb); - while (ctx.bstate == BS_NONE) { - tcg_gen_insn_start(ctx.pc, ctx.hflags & MIPS_HFLAG_BMASK, ctx.btarget); - num_insns++; + LOG_DISAS("\ntb %p idx %d hflags %04x\n", ctx->base.tb, ctx->mem_idx, + ctx->hflags); +} - if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { - save_cpu_state(&ctx, 1); - ctx.bstate = BS_BRANCH; - gen_helper_raise_exception_debug(cpu_env); - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx.pc += 4; - goto done_generating; - } +static void mips_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) +{ +} - if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { - gen_io_start(); - } +static void mips_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); - is_slot = ctx.hflags & MIPS_HFLAG_BMASK; - if (!(ctx.hflags & MIPS_HFLAG_M16)) { - ctx.opcode = cpu_ldl_code(env, ctx.pc); - insn_bytes = 4; - decode_opc(env, &ctx); - } else if (ctx.insn_flags & ASE_MICROMIPS) { - ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_micromips_opc(env, &ctx); - } else if (ctx.insn_flags & ASE_MIPS16) { - ctx.opcode = cpu_lduw_code(env, ctx.pc); - insn_bytes = decode_mips16_opc(env, &ctx); - } else { - generate_exception_end(&ctx, EXCP_RI); - break; - } + tcg_gen_insn_start(ctx->base.pc_next, ctx->hflags & MIPS_HFLAG_BMASK, + ctx->btarget); +} - if (ctx.hflags & MIPS_HFLAG_BMASK) { - if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 | - MIPS_HFLAG_FBNSLOT))) { - /* force to generate branch as there is neither delay nor - forbidden slot */ - is_slot = 1; - } - if ((ctx.hflags & MIPS_HFLAG_M16) && - (ctx.hflags & MIPS_HFLAG_FBNSLOT)) { - /* Force to generate branch as microMIPS R6 doesn't restrict - branches in the forbidden slot. */ - is_slot = 1; - } - } - if (is_slot) { - gen_branch(&ctx, insn_bytes); - } - ctx.pc += insn_bytes; +static bool mips_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, + const CPUBreakpoint *bp) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); - /* Execute a branch and its delay slot as a single instruction. - This is what GDB expects and is consistent with what the - hardware does (e.g. if a delay slot instruction faults, the - reported PC is the PC of the branch). */ - if (cs->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) { - break; - } + save_cpu_state(ctx, 1); + ctx->base.is_jmp = DISAS_NORETURN; + gen_helper_raise_exception_debug(cpu_env); + /* The address covered by the breakpoint must be included in + [tb->pc, tb->pc + tb->size) in order to for it to be + properly cleared -- thus we increment the PC here so that + the logic setting tb->size below does the right thing. */ + ctx->base.pc_next += 4; + return true; +} - if (ctx.pc >= next_page_start) { - break; - } +static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +{ + CPUMIPSState *env = cs->env_ptr; + DisasContext *ctx = container_of(dcbase, DisasContext, base); + int insn_bytes; + int is_slot; - if (tcg_op_buf_full()) { - break; - } + is_slot = ctx->hflags & MIPS_HFLAG_BMASK; + if (!(ctx->hflags & MIPS_HFLAG_M16)) { + ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); + insn_bytes = 4; + decode_opc(env, ctx); + } else if (ctx->insn_flags & ASE_MICROMIPS) { + ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next); + insn_bytes = decode_micromips_opc(env, ctx); + } else if (ctx->insn_flags & ASE_MIPS16) { + ctx->opcode = cpu_lduw_code(env, ctx->base.pc_next); + insn_bytes = decode_mips16_opc(env, ctx); + } else { + generate_exception_end(ctx, EXCP_RI); + g_assert(ctx->base.is_jmp == DISAS_NORETURN); + return; + } - if (num_insns >= max_insns) - break; + if (ctx->hflags & MIPS_HFLAG_BMASK) { + if (!(ctx->hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 | + MIPS_HFLAG_FBNSLOT))) { + /* force to generate branch as there is neither delay nor + forbidden slot */ + is_slot = 1; + } + if ((ctx->hflags & MIPS_HFLAG_M16) && + (ctx->hflags & MIPS_HFLAG_FBNSLOT)) { + /* Force to generate branch as microMIPS R6 doesn't restrict + branches in the forbidden slot. */ + is_slot = 1; + } + } + if (is_slot) { + gen_branch(ctx, insn_bytes); + } + ctx->base.pc_next += insn_bytes; - if (singlestep) - break; + if (ctx->base.is_jmp != DISAS_NEXT) { + return; } - if (tb_cflags(tb) & CF_LAST_IO) { - gen_io_end(); + /* Execute a branch and its delay slot as a single instruction. + This is what GDB expects and is consistent with what the + hardware does (e.g. if a delay slot instruction faults, the + reported PC is the PC of the branch). */ + if (ctx->base.singlestep_enabled && + (ctx->hflags & MIPS_HFLAG_BMASK) == 0) { + ctx->base.is_jmp = DISAS_TOO_MANY; } - if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) { - save_cpu_state(&ctx, ctx.bstate != BS_EXCP); + if (ctx->base.pc_next - ctx->page_start >= TARGET_PAGE_SIZE) { + ctx->base.is_jmp = DISAS_TOO_MANY; + } +} + +static void mips_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + if (ctx->base.singlestep_enabled && ctx->base.is_jmp != DISAS_NORETURN) { + save_cpu_state(ctx, ctx->base.is_jmp != DISAS_EXIT); gen_helper_raise_exception_debug(cpu_env); } else { - switch (ctx.bstate) { - case BS_STOP: - gen_goto_tb(&ctx, 0, ctx.pc); + switch (ctx->base.is_jmp) { + case DISAS_STOP: + gen_save_pc(ctx->base.pc_next); + tcg_gen_lookup_and_goto_ptr(); break; - case BS_NONE: - save_cpu_state(&ctx, 0); - gen_goto_tb(&ctx, 0, ctx.pc); + case DISAS_NEXT: + case DISAS_TOO_MANY: + save_cpu_state(ctx, 0); + gen_goto_tb(ctx, 0, ctx->base.pc_next); break; - case BS_EXCP: + case DISAS_EXIT: tcg_gen_exit_tb(0); break; - case BS_BRANCH: - default: + case DISAS_NORETURN: break; + default: + g_assert_not_reached(); } } -done_generating: - gen_tb_end(tb, num_insns); - - tb->size = ctx.pc - pc_start; - tb->icount = num_insns; - -#ifdef DEBUG_DISAS - LOG_DISAS("\n"); - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - qemu_log_lock(); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, ctx.pc - pc_start); - qemu_log("\n"); - qemu_log_unlock(); - } -#endif +} + +static void mips_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +{ + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); + log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); +} + +static const TranslatorOps mips_tr_ops = { + .init_disas_context = mips_tr_init_disas_context, + .tb_start = mips_tr_tb_start, + .insn_start = mips_tr_insn_start, + .breakpoint_check = mips_tr_breakpoint_check, + .translate_insn = mips_tr_translate_insn, + .tb_stop = mips_tr_tb_stop, + .disas_log = mips_tr_disas_log, +}; + +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) +{ + DisasContext ctx; + + translator_loop(&mips_tr_ops, &ctx.base, cs, tb); } static void fpu_dump_state(CPUMIPSState *env, FILE *f, fprintf_function fpu_fprintf, |