diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3314c9d91b..5e4b91dcc3 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -1,6 +1,8 @@ #if !defined (__MIPS_CPU_H__) #define __MIPS_CPU_H__ +#define TARGET_HAS_ICE 1 + #include "mips-defs.h" #include "cpu-defs.h" #include "config.h" @@ -18,6 +20,7 @@ typedef struct tlb_t tlb_t; struct tlb_t { target_ulong VPN; target_ulong end; + target_ulong end2; uint8_t ASID; uint8_t G; uint8_t C[2]; @@ -151,18 +154,20 @@ struct CPUMIPSState { #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ -#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */ - /* Those flags keep the branch state if the translation is interrupted - * between the branch instruction and the delay slot - */ -#define MIPS_HFLAG_BMASK 0x0F00 -#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ -#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ -#define MIPS_HFLAG_BL 0x0400 /* Likely branch */ -#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ + /* If translation is interrupted between the branch instruction and + * the delay slot, record what type of branch it is so that we can + * resume translation properly. It might be possible to reduce + * this from three bits to two. */ +#define MIPS_HFLAG_BMASK 0x0380 +#define MIPS_HFLAG_B 0x0080 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0100 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0180 /* Likely branch */ +#define MIPS_HFLAG_BR 0x0200 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ + int halted; /* TRUE if the CPU is in suspend state */ + CPU_COMMON }; @@ -202,15 +207,15 @@ enum { EXCP_IBE, EXCP_DBp, EXCP_SYSCALL, - EXCP_BREAK, - EXCP_CpU, /* 16 */ + EXCP_BREAK, /* 16 */ + EXCP_CpU, EXCP_RI, EXCP_OVERFLOW, EXCP_TRAP, EXCP_DDBS, EXCP_DWATCH, - EXCP_LAE, /* 22 */ - EXCP_SAE, + EXCP_LAE, + EXCP_SAE, /* 24 */ EXCP_LTLBL, EXCP_TLBL, EXCP_TLBS, diff --git a/target-mips/exec.h b/target-mips/exec.h index b3e423493b..7031862c10 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -65,19 +65,19 @@ void do_tlbwi (void); void do_tlbwr (void); void do_tlbp (void); void do_tlbr (void); -void do_lwl_raw (void); -void do_lwr_raw (void); -void do_swl_raw (void); -void do_swr_raw (void); +void do_lwl_raw (uint32_t); +void do_lwr_raw (uint32_t); +uint32_t do_swl_raw (uint32_t); +uint32_t do_swr_raw (uint32_t); #if !defined(CONFIG_USER_ONLY) -void do_lwl_user (void); -void do_lwl_kernel (void); -void do_lwr_user (void); -void do_lwr_kernel (void); -void do_swl_user (void); -void do_swl_kernel (void); -void do_swr_user (void); -void do_swr_kernel (void); +void do_lwl_user (uint32_t); +void do_lwl_kernel (uint32_t); +void do_lwr_user (uint32_t); +void do_lwr_kernel (uint32_t); +uint32_t do_swl_user (uint32_t); +uint32_t do_swl_kernel (uint32_t); +uint32_t do_swr_user (uint32_t); +uint32_t do_swr_kernel (uint32_t); #endif void do_pmon (int function); @@ -88,6 +88,7 @@ void do_interrupt (CPUState *env); void cpu_loop_exit(void); void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); +void do_raise_exception_direct (uint32_t exception); void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), diff --git a/target-mips/helper.c b/target-mips/helper.c index 8d2617557a..8b4deb3ddc 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -46,7 +46,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && - tlb->VPN == tag && address < tlb->end) { + tlb->VPN == tag && address < tlb->end2) { /* TLB match */ n = (address >> 12) & 1; /* Check access rights */ @@ -167,10 +167,15 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int ret = 0; if (logfile) { +#if 0 cpu_dump_state(env, logfile, fprintf, 0); +#endif fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", __func__, env->PC, address, rw, is_user, is_softmmu); } + + rw &= 1; + /* data access */ /* XXX: put correct access by using cpu_restore_state() correctly */ @@ -226,7 +231,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* Raise exception */ env->CP0_BadVAddr = address; env->CP0_Context = (env->CP0_Context & 0xff800000) | - ((address >> 8) & 0x007ffff0); + ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = (env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000); env->exception_index = exception; @@ -276,11 +281,12 @@ void do_interrupt (CPUState *env) env->CP0_Debug |= 1 << CP0DB_DDBL; goto set_DEPC; set_DEPC: - if (env->hflags & MIPS_HFLAG_DS) { + if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump */ env->CP0_DEPC = env->PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_DEPC = env->PC; } @@ -316,8 +322,7 @@ void do_interrupt (CPUState *env) env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) | (1 << CP0St_NMI); set_error_EPC: - env->hflags = MIPS_HFLAG_ERL; - if (env->hflags & MIPS_HFLAG_DS) { + if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump */ @@ -325,6 +330,7 @@ void do_interrupt (CPUState *env) } else { env->CP0_ErrorEPC = env->PC; } + env->hflags = MIPS_HFLAG_ERL; pc = 0xBFC00000; break; case EXCP_MCHECK: @@ -366,7 +372,7 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_CpU: cause = 11; - /* XXX: fill in the faulty unit number */ + env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28); goto set_EPC; case EXCP_OVERFLOW: cause = 12; @@ -391,12 +397,13 @@ void do_interrupt (CPUState *env) env->hflags |= MIPS_HFLAG_EXL; pc += offset; env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); - if (env->hflags & MIPS_HFLAG_DS) { + if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump */ env->CP0_EPC = env->PC - 4; env->CP0_Cause |= 0x80000000; + env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_EPC = env->PC; env->CP0_Cause &= ~0x80000000; diff --git a/target-mips/op.c b/target-mips/op.c index 029ce5d005..71abd95bea 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -207,7 +207,7 @@ void op_addo (void) tmp = T0; T0 += T1; if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) { - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } RETURN(); } @@ -225,7 +225,7 @@ void op_subo (void) tmp = T0; T0 = (int32_t)T0 - (int32_t)T1; if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) { - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } RETURN(); } @@ -364,7 +364,7 @@ static inline void set_HILO (uint64_t HILO) void op_mult (void) { - set_HILO((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); RETURN(); } @@ -378,7 +378,7 @@ void op_madd (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() + tmp); RETURN(); } @@ -396,7 +396,7 @@ void op_msub (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() - tmp); RETURN(); } @@ -595,11 +595,16 @@ void op_pmon (void) void op_trap (void) { if (T0) { - CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); + CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP); } RETURN(); } +void op_debug (void) +{ + CALL_FROM_TB1(do_raise_exception_direct, EXCP_DEBUG); +} + void op_set_lladdr (void) { env->CP0_LLAddr = T2; @@ -654,3 +659,8 @@ void op_exit_tb (void) EXIT_TB(); } +void op_wait (void) +{ + env->halted = 1; + CALL_FROM_TB1(do_raise_exception, EXCP_HLT); +} diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index cb4789cfa5..be207b9bb9 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -22,6 +22,8 @@ #define MIPS_DEBUG_DISAS +#define GETPC() (__builtin_return_address(0)) + /*****************************************************************************/ /* Exceptions processing helpers */ void cpu_loop_exit(void) @@ -46,6 +48,21 @@ void do_raise_exception (uint32_t exception) do_raise_exception_err(exception, 0); } +void do_restore_state (void *pc_ptr) +{ + TranslationBlock *tb; + unsigned long pc = (unsigned long) pc_ptr; + + tb = tb_find_pc (pc); + cpu_restore_state (tb, env, pc, NULL); +} + +void do_raise_exception_direct (uint32_t exception) +{ + do_restore_state (GETPC ()); + do_raise_exception_err (exception, 0); +} + #define MEMSUFFIX _raw #include "op_helper_mem.c" #undef MEMSUFFIX @@ -73,7 +90,7 @@ static inline void set_HILO (uint64_t HILO) void do_mult (void) { - set_HILO((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); } void do_multu (void) @@ -85,7 +102,7 @@ void do_madd (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() + tmp); } @@ -101,7 +118,7 @@ void do_msub (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() - tmp); } @@ -353,6 +370,9 @@ void do_mtc0 (int reg, int sel) val = T0 & 0xFFFFF0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; + /* If the ASID changes, flush qemu's TLB. */ + if ((old & 0xFF) != (val & 0xFF)) + tlb_flush (env, 1); rn = "EntryHi"; break; case 11: @@ -525,11 +545,25 @@ static void invalidate_tb (int idx) addr = tlb->PFN[0]; end = addr + (tlb->end - tlb->VPN); tb_invalidate_page_range(addr, end); + /* FIXME: Might be faster to just invalidate the whole "tlb" here + and refill it on demand from our simulated TLB. */ + addr = tlb->VPN; + while (addr < tlb->end) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } } if (tlb->V[1]) { addr = tlb->PFN[1]; end = addr + (tlb->end - tlb->VPN); tb_invalidate_page_range(addr, end); + /* FIXME: Might be faster to just invalidate the whole "tlb" here + and refill it on demand from our simulated TLB. */ + addr = tlb->end; + while (addr < tlb->end2) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } } } @@ -545,6 +579,7 @@ static void fill_tb (int idx) size = env->CP0_PageMask >> 13; size = 4 * (size + 1); tlb->end = tlb->VPN + (1 << (8 + size)); + tlb->end2 = tlb->end + (1 << (8 + size)); tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; tlb->V[0] = env->CP0_EntryLo0 & 2; tlb->D[0] = env->CP0_EntryLo0 & 4; @@ -601,6 +636,12 @@ void do_tlbr (void) int size; tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; + + /* If this will change the current ASID, flush qemu's TLB. */ + /* FIXME: Could avoid flushing things which match global entries... */ + if ((env->CP0_EntryHi & 0xFF) != tlb->ASID) + tlb_flush (env, 1); + env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; env->CP0_PageMask = (size - 1) << 13; @@ -664,8 +705,10 @@ void do_pmon (int function) #if !defined(CONFIG_USER_ONLY) +static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); + #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#define ALIGNED_ONLY #define SHIFT 0 #include "softmmu_template.h" @@ -679,6 +722,13 @@ void do_pmon (int function) #define SHIFT 3 #include "softmmu_template.h" +static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + env->CP0_BadVAddr = addr; + do_restore_state (retaddr); + do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); +} + void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 69793b0b97..3a6d386a68 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -1,11 +1,9 @@ -void glue(do_lwl, MEMSUFFIX) (void) +void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav = T0; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ @@ -32,14 +30,12 @@ void glue(do_lwl, MEMSUFFIX) (void) RETURN(); } -void glue(do_lwr, MEMSUFFIX) (void) +void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav = T0; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ @@ -66,14 +62,12 @@ void glue(do_lwr, MEMSUFFIX) (void) RETURN(); } -void glue(do_swl, MEMSUFFIX) (void) +uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); #if defined (DEBUG_OP) sav = tmp; #endif @@ -94,7 +88,6 @@ void glue(do_swl, MEMSUFFIX) (void) tmp = (tmp & 0xFFFFFF00) | (T1 >> 24); break; } - glue(stl, MEMSUFFIX)(T0 & ~3, tmp); #if defined (DEBUG_OP) if (logfile) { fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", @@ -102,16 +95,15 @@ void glue(do_swl, MEMSUFFIX) (void) } #endif RETURN(); + return tmp; } -void glue(do_swr, MEMSUFFIX) (void) +uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); #if defined (DEBUG_OP) sav = tmp; #endif @@ -132,7 +124,6 @@ void glue(do_swr, MEMSUFFIX) (void) tmp = T1; break; } - glue(stl, MEMSUFFIX)(T0 & ~3, tmp); #if defined (DEBUG_OP) if (logfile) { fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", @@ -140,4 +131,5 @@ void glue(do_swr, MEMSUFFIX) (void) } #endif RETURN(); + return tmp; } diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index bbb322db49..7fcfc24a6f 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -67,28 +67,35 @@ void glue(op_sw, MEMSUFFIX) (void) RETURN(); } -/* "half" load and stores */ +/* "half" load and stores. We must do the memory access inline, + or fault handling won't work. */ void glue(op_lwl, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + CALL_FROM_TB1(glue(do_lwl, MEMSUFFIX), tmp); RETURN(); } void glue(op_lwr, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + CALL_FROM_TB1(glue(do_lwr, MEMSUFFIX), tmp); RETURN(); } void glue(op_swl, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_swl, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + tmp = CALL_FROM_TB1(glue(do_swl, MEMSUFFIX), tmp); + glue(stl, MEMSUFFIX)(T0 & ~3, tmp); RETURN(); } void glue(op_swr, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_swr, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + tmp = CALL_FROM_TB1(glue(do_swr, MEMSUFFIX), tmp); + glue(stl, MEMSUFFIX)(T0 & ~3, tmp); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index bb8128401f..418a7afa03 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -338,17 +338,25 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } } -static inline void generate_exception (DisasContext *ctx, int excp) +static inline void generate_exception_err (DisasContext *ctx, int excp, int err) { #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) fprintf(logfile, "%s: raise exception %d\n", __func__, excp); #endif save_cpu_state(ctx, 1); - gen_op_raise_exception(excp); + if (err == 0) + gen_op_raise_exception(excp); + else + gen_op_raise_exception_err(excp, err); ctx->bstate = BS_EXCP; } +static inline void generate_exception (DisasContext *ctx, int excp) +{ + generate_exception_err (ctx, excp, 0); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -1020,14 +1028,14 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_BLEZ: /* 0 <= 0 */ case OPC_BLEZL: /* 0 <= 0 likely */ /* Always take */ - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways"); break; case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZALL: /* 0 >= 0 likely */ /* Always take and link */ blink = 31; - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways and link"); break; case OPC_BNE: /* rx != rx */ @@ -1053,21 +1061,21 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, gen_goto_tb(ctx, 0, ctx->pc + 4); return; case OPC_J: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("j %08x", btarget); break; case OPC_JAL: blink = 31; - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("jal %08x", btarget); break; case OPC_JR: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; + ctx->hflags |= MIPS_HFLAG_BR; MIPS_DEBUG("jr %s", regnames[rs]); break; case OPC_JALR: blink = rt; - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; + ctx->hflags |= MIPS_HFLAG_BR; MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); break; default: @@ -1144,14 +1152,14 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, blink = 31; MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); not_likely: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC; + ctx->hflags |= MIPS_HFLAG_BC; break; case OPC_BLTZALL: gen_op_ltz(); blink = 31; MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); likely: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL; + ctx->hflags |= MIPS_HFLAG_BL; break; } gen_op_set_bcond(); @@ -1178,7 +1186,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "CP0 is not usable\n"); } - gen_op_raise_exception_err(EXCP_CpU, 0); + generate_exception_err (ctx, EXCP_CpU, 0); return; } switch (opc) { @@ -1236,7 +1244,15 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) ctx->bstate = BS_EXCP; } break; - /* XXX: TODO: WAIT */ + case OPC_WAIT: + opn = "wait"; + /* If we get an exception, we want to restart at next instruction */ + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; + gen_op_wait(); + ctx->bstate = BS_EXCP; + break; default: if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n", @@ -1292,7 +1308,7 @@ static void gen_blikely(DisasContext *ctx) int l1; l1 = gen_new_label(); gen_op_jnz_T2(l1); - gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); + gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); gen_goto_tb(ctx, 1, ctx->pc + 4); gen_set_label(l1); } @@ -1304,8 +1320,7 @@ static void decode_opc (DisasContext *ctx) uint16_t op, op1; int16_t imm; - if ((ctx->hflags & MIPS_HFLAG_DS) && - (ctx->hflags & MIPS_HFLAG_BL)) { + if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { /* Handle blikely not taken case */ MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); gen_blikely(ctx); @@ -1361,9 +1376,16 @@ static void decode_opc (DisasContext *ctx) case 0x05: /* Pmon entry point */ gen_op_pmon((ctx->opcode >> 6) & 0x1F); break; -#if defined (MIPS_HAS_MOVCI) + case 0x01: /* MOVCI */ +#if defined (MIPS_HAS_MOVCI) + /* XXX */ +#else + /* Not implemented */ + generate_exception_err (ctx, EXCP_CpU, 1); #endif + break; + #if defined (TARGET_MIPS64) case 0x14: /* MIPS64 specific opcodes */ case 0x16: @@ -1438,7 +1460,7 @@ static void decode_opc (DisasContext *ctx) gen_cp0(ctx, op1 | EXT_CP0, rt, rd); break; default: - gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd); + gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd); break; } break; @@ -1467,23 +1489,35 @@ static void decode_opc (DisasContext *ctx) break; case 0x3F: /* HACK */ break; -#if defined(MIPS_USES_FPU) - case 0x31 ... 0x32: /* Floating point load/store */ - case 0x35 ... 0x36: - case 0x3A ... 0x3B: - case 0x3D ... 0x3E: - /* Not implemented */ - /* XXX: not correct */ -#endif + + /* Floating point. */ + case 0x31: /* LWC1 */ + case 0x35: /* LDC1 */ + case 0x39: /* SWC1 */ + case 0x3D: /* SDC1 */ case 0x11: /* CP1 opcode */ - /* Not implemented */ +#if defined(MIPS_USES_FPU) /* XXX: not correct */ +#else + generate_exception_err(ctx, EXCP_CpU, 1); +#endif + break; + + /* COP2. */ + case 0x32: /* LWC2 */ + case 0x36: /* LDC2 */ + case 0x3A: /* SWC2 */ + case 0x3E: /* SDC2 */ case 0x12: /* CP2 opcode */ /* Not implemented */ - /* XXX: not correct */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; + case 0x13: /* CP3 opcode */ /* Not implemented */ - /* XXX: not correct */ + generate_exception_err(ctx, EXCP_CpU, 3); + break; + #if defined (TARGET_MIPS64) case 0x18 ... 0x1B: case 0x27: @@ -1497,21 +1531,15 @@ static void decode_opc (DisasContext *ctx) #endif case 0x1E: /* ASE specific */ -#if defined (MIPS_HAS_LSC) - case 0x31: /* LWC1 */ - case 0x32: /* LWC2 */ - case 0x35: /* SDC1 */ - case 0x36: /* SDC2 */ -#endif default: /* Invalid */ MIPS_INVAL(""); generate_exception(ctx, EXCP_RI); break; } - if (ctx->hflags & MIPS_HFLAG_DS) { + if (ctx->hflags & MIPS_HFLAG_BMASK) { int hflags = ctx->hflags; /* Branches completion */ - ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS); + ctx->hflags &= ~MIPS_HFLAG_BMASK; ctx->bstate = BS_BRANCH; save_cpu_state(ctx, 0); switch (hflags & MIPS_HFLAG_BMASK) { @@ -1557,16 +1585,20 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, uint16_t *gen_opc_end; int j, lj = -1; + if (search_pc && loglevel) + fprintf (logfile, "search pc %d\n", search_pc); + pc_start = tb->pc; gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; nb_gen_labels = 0; ctx.pc = pc_start; + ctx.saved_pc = -1; ctx.tb = tb; ctx.bstate = BS_NONE; - /* Restore delay slot state */ - ctx.hflags = env->hflags; + /* Restore delay slot state from the tb context. */ + ctx.hflags = tb->flags; ctx.saved_hflags = ctx.hflags; if (ctx.hflags & MIPS_HFLAG_BR) { gen_op_restore_breg_target(); @@ -1588,42 +1620,65 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "------------------------------------------------\n"); + /* FIXME: This may print out stale hflags from env... */ cpu_dump_state(env, logfile, fprintf, 0); } #endif #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "\ntb %p super %d cond %04x %04x\n", - tb, ctx.mem_idx, ctx.hflags, env->hflags); + fprintf(logfile, "\ntb %p super %d cond %04x\n", + tb, ctx.mem_idx, ctx.hflags); #endif while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == ctx.pc) { + save_cpu_state(ctxp, 1); + ctx.bstate = BS_BRANCH; + gen_op_debug(); + goto done_generating; + } + } + } + if (search_pc) { j = gen_opc_ptr - gen_opc_buf; - save_cpu_state(ctxp, 1); if (lj < j) { lj++; while (lj < j) gen_opc_instr_start[lj++] = 0; - gen_opc_pc[lj] = ctx.pc; - gen_opc_instr_start[lj] = 1; } + gen_opc_pc[lj] = ctx.pc; + gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; + gen_opc_instr_start[lj] = 1; } ctx.opcode = ldl_code(ctx.pc); decode_opc(&ctx); ctx.pc += 4; + + if (env->singlestep_enabled) + break; + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) break; + #if defined (MIPS_SINGLE_STEP) break; #endif } - if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { + if (env->singlestep_enabled) { + save_cpu_state(ctxp, ctx.bstate == BS_NONE); + gen_op_debug(); + goto done_generating; + } + else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { save_cpu_state(ctxp, 0); gen_goto_tb(&ctx, 0, ctx.pc); } gen_op_reset_T0(); /* Generate the return instruction */ gen_op_exit_tb(); +done_generating: *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf;