Fabrice, since the last combined patch I sent you, I've dropped the exec.c bits; added EXCP_HALTED; improved the unaligned access traps; and shaved two bits off the branch delay slot state. It's still pretty slow, but I'm confident it can go faster. Also has the command line passing bits merged.
-- Daniel Jacobowitz CodeSourcery, LLC
Index: cpu-exec.c =================================================================== RCS file: /cvsroot/qemu/qemu/cpu-exec.c,v retrieving revision 1.69 diff -u -p -r1.69 cpu-exec.c --- cpu-exec.c 4 Dec 2005 18:46:05 -0000 1.69 +++ cpu-exec.c 4 Dec 2005 21:15:43 -0000 @@ -191,7 +191,7 @@ static inline TranslationBlock *tb_find_ cs_base = 0; pc = env->nip; #elif defined(TARGET_MIPS) - flags = env->hflags & MIPS_HFLAGS_TMASK; + flags = env->hflags & (MIPS_HFLAGS_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; pc = env->PC; #else @@ -280,6 +280,15 @@ int cpu_exec(CPUState *env1) set. */ if (env1->interrupt_request & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } +#elif defined(TARGET_MIPS) + if (env1->halted) { + if (env1->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) { env1->halted = 0; } else { return EXCP_HALTED; Index: exec-all.h =================================================================== RCS file: /cvsroot/qemu/qemu/exec-all.h,v retrieving revision 1.43 diff -u -p -r1.43 exec-all.h --- exec-all.h 28 Nov 2005 21:19:04 -0000 1.43 +++ exec-all.h 4 Dec 2005 21:15:43 -0000 @@ -62,6 +62,7 @@ extern target_ulong gen_opc_npc[OPC_BUF_ extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern target_ulong gen_opc_jump_pc[2]; +extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); Index: gdbstub.c =================================================================== RCS file: /cvsroot/qemu/qemu/gdbstub.c,v retrieving revision 1.33 diff -u -p -r1.33 gdbstub.c --- gdbstub.c 26 Nov 2005 10:38:38 -0000 1.33 +++ gdbstub.c 4 Dec 2005 21:15:43 -0000 @@ -421,6 +421,72 @@ static void cpu_gdb_write_registers(CPUS ptr += 8 * 12 + 4; cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); } +#elif defined (TARGET_MIPS) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + for (i = 0; i < 32; i++) + { + *(uint32_t *)ptr = tswapl(env->gpr[i]); + ptr += 4; + } + + *(uint32_t *)ptr = tswapl(env->CP0_Status); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->LO); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->HI); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->CP0_BadVAddr); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->CP0_Cause); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->PC); + ptr += 4; + + /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ + + return ptr - mem_buf; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + for (i = 0; i < 32; i++) + { + env->gpr[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + + env->CP0_Status = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->LO = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->HI = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->CP0_Cause = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->PC = tswapl(*(uint32_t *)ptr); + ptr += 4; +} #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { @@ -511,10 +577,12 @@ static int gdb_handle_packet(GDBState *s if (*p == ',') p++; len = strtoul(p, NULL, 16); - if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) - memset(mem_buf, 0, len); - memtohex(buf, mem_buf, len); - put_packet(s, buf); + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { + put_packet (s, "E14"); + } else { + memtohex(buf, mem_buf, len); + put_packet(s, buf); + } break; case 'M': addr = strtoul(p, (char **)&p, 16); Index: softmmu_template.h =================================================================== RCS file: /cvsroot/qemu/qemu/softmmu_template.h,v retrieving revision 1.14 diff -u -p -r1.14 softmmu_template.h --- softmmu_template.h 28 Nov 2005 21:19:04 -0000 1.14 +++ softmmu_template.h 4 Dec 2005 21:15:43 -0000 @@ -97,15 +97,28 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUF /* slow unaligned access (it spans two pages or IO) */ do_unaligned_access: retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); +#endif res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, is_user, retaddr); } else { - /* unaligned access in the same page */ + /* unaligned/aligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); + } +#endif res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); } } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); +#endif tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr); goto redo; } @@ -213,15 +226,28 @@ void REGPARM(2) glue(glue(__st, SUFFIX), } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, 1, is_user, retaddr); +#endif glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, is_user, retaddr); } else { /* aligned/unaligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, 1, is_user, retaddr); + } +#endif glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); } } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, 1, is_user, retaddr); +#endif tlb_fill(addr, 1, is_user, retaddr); goto redo; } Index: translate-all.c =================================================================== RCS file: /cvsroot/qemu/qemu/translate-all.c,v retrieving revision 1.13 diff -u -p -r1.13 translate-all.c --- translate-all.c 2 Jul 2005 14:56:31 -0000 1.13 +++ translate-all.c 4 Dec 2005 21:15:43 -0000 @@ -53,6 +53,8 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; #elif defined(TARGET_SPARC) target_ulong gen_opc_npc[OPC_BUF_SIZE]; target_ulong gen_opc_jump_pc[2]; +#elif defined(TARGET_MIPS) +uint32_t gen_opc_hflags[OPC_BUF_SIZE]; #endif int code_copy_enabled = 1; @@ -302,6 +304,8 @@ int cpu_restore_state(TranslationBlock * } #elif defined(TARGET_MIPS) env->PC = gen_opc_pc[j]; + env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags |= gen_opc_hflags[j]; #endif return 0; } Index: hw/mips_r4k.c =================================================================== RCS file: /cvsroot/qemu/qemu/hw/mips_r4k.c,v retrieving revision 1.11 diff -u -p -r1.11 mips_r4k.c --- hw/mips_r4k.c 23 Nov 2005 21:11:49 -0000 1.11 +++ hw/mips_r4k.c 4 Dec 2005 21:15:43 -0000 @@ -53,7 +53,7 @@ static void cpu_mips_update_count (CPUSt next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); if (next == now) next++; -#if 1 +#if 0 if (logfile) { fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", __func__, now, count, compare, next - now); @@ -84,7 +84,7 @@ static void mips_timer_cb (void *opaque) CPUState *env; env = opaque; -#if 1 +#if 0 if (logfile) { fprintf(logfile, "%s\n", __func__); } @@ -103,23 +103,29 @@ void cpu_mips_clock_init (CPUState *env) static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#endif cpu_outb(NULL, addr & 0xffff, value); } static uint32_t io_readb (void *opaque, target_phys_addr_t addr) { uint32_t ret = cpu_inb(NULL, addr & 0xffff); +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); +#endif return ret; } static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#endif #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); #endif @@ -132,15 +138,19 @@ static uint32_t io_readw (void *opaque, #ifdef TARGET_WORDS_BIGENDIAN ret = bswap16(ret); #endif +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); +#endif return ret; } static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#endif #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); #endif @@ -154,8 +164,10 @@ static uint32_t io_readl (void *opaque, #ifdef TARGET_WORDS_BIGENDIAN ret = bswap32(ret); #endif +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); +#endif return ret; } @@ -233,6 +245,11 @@ void mips_r4k_init (int ram_size, int vg initrd_size = 0; } env->PC = KERNEL_LOAD_ADDR; + /* Store command line. */ + strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); + /* FIXME: little endian support */ + *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); + *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); } else { kernel_base = 0; kernel_size = 0; Index: target-mips/cpu.h =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/cpu.h,v retrieving revision 1.3 diff -u -p -r1.3 cpu.h --- target-mips/cpu.h 20 Nov 2005 10:29:33 -0000 1.3 +++ target-mips/cpu.h 4 Dec 2005 21:15:43 -0000 @@ -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, Index: target-mips/exec.h =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/exec.h,v retrieving revision 1.4 diff -u -p -r1.4 exec.h --- target-mips/exec.h 30 Oct 2005 18:16:26 -0000 1.4 +++ target-mips/exec.h 4 Dec 2005 21:15:43 -0000 @@ -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, ...), Index: target-mips/helper.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/helper.c,v retrieving revision 1.7 diff -u -p -r1.7 helper.c --- target-mips/helper.c 4 Jul 2005 22:17:32 -0000 1.7 +++ target-mips/helper.c 4 Dec 2005 21:15:43 -0000 @@ -46,7 +46,7 @@ static int map_address (CPUState *env, t 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 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 /* 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; Index: target-mips/op.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/op.c,v retrieving revision 1.4 diff -u -p -r1.4 op.c --- target-mips/op.c 30 Oct 2005 21:39:18 -0000 1.4 +++ target-mips/op.c 4 Dec 2005 21:15:43 -0000 @@ -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 HI 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); +} Index: target-mips/op_helper.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/op_helper.c,v retrieving revision 1.7 diff -u -p -r1.7 op_helper.c --- target-mips/op_helper.c 26 Nov 2005 18:47:20 -0000 1.7 +++ target-mips/op_helper.c 4 Dec 2005 21:15:44 -0000 @@ -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 except 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 HI 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" @@ -678,6 +721,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) { Index: target-mips/op_helper_mem.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/op_helper_mem.c,v retrieving revision 1.1 diff -u -p -r1.1 op_helper_mem.c --- target-mips/op_helper_mem.c 2 Jul 2005 14:57:14 -0000 1.1 +++ target-mips/op_helper_mem.c 4 Dec 2005 21:15:44 -0000 @@ -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; } Index: target-mips/op_mem.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/op_mem.c,v retrieving revision 1.1 diff -u -p -r1.1 op_mem.c --- target-mips/op_mem.c 2 Jul 2005 14:57:14 -0000 1.1 +++ target-mips/op_mem.c 4 Dec 2005 21:15:44 -0000 @@ -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(); } Index: target-mips/translate.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-mips/translate.c,v retrieving revision 1.10 diff -u -p -r1.10 translate.c --- target-mips/translate.c 26 Nov 2005 18:47:06 -0000 1.10 +++ target-mips/translate.c 4 Dec 2005 21:15:44 -0000 @@ -338,17 +338,25 @@ static inline void save_cpu_state (Disas } } -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 (DisasCon 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 (DisasCon 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 (DisasCon 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, 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, 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 *ct 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 *ct 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 *ct 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 *ct 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 *ct break; case 0x3F: /* HACK */ break; + + /* Floating point. */ + case 0x31: /* LWC1 */ + case 0x35: /* LDC1 */ + case 0x39: /* SWC1 */ + case 0x3D: /* SDC1 */ + case 0x11: /* CP1 opcode */ #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 */ +#else + generate_exception_err(ctx, EXCP_CpU, 1); #endif - case 0x11: /* CP1 opcode */ - /* Not implemented */ - /* XXX: not correct */ + 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 *ct #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 (CPUS 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 (CPUS #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;
_______________________________________________ Qemu-devel mailing list Qemu-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/qemu-devel