Commit 6af0bf9c7c3ab9ddbf74a3bf34e067761eb43c3d

Authored by bellard
1 parent 6643d27e

MIPS target (Jocelyn Mayer)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1464 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -72,6 +72,10 @@ ifeq ($(ARCH), ppc)
72 72 PROGS+=$(QEMU_SYSTEM)
73 73 endif
74 74  
  75 +endif # TARGET_ARCH = ppc
  76 +
  77 +ifeq ($(TARGET_ARCH), mips)
  78 +
75 79 ifeq ($(ARCH), i386)
76 80 ifdef CONFIG_SOFTMMU
77 81 PROGS+=$(QEMU_SYSTEM)
... ... @@ -84,7 +88,7 @@ PROGS+=$(QEMU_SYSTEM)
84 88 endif
85 89 endif # ARCH = x86_64
86 90  
87   -endif # TARGET_ARCH = ppc
  91 +endif # TARGET_ARCH = mips
88 92  
89 93 ifeq ($(TARGET_ARCH), sparc)
90 94  
... ... @@ -263,6 +267,10 @@ ifeq ($(TARGET_ARCH), ppc)
263 267 LIBOBJS+= op_helper.o helper.o
264 268 endif
265 269  
  270 +ifeq ($(TARGET_ARCH), mips)
  271 +LIBOBJS+= op_helper.o helper.o
  272 +endif
  273 +
266 274 ifeq ($(TARGET_BASE_ARCH), sparc)
267 275 LIBOBJS+= op_helper.o helper.o
268 276 endif
... ... @@ -288,6 +296,9 @@ endif
288 296 ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
289 297 LIBOBJS+=ppc-dis.o
290 298 endif
  299 +ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
  300 +LIBOBJS+=mips-dis.o
  301 +endif
291 302 ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
292 303 LIBOBJS+=sparc-dis.o
293 304 endif
... ... @@ -348,6 +359,10 @@ VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
348 359 VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
349 360 VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
350 361 endif
  362 +ifeq ($(TARGET_ARCH), mips)
  363 +VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o #ide.o ne2000.o pckbd.o
  364 +VL_OBJS+= #i8259.o i8254.o fdc.o m48t59.o
  365 +endif
351 366 ifeq ($(TARGET_BASE_ARCH), sparc)
352 367 ifeq ($(TARGET_ARCH), sparc64)
353 368 VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o
... ... @@ -455,6 +470,11 @@ op.o: op.c op_template.h op_mem.h
455 470 op_helper.o: op_helper_mem.h
456 471 endif
457 472  
  473 +ifeq ($(TARGET_ARCH), mips)
  474 +op.o: op.c op_template.c op_mem.c
  475 +op_helper.o: op_helper_mem.c
  476 +endif
  477 +
458 478 mixeng.o: mixeng.c mixeng.h mixeng_template.h
459 479  
460 480 %.o: %.c
... ...
cpu-all.h
... ... @@ -617,6 +617,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
617 617 #define cpu_gen_code cpu_ppc_gen_code
618 618 #define cpu_signal_handler cpu_ppc_signal_handler
619 619  
  620 +#elif defined(TARGET_MIPS)
  621 +#define CPUState CPUMIPSState
  622 +#define cpu_init cpu_mips_init
  623 +#define cpu_exec cpu_mips_exec
  624 +#define cpu_gen_code cpu_mips_gen_code
  625 +#define cpu_signal_handler cpu_mips_signal_handler
  626 +
620 627 #else
621 628  
622 629 #error unsupported target CPU
... ...
cpu-exec.c
... ... @@ -182,6 +182,7 @@ int cpu_exec(CPUState *env1)
182 182 saved_regwptr = REGWPTR;
183 183 #endif
184 184 #elif defined(TARGET_PPC)
  185 +#elif defined(TARGET_MIPS)
185 186 #else
186 187 #error unsupported target CPU
187 188 #endif
... ... @@ -220,6 +221,8 @@ int cpu_exec(CPUState *env1)
220 221 env->exception_next_eip, 0);
221 222 #elif defined(TARGET_PPC)
222 223 do_interrupt(env);
  224 +#elif defined(TARGET_MIPS)
  225 + do_interrupt(env);
223 226 #elif defined(TARGET_SPARC)
224 227 do_interrupt(env->exception_index);
225 228 #endif
... ... @@ -301,6 +304,19 @@ int cpu_exec(CPUState *env1)
301 304 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
302 305 }
303 306 }
  307 +#elif defined(TARGET_MIPS)
  308 + if ((interrupt_request & CPU_INTERRUPT_HARD) &&
  309 + (env->CP0_Status & (1 << CP0St_IE)) &&
  310 + (env->CP0_Cause & 0x0000FC00) &&
  311 + !(env->hflags & MIPS_HFLAG_EXL) &&
  312 + !(env->hflags & MIPS_HFLAG_ERL) &&
  313 + !(env->hflags & MIPS_HFLAG_DM)) {
  314 + /* Raise it */
  315 + env->exception_index = EXCP_EXT_INTERRUPT;
  316 + env->error_code = 0;
  317 + do_interrupt(env);
  318 + env->interrupt_request &= ~CPU_INTERRUPT_HARD;
  319 + }
304 320 #elif defined(TARGET_SPARC)
305 321 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
306 322 (env->psret != 0)) {
... ... @@ -376,6 +392,8 @@ int cpu_exec(CPUState *env1)
376 392 cpu_dump_state(env, logfile, fprintf, 0);
377 393 #elif defined(TARGET_PPC)
378 394 cpu_dump_state(env, logfile, fprintf, 0);
  395 +#elif defined(TARGET_MIPS)
  396 + cpu_dump_state(env, logfile, fprintf, 0);
379 397 #else
380 398 #error unsupported target CPU
381 399 #endif
... ... @@ -407,6 +425,10 @@ int cpu_exec(CPUState *env1)
407 425 (msr_se << MSR_SE) | (msr_le << MSR_LE);
408 426 cs_base = 0;
409 427 pc = env->nip;
  428 +#elif defined(TARGET_MIPS)
  429 + flags = env->hflags & MIPS_HFLAGS_TMASK;
  430 + cs_base = NULL;
  431 + pc = env->PC;
410 432 #else
411 433 #error unsupported CPU
412 434 #endif
... ... @@ -684,6 +706,7 @@ int cpu_exec(CPUState *env1)
684 706 REGWPTR = saved_regwptr;
685 707 #endif
686 708 #elif defined(TARGET_PPC)
  709 +#elif defined(TARGET_MIPS)
687 710 #else
688 711 #error unsupported target CPU
689 712 #endif
... ... @@ -935,6 +958,57 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
935 958 /* never comes here */
936 959 return 1;
937 960 }
  961 +
  962 +#elif defined (TARGET_MIPS)
  963 +static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
  964 + int is_write, sigset_t *old_set,
  965 + void *puc)
  966 +{
  967 + TranslationBlock *tb;
  968 + int ret;
  969 +
  970 + if (cpu_single_env)
  971 + env = cpu_single_env; /* XXX: find a correct solution for multithread */
  972 +#if defined(DEBUG_SIGNAL)
  973 + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
  974 + pc, address, is_write, *(unsigned long *)old_set);
  975 +#endif
  976 + /* XXX: locking issue */
  977 + if (is_write && page_unprotect(address, pc, puc)) {
  978 + return 1;
  979 + }
  980 +
  981 + /* see if it is an MMU fault */
  982 + ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
  983 + if (ret < 0)
  984 + return 0; /* not an MMU fault */
  985 + if (ret == 0)
  986 + return 1; /* the MMU fault was handled without causing real CPU fault */
  987 +
  988 + /* now we have a real cpu fault */
  989 + tb = tb_find_pc(pc);
  990 + if (tb) {
  991 + /* the PC is inside the translated code. It means that we have
  992 + a virtual CPU fault */
  993 + cpu_restore_state(tb, env, pc, puc);
  994 + }
  995 + if (ret == 1) {
  996 +#if 0
  997 + printf("PF exception: NIP=0x%08x error=0x%x %p\n",
  998 + env->nip, env->error_code, tb);
  999 +#endif
  1000 + /* we restore the process signal mask as the sigreturn should
  1001 + do it (XXX: use sigsetjmp) */
  1002 + sigprocmask(SIG_SETMASK, old_set, NULL);
  1003 + do_raise_exception_err(env->exception_index, env->error_code);
  1004 + } else {
  1005 + /* activate soft MMU for this block */
  1006 + cpu_resume_from_signal(env, puc);
  1007 + }
  1008 + /* never comes here */
  1009 + return 1;
  1010 +}
  1011 +
938 1012 #else
939 1013 #error unsupported target CPU
940 1014 #endif
... ...
dis-asm.h
... ... @@ -404,6 +404,8 @@ extern int generic_symbol_at_address
404 404  
405 405 bfd_vma bfd_getl32 (const bfd_byte *addr);
406 406 bfd_vma bfd_getb32 (const bfd_byte *addr);
  407 +bfd_vma bfd_getl16 (const bfd_byte *addr);
  408 +bfd_vma bfd_getb16 (const bfd_byte *addr);
407 409 typedef enum bfd_boolean {false, true} boolean;
408 410  
409 411 #endif /* ! defined (DIS_ASM_H) */
... ...
... ... @@ -108,6 +108,24 @@ bfd_vma bfd_getb32 (const bfd_byte *addr)
108 108 return (bfd_vma) v;
109 109 }
110 110  
  111 +bfd_vma bfd_getl16 (const bfd_byte *addr)
  112 +{
  113 + unsigned long v;
  114 +
  115 + v = (unsigned long) addr[0];
  116 + v |= (unsigned long) addr[1] << 8;
  117 + return (bfd_vma) v;
  118 +}
  119 +
  120 +bfd_vma bfd_getb16 (const bfd_byte *addr)
  121 +{
  122 + unsigned long v;
  123 +
  124 + v = (unsigned long) addr[0] << 24;
  125 + v |= (unsigned long) addr[1] << 16;
  126 + return (bfd_vma) v;
  127 +}
  128 +
111 129 #ifdef TARGET_ARM
112 130 static int
113 131 print_insn_thumb1(bfd_vma pc, disassemble_info *info)
... ... @@ -162,6 +180,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
162 180 if (cpu_single_env->msr[MSR_LE])
163 181 disasm_info.endian = BFD_ENDIAN_LITTLE;
164 182 print_insn = print_insn_ppc;
  183 +#elif defined(TARGET_MIPS)
  184 + print_insn = print_insn_big_mips;
165 185 #else
166 186 fprintf(out, "0x" TARGET_FMT_lx
167 187 ": Asm output not supported on this arch\n", code);
... ... @@ -222,6 +242,10 @@ void disas(FILE *out, void *code, unsigned long size)
222 242 print_insn = print_insn_sparc;
223 243 #elif defined(__arm__)
224 244 print_insn = print_insn_arm;
  245 +#elif defined(__MIPSEB__)
  246 + print_insn = print_insn_big_mips;
  247 +#elif defined(__MIPSEL__)
  248 + print_insn = print_insn_little_mips;
225 249 #else
226 250 fprintf(out, "0x%lx: Asm output not supported on this arch\n",
227 251 (long) code);
... ... @@ -332,6 +356,8 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
332 356 print_insn = print_insn_sparc;
333 357 #elif defined(TARGET_PPC)
334 358 print_insn = print_insn_ppc;
  359 +#elif defined(TARGET_MIPS)
  360 + print_insn = print_insn_big_mips;
335 361 #else
336 362 term_printf("0x" TARGET_FMT_lx
337 363 ": Asm output not supported on this arch\n", pc);
... ...
... ... @@ -31,11 +31,29 @@ typedef int64_t Elf64_Sxword;
31 31 #define PT_LOPROC 0x70000000
32 32 #define PT_HIPROC 0x7fffffff
33 33 #define PT_MIPS_REGINFO 0x70000000
  34 +#define PT_MIPS_OPTIONS 0x70000001
34 35  
35 36 /* Flags in the e_flags field of the header */
  37 +/* MIPS architecture level. */
  38 +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
  39 +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
  40 +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
  41 +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
  42 +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
  43 +#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
  44 +#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
  45 +
  46 +/* The ABI of a file. */
  47 +#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */
  48 +#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */
  49 +
36 50 #define EF_MIPS_NOREORDER 0x00000001
37 51 #define EF_MIPS_PIC 0x00000002
38 52 #define EF_MIPS_CPIC 0x00000004
  53 +#define EF_MIPS_ABI2 0x00000020
  54 +#define EF_MIPS_OPTIONS_FIRST 0x00000080
  55 +#define EF_MIPS_32BITMODE 0x00000100
  56 +#define EF_MIPS_ABI 0x0000f000
39 57 #define EF_MIPS_ARCH 0xf0000000
40 58  
41 59 /* These constants define the different elf file types */
... ...
exec-all.h
... ... @@ -582,6 +582,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
582 582 is_user = ((env->hflags & HF_CPL_MASK) == 3);
583 583 #elif defined (TARGET_PPC)
584 584 is_user = msr_pr;
  585 +#elif defined (TARGET_MIPS)
  586 + is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
585 587 #elif defined (TARGET_SPARC)
586 588 is_user = (env->psrs == 0);
587 589 #else
... ...
hw/mips_r4k.c 0 โ†’ 100644
  1 +#include "vl.h"
  2 +
  3 +#define DEBUG_IRQ_COUNT
  4 +
  5 +#define BIOS_FILENAME "mips_bios.bin"
  6 +//#define BIOS_FILENAME "system.bin"
  7 +#define KERNEL_LOAD_ADDR 0x80010000
  8 +#define INITRD_LOAD_ADDR 0x80800000
  9 +
  10 +/* MIPS R4K IRQ controler */
  11 +#if defined(DEBUG_IRQ_COUNT)
  12 +static uint64_t irq_count[16];
  13 +#endif
  14 +
  15 +extern FILE *logfile;
  16 +
  17 +void mips_set_irq (int n_IRQ, int level)
  18 +{
  19 + uint32_t mask;
  20 +
  21 + if (n_IRQ < 0 || n_IRQ >= 8)
  22 + return;
  23 + mask = 0x100 << n_IRQ;
  24 + if (level != 0) {
  25 +#if 1
  26 + if (logfile) {
  27 + fprintf(logfile, "%s n %d l %d mask %08x %08x\n",
  28 + __func__, n_IRQ, level, mask, cpu_single_env->CP0_Status);
  29 + }
  30 +#endif
  31 + cpu_single_env->CP0_Cause |= mask;
  32 + if ((cpu_single_env->CP0_Status & 0x00000001) &&
  33 + (cpu_single_env->CP0_Status & mask)) {
  34 +#if defined(DEBUG_IRQ_COUNT)
  35 + irq_count[n_IRQ]++;
  36 +#endif
  37 +#if 1
  38 + if (logfile)
  39 + fprintf(logfile, "%s raise IRQ\n", __func__);
  40 +#endif
  41 + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
  42 + }
  43 + } else {
  44 + cpu_single_env->CP0_Cause &= ~mask;
  45 + }
  46 +}
  47 +
  48 +void pic_set_irq (int n_IRQ, int level)
  49 +{
  50 + mips_set_irq(n_IRQ + 2, level);
  51 +}
  52 +
  53 +void pic_info (void)
  54 +{
  55 + term_printf("IRQ asserted: %02x mask: %02x\n",
  56 + (cpu_single_env->CP0_Cause >> 8) & 0xFF,
  57 + (cpu_single_env->CP0_Status >> 8) & 0xFF);
  58 +}
  59 +
  60 +void irq_info (void)
  61 +{
  62 +#if !defined(DEBUG_IRQ_COUNT)
  63 + term_printf("irq statistic code not compiled.\n");
  64 +#else
  65 + int i;
  66 + int64_t count;
  67 +
  68 + term_printf("IRQ statistics:\n");
  69 + for (i = 0; i < 8; i++) {
  70 + count = irq_count[i];
  71 + if (count > 0)
  72 + term_printf("%2d: %lld\n", i, count);
  73 + }
  74 +#endif
  75 +}
  76 +
  77 +void cpu_mips_irqctrl_init (void)
  78 +{
  79 +}
  80 +
  81 +/* MIPS R4K timer */
  82 +uint32_t cpu_mips_get_random (CPUState *env)
  83 +{
  84 + uint64_t now = qemu_get_clock(vm_clock);
  85 +
  86 + return (uint32_t)now & 0x0000000F;
  87 +}
  88 +
  89 +uint32_t cpu_mips_get_count (CPUState *env)
  90 +{
  91 + return env->CP0_Count +
  92 + (uint32_t)muldiv64(qemu_get_clock(vm_clock),
  93 + 100 * 1000 * 1000, ticks_per_sec);
  94 +}
  95 +
  96 +static void cpu_mips_update_count (CPUState *env, uint32_t count,
  97 + uint32_t compare)
  98 +{
  99 + uint64_t now, next;
  100 + uint32_t tmp;
  101 +
  102 + tmp = count;
  103 + if (count == compare)
  104 + tmp++;
  105 + now = qemu_get_clock(vm_clock);
  106 + next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
  107 + if (next == now)
  108 + next++;
  109 +#if 1
  110 + if (logfile) {
  111 + fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
  112 + __func__, now, count, compare, next - now);
  113 + }
  114 +#endif
  115 + /* Store new count and compare registers */
  116 + env->CP0_Compare = compare;
  117 + env->CP0_Count =
  118 + count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
  119 + /* Adjust timer */
  120 + qemu_mod_timer(env->timer, next);
  121 +}
  122 +
  123 +void cpu_mips_store_count (CPUState *env, uint32_t value)
  124 +{
  125 + cpu_mips_update_count(env, value, env->CP0_Compare);
  126 +}
  127 +
  128 +void cpu_mips_store_compare (CPUState *env, uint32_t value)
  129 +{
  130 + cpu_mips_update_count(env, cpu_mips_get_count(env), value);
  131 + pic_set_irq(5, 0);
  132 +}
  133 +
  134 +static void mips_timer_cb (void *opaque)
  135 +{
  136 + CPUState *env;
  137 +
  138 + env = opaque;
  139 +#if 1
  140 + if (logfile) {
  141 + fprintf(logfile, "%s\n", __func__);
  142 + }
  143 +#endif
  144 + cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
  145 + pic_set_irq(5, 1);
  146 +}
  147 +
  148 +void cpu_mips_clock_init (CPUState *env)
  149 +{
  150 + env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
  151 + env->CP0_Compare = 0;
  152 + cpu_mips_update_count(env, 1, 0);
  153 +}
  154 +
  155 +static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
  156 +{
  157 + if (logfile)
  158 + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
  159 + cpu_outb(NULL, addr & 0xffff, value);
  160 +}
  161 +
  162 +static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
  163 +{
  164 + uint32_t ret = cpu_inb(NULL, addr & 0xffff);
  165 + if (logfile)
  166 + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
  167 + return ret;
  168 +}
  169 +
  170 +static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
  171 +{
  172 + if (logfile)
  173 + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
  174 +#ifdef TARGET_WORDS_BIGENDIAN
  175 + value = bswap16(value);
  176 +#endif
  177 + cpu_outw(NULL, addr & 0xffff, value);
  178 +}
  179 +
  180 +static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
  181 +{
  182 + uint32_t ret = cpu_inw(NULL, addr & 0xffff);
  183 +#ifdef TARGET_WORDS_BIGENDIAN
  184 + ret = bswap16(ret);
  185 +#endif
  186 + if (logfile)
  187 + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
  188 + return ret;
  189 +}
  190 +
  191 +static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
  192 +{
  193 + if (logfile)
  194 + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
  195 +#ifdef TARGET_WORDS_BIGENDIAN
  196 + value = bswap32(value);
  197 +#endif
  198 + cpu_outl(NULL, addr & 0xffff, value);
  199 +}
  200 +
  201 +static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
  202 +{
  203 + uint32_t ret = cpu_inl(NULL, addr & 0xffff);
  204 +
  205 +#ifdef TARGET_WORDS_BIGENDIAN
  206 + ret = bswap32(ret);
  207 +#endif
  208 + if (logfile)
  209 + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
  210 + return ret;
  211 +}
  212 +
  213 +CPUWriteMemoryFunc *io_write[] = {
  214 + &io_writeb,
  215 + &io_writew,
  216 + &io_writel,
  217 +};
  218 +
  219 +CPUReadMemoryFunc *io_read[] = {
  220 + &io_readb,
  221 + &io_readw,
  222 + &io_readl,
  223 +};
  224 +
  225 +void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
  226 + DisplayState *ds, const char **fd_filename, int snapshot,
  227 + const char *kernel_filename, const char *kernel_cmdline,
  228 + const char *initrd_filename)
  229 +{
  230 + char buf[1024];
  231 + target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
  232 + unsigned long bios_offset;
  233 + int io_memory;
  234 + int linux_boot;
  235 + int ret;
  236 +
  237 + printf("%s: start\n", __func__);
  238 + linux_boot = (kernel_filename != NULL);
  239 + /* allocate RAM */
  240 + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
  241 + bios_offset = ram_size + vga_ram_size;
  242 + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
  243 + printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
  244 + ret = load_image(buf, phys_ram_base + bios_offset);
  245 + if (ret != BIOS_SIZE) {
  246 + fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
  247 + exit(1);
  248 + }
  249 + cpu_register_physical_memory((uint32_t)(0x1fc00000),
  250 + BIOS_SIZE, bios_offset | IO_MEM_ROM);
  251 +#if 0
  252 + memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
  253 + cpu_single_env->PC = 0x80010004;
  254 +#else
  255 + cpu_single_env->PC = 0xBFC00004;
  256 +#endif
  257 + if (linux_boot) {
  258 + kernel_base = KERNEL_LOAD_ADDR;
  259 + /* now we can load the kernel */
  260 + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
  261 + if (kernel_size < 0) {
  262 + fprintf(stderr, "qemu: could not load kernel '%s'\n",
  263 + kernel_filename);
  264 + exit(1);
  265 + }
  266 + /* load initrd */
  267 + if (initrd_filename) {
  268 + initrd_base = INITRD_LOAD_ADDR;
  269 + initrd_size = load_image(initrd_filename,
  270 + phys_ram_base + initrd_base);
  271 + if (initrd_size < 0) {
  272 + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
  273 + initrd_filename);
  274 + exit(1);
  275 + }
  276 + } else {
  277 + initrd_base = 0;
  278 + initrd_size = 0;
  279 + }
  280 + cpu_single_env->PC = KERNEL_LOAD_ADDR;
  281 + } else {
  282 + kernel_base = 0;
  283 + kernel_size = 0;
  284 + initrd_base = 0;
  285 + initrd_size = 0;
  286 + }
  287 + /* XXX: should not be ! */
  288 + printf("%s: init VGA\n", __func__);
  289 + vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
  290 + vga_ram_size);
  291 +
  292 +
  293 + /* Init internal devices */
  294 + cpu_mips_clock_init(cpu_single_env);
  295 + cpu_mips_irqctrl_init();
  296 +
  297 + isa_mem_base = 0x78000000;
  298 + /* Register 64 KB of ISA IO space at random address */
  299 + io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
  300 + cpu_register_physical_memory(0x70000000, 0x00010000, io_memory);
  301 + serial_init(0x3f8, 4, serial_hds[0]);
  302 + printf("%s: done\n", __func__);
  303 +}
  304 +
  305 +QEMUMachine mips_machine = {
  306 + "mips",
  307 + "mips r4k platform",
  308 + mips_r4k_init,
  309 +};
... ...
softmmu_header.h
... ... @@ -55,6 +55,8 @@
55 55 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
56 56 #elif defined (TARGET_PPC)
57 57 #define CPU_MEM_INDEX (msr_pr)
  58 +#elif defined (TARGET_MIPS)
  59 +#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
58 60 #elif defined (TARGET_SPARC)
59 61 #define CPU_MEM_INDEX ((env->psrs) == 0)
60 62 #endif
... ... @@ -66,6 +68,8 @@
66 68 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
67 69 #elif defined (TARGET_PPC)
68 70 #define CPU_MEM_INDEX (msr_pr)
  71 +#elif defined (TARGET_MIPS)
  72 +#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
69 73 #elif defined (TARGET_SPARC)
70 74 #define CPU_MEM_INDEX ((env->psrs) == 0)
71 75 #endif
... ...
target-mips/cpu.h 0 โ†’ 100644
  1 +#if !defined (__MIPS_CPU_H__)
  2 +#define __MIPS_CPU_H__
  3 +
  4 +#include "mips-defs.h"
  5 +#include "cpu-defs.h"
  6 +#include "config.h"
  7 +#include "softfloat.h"
  8 +
  9 +typedef union fpr_t fpr_t;
  10 +union fpr_t {
  11 + double d;
  12 + float f;
  13 + uint32_t u[2];
  14 +};
  15 +
  16 +#if defined(MIPS_USES_R4K_TLB)
  17 +typedef struct tlb_t tlb_t;
  18 +struct tlb_t {
  19 + target_ulong VPN;
  20 + target_ulong end;
  21 + uint8_t ASID;
  22 + uint8_t G;
  23 + uint8_t C[2];
  24 + uint8_t V[2];
  25 + uint8_t D[2];
  26 + target_ulong PFN[2];
  27 +};
  28 +#endif
  29 +
  30 +typedef struct CPUMIPSState CPUMIPSState;
  31 +struct CPUMIPSState {
  32 + /* General integer registers */
  33 + target_ulong gpr[32];
  34 + /* Special registers */
  35 + target_ulong PC;
  36 + uint32_t HI, LO;
  37 + uint32_t DCR; /* ? */
  38 +#if defined(MIPS_USES_FPU)
  39 + /* Floating point registers */
  40 + fpr_t fpr[16];
  41 + /* Floating point special purpose registers */
  42 + uint32_t fcr0;
  43 + uint32_t fcr25;
  44 + uint32_t fcr26;
  45 + uint32_t fcr28;
  46 + uint32_t fcsr;
  47 +#endif
  48 +#if defined(MIPS_USES_R4K_TLB)
  49 + tlb_t tlb[16];
  50 +#endif
  51 + uint32_t CP0_index;
  52 + uint32_t CP0_random;
  53 + uint32_t CP0_EntryLo0;
  54 + uint32_t CP0_EntryLo1;
  55 + uint32_t CP0_Context;
  56 + uint32_t CP0_PageMask;
  57 + uint32_t CP0_Wired;
  58 + uint32_t CP0_BadVAddr;
  59 + uint32_t CP0_Count;
  60 + uint32_t CP0_EntryHi;
  61 + uint32_t CP0_Compare;
  62 + uint32_t CP0_Status;
  63 +#define CP0St_CU3 31
  64 +#define CP0St_CU2 30
  65 +#define CP0St_CU1 29
  66 +#define CP0St_CU0 28
  67 +#define CP0St_RP 27
  68 +#define CP0St_RE 25
  69 +#define CP0St_BEV 22
  70 +#define CP0St_TS 21
  71 +#define CP0St_SR 20
  72 +#define CP0St_NMI 19
  73 +#define CP0St_IM 8
  74 +#define CP0St_UM 4
  75 +#define CP0St_ERL 2
  76 +#define CP0St_EXL 1
  77 +#define CP0St_IE 0
  78 + uint32_t CP0_Cause;
  79 +#define CP0Ca_IV 23
  80 + uint32_t CP0_EPC;
  81 + uint32_t CP0_PRid;
  82 + uint32_t CP0_Config0;
  83 +#define CP0C0_M 31
  84 +#define CP0C0_K23 28
  85 +#define CP0C0_KU 25
  86 +#define CP0C0_MDU 20
  87 +#define CP0C0_MM 17
  88 +#define CP0C0_BM 16
  89 +#define CP0C0_BE 15
  90 +#define CP0C0_AT 13
  91 +#define CP0C0_AR 10
  92 +#define CP0C0_MT 7
  93 +#define CP0C0_K0 0
  94 + uint32_t CP0_Config1;
  95 +#define CP0C1_MMU 25
  96 +#define CP0C1_IS 22
  97 +#define CP0C1_IL 19
  98 +#define CP0C1_IA 16
  99 +#define CP0C1_DS 13
  100 +#define CP0C1_DL 10
  101 +#define CP0C1_DA 7
  102 +#define CP0C1_PC 4
  103 +#define CP0C1_WR 3
  104 +#define CP0C1_CA 2
  105 +#define CP0C1_EP 1
  106 +#define CP0C1_FP 0
  107 + uint32_t CP0_LLAddr;
  108 + uint32_t CP0_WatchLo;
  109 + uint32_t CP0_WatchHi;
  110 + uint32_t CP0_Debug;
  111 +#define CPDB_DBD 31
  112 +#define CP0DB_DM 30
  113 +#define CP0DB_LSNM 28
  114 +#define CP0DB_Doze 27
  115 +#define CP0DB_Halt 26
  116 +#define CP0DB_CNT 25
  117 +#define CP0DB_IBEP 24
  118 +#define CP0DB_DBEP 21
  119 +#define CP0DB_IEXI 20
  120 +#define CP0DB_VER 15
  121 +#define CP0DB_DEC 10
  122 +#define CP0DB_SSt 8
  123 +#define CP0DB_DINT 5
  124 +#define CP0DB_DIB 4
  125 +#define CP0DB_DDBS 3
  126 +#define CP0DB_DDBL 2
  127 +#define CP0DB_DBp 1
  128 +#define CP0DB_DSS 0
  129 + uint32_t CP0_DEPC;
  130 + uint32_t CP0_TagLo;
  131 + uint32_t CP0_DataLo;
  132 + uint32_t CP0_ErrorEPC;
  133 + uint32_t CP0_DESAVE;
  134 + /* Qemu */
  135 +#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
  136 + double ft0, ft1, ft2;
  137 +#endif
  138 + struct QEMUTimer *timer; /* Internal timer */
  139 + int interrupt_request;
  140 + jmp_buf jmp_env;
  141 + int exception_index;
  142 + int error_code;
  143 + int user_mode_only; /* user mode only simulation */
  144 + uint32_t hflags; /* CPU State */
  145 + /* TMASK defines different execution modes */
  146 +#define MIPS_HFLAGS_TMASK 0x00FF
  147 +#define MIPS_HFLAG_MODE 0x001F /* execution modes */
  148 +#define MIPS_HFLAG_UM 0x0001 /* user mode */
  149 +#define MIPS_HFLAG_ERL 0x0002 /* Error mode */
  150 +#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */
  151 +#define MIPS_HFLAG_DM 0x0008 /* Debug mode */
  152 +#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */
  153 +#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */
  154 +#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */
  155 + /* Those flags keep the branch state if the translation is interrupted
  156 + * between the branch instruction and the delay slot
  157 + */
  158 +#define MIPS_HFLAG_BMASK 0x0F00
  159 +#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */
  160 +#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */
  161 +#define MIPS_HFLAG_BL 0x0400 /* Likely branch */
  162 +#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */
  163 + target_ulong btarget; /* Jump / branch target */
  164 + int bcond; /* Branch condition (if needed) */
  165 + struct TranslationBlock *current_tb; /* currently executing TB */
  166 + /* soft mmu support */
  167 + /* in order to avoid passing too many arguments to the memory
  168 + write helpers, we store some rarely used information in the CPU
  169 + context) */
  170 + target_ulong mem_write_pc; /* host pc at which the memory was
  171 + written */
  172 + unsigned long mem_write_vaddr; /* target virtual addr at which the
  173 + memory was written */
  174 + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
  175 + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
  176 + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
  177 + /* ice debug support */
  178 + target_ulong breakpoints[MAX_BREAKPOINTS];
  179 + int nb_breakpoints;
  180 + int singlestep_enabled; /* XXX: should use CPU single step mode instead */
  181 + /* user data */
  182 + void *opaque;
  183 +};
  184 +
  185 +#include "cpu-all.h"
  186 +
  187 +/* Memory access type :
  188 + * may be needed for precise access rights control and precise exceptions.
  189 + */
  190 +enum {
  191 + /* 1 bit to define user level / supervisor access */
  192 + ACCESS_USER = 0x00,
  193 + ACCESS_SUPER = 0x01,
  194 + /* 1 bit to indicate direction */
  195 + ACCESS_STORE = 0x02,
  196 + /* Type of instruction that generated the access */
  197 + ACCESS_CODE = 0x10, /* Code fetch access */
  198 + ACCESS_INT = 0x20, /* Integer load/store access */
  199 + ACCESS_FLOAT = 0x30, /* floating point load/store access */
  200 +};
  201 +
  202 +/* Exceptions */
  203 +enum {
  204 + EXCP_NONE = -1,
  205 + EXCP_RESET = 0,
  206 + EXCP_SRESET,
  207 + EXCP_DSS,
  208 + EXCP_DINT,
  209 + EXCP_NMI,
  210 + EXCP_MCHECK,
  211 + EXCP_EXT_INTERRUPT,
  212 + EXCP_DFWATCH,
  213 + EXCP_DIB, /* 8 */
  214 + EXCP_IWATCH,
  215 + EXCP_AdEL,
  216 + EXCP_AdES,
  217 + EXCP_TLBF,
  218 + EXCP_IBE,
  219 + EXCP_DBp,
  220 + EXCP_SYSCALL,
  221 + EXCP_BREAK,
  222 + EXCP_CpU, /* 16 */
  223 + EXCP_RI,
  224 + EXCP_OVERFLOW,
  225 + EXCP_TRAP,
  226 + EXCP_DDBS,
  227 + EXCP_DWATCH,
  228 + EXCP_LAE, /* 22 */
  229 + EXCP_SAE,
  230 + EXCP_LTLBL,
  231 + EXCP_TLBL,
  232 + EXCP_TLBS,
  233 + EXCP_DBE,
  234 + EXCP_DDBL,
  235 + EXCP_MTCP0 = 0x104, /* mtmsr instruction: */
  236 + /* may change privilege level */
  237 + EXCP_BRANCH = 0x108, /* branch instruction */
  238 + EXCP_ERET = 0x10C, /* return from interrupt */
  239 + EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */
  240 + EXCP_FLUSH = 0x109,
  241 +};
  242 +
  243 +/* MIPS opcodes */
  244 +#define EXT_SPECIAL 0x100
  245 +#define EXT_SPECIAL2 0x200
  246 +#define EXT_REGIMM 0x300
  247 +#define EXT_CP0 0x400
  248 +#define EXT_CP1 0x500
  249 +#define EXT_CP2 0x600
  250 +#define EXT_CP3 0x700
  251 +
  252 +enum {
  253 + /* indirect opcode tables */
  254 + OPC_SPECIAL = 0x00,
  255 + OPC_BREGIMM = 0x01,
  256 + OPC_CP0 = 0x10,
  257 + OPC_CP1 = 0x11,
  258 + OPC_CP2 = 0x12,
  259 + OPC_CP3 = 0x13,
  260 + OPC_SPECIAL2 = 0x1C,
  261 + /* arithmetic with immediate */
  262 + OPC_ADDI = 0x08,
  263 + OPC_ADDIU = 0x09,
  264 + OPC_SLTI = 0x0A,
  265 + OPC_SLTIU = 0x0B,
  266 + OPC_ANDI = 0x0C,
  267 + OPC_ORI = 0x0D,
  268 + OPC_XORI = 0x0E,
  269 + OPC_LUI = 0x0F,
  270 + /* Jump and branches */
  271 + OPC_J = 0x02,
  272 + OPC_JAL = 0x03,
  273 + OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */
  274 + OPC_BEQL = 0x14,
  275 + OPC_BNE = 0x05,
  276 + OPC_BNEL = 0x15,
  277 + OPC_BLEZ = 0x06,
  278 + OPC_BLEZL = 0x16,
  279 + OPC_BGTZ = 0x07,
  280 + OPC_BGTZL = 0x17,
  281 + OPC_JALX = 0x1D, /* MIPS 16 only */
  282 + /* Load and stores */
  283 + OPC_LB = 0x20,
  284 + OPC_LH = 0x21,
  285 + OPC_LWL = 0x22,
  286 + OPC_LW = 0x23,
  287 + OPC_LBU = 0x24,
  288 + OPC_LHU = 0x25,
  289 + OPC_LWR = 0x26,
  290 + OPC_SB = 0x28,
  291 + OPC_SH = 0x29,
  292 + OPC_SWL = 0x2A,
  293 + OPC_SW = 0x2B,
  294 + OPC_SWR = 0x2E,
  295 + OPC_LL = 0x30,
  296 + OPC_SC = 0x38,
  297 + /* Floating point load/store */
  298 + OPC_LWC1 = 0x31,
  299 + OPC_LWC2 = 0x32,
  300 + OPC_LDC1 = 0x35,
  301 + OPC_LDC2 = 0x36,
  302 + OPC_SWC1 = 0x39,
  303 + OPC_SWC2 = 0x3A,
  304 + OPC_SDC1 = 0x3D,
  305 + OPC_SDC2 = 0x3E,
  306 + /* Cache and prefetch */
  307 + OPC_CACHE = 0x2F,
  308 + OPC_PREF = 0x33,
  309 +};
  310 +
  311 +/* MIPS special opcodes */
  312 +enum {
  313 + /* Shifts */
  314 + OPC_SLL = 0x00 | EXT_SPECIAL,
  315 + /* NOP is SLL r0, r0, 0 */
  316 + /* SSNOP is SLL r0, r0, 1 */
  317 + OPC_SRL = 0x02 | EXT_SPECIAL,
  318 + OPC_SRA = 0x03 | EXT_SPECIAL,
  319 + OPC_SLLV = 0x04 | EXT_SPECIAL,
  320 + OPC_SRLV = 0x06 | EXT_SPECIAL,
  321 + OPC_SRAV = 0x07 | EXT_SPECIAL,
  322 + /* Multiplication / division */
  323 + OPC_MULT = 0x18 | EXT_SPECIAL,
  324 + OPC_MULTU = 0x19 | EXT_SPECIAL,
  325 + OPC_DIV = 0x1A | EXT_SPECIAL,
  326 + OPC_DIVU = 0x1B | EXT_SPECIAL,
  327 + /* 2 registers arithmetic / logic */
  328 + OPC_ADD = 0x20 | EXT_SPECIAL,
  329 + OPC_ADDU = 0x21 | EXT_SPECIAL,
  330 + OPC_SUB = 0x22 | EXT_SPECIAL,
  331 + OPC_SUBU = 0x23 | EXT_SPECIAL,
  332 + OPC_AND = 0x24 | EXT_SPECIAL,
  333 + OPC_OR = 0x25 | EXT_SPECIAL,
  334 + OPC_XOR = 0x26 | EXT_SPECIAL,
  335 + OPC_NOR = 0x27 | EXT_SPECIAL,
  336 + OPC_SLT = 0x2A | EXT_SPECIAL,
  337 + OPC_SLTU = 0x2B | EXT_SPECIAL,
  338 + /* Jumps */
  339 + OPC_JR = 0x08 | EXT_SPECIAL,
  340 + OPC_JALR = 0x09 | EXT_SPECIAL,
  341 + /* Traps */
  342 + OPC_TGE = 0x30 | EXT_SPECIAL,
  343 + OPC_TGEU = 0x31 | EXT_SPECIAL,
  344 + OPC_TLT = 0x32 | EXT_SPECIAL,
  345 + OPC_TLTU = 0x33 | EXT_SPECIAL,
  346 + OPC_TEQ = 0x34 | EXT_SPECIAL,
  347 + OPC_TNE = 0x36 | EXT_SPECIAL,
  348 + /* HI / LO registers load & stores */
  349 + OPC_MFHI = 0x10 | EXT_SPECIAL,
  350 + OPC_MTHI = 0x11 | EXT_SPECIAL,
  351 + OPC_MFLO = 0x12 | EXT_SPECIAL,
  352 + OPC_MTLO = 0x13 | EXT_SPECIAL,
  353 + /* Conditional moves */
  354 + OPC_MOVZ = 0x0A | EXT_SPECIAL,
  355 + OPC_MOVN = 0x0B | EXT_SPECIAL,
  356 +
  357 + OPC_MOVCI = 0x01 | EXT_SPECIAL,
  358 +
  359 + /* Special */
  360 + OPC_PMON = 0x05 | EXT_SPECIAL,
  361 + OPC_SYSCALL = 0x0C | EXT_SPECIAL,
  362 + OPC_BREAK = 0x0D | EXT_SPECIAL,
  363 + OPC_SYNC = 0x0F | EXT_SPECIAL,
  364 +};
  365 +
  366 +enum {
  367 + /* Mutiply & xxx operations */
  368 + OPC_MADD = 0x00 | EXT_SPECIAL2,
  369 + OPC_MADDU = 0x01 | EXT_SPECIAL2,
  370 + OPC_MUL = 0x02 | EXT_SPECIAL2,
  371 + OPC_MSUB = 0x04 | EXT_SPECIAL2,
  372 + OPC_MSUBU = 0x05 | EXT_SPECIAL2,
  373 + /* Misc */
  374 + OPC_CLZ = 0x20 | EXT_SPECIAL2,
  375 + OPC_CLO = 0x21 | EXT_SPECIAL2,
  376 + /* Special */
  377 + OPC_SDBBP = 0x3F | EXT_SPECIAL2,
  378 +};
  379 +
  380 +/* Branch REGIMM */
  381 +enum {
  382 + OPC_BLTZ = 0x00 | EXT_REGIMM,
  383 + OPC_BLTZL = 0x02 | EXT_REGIMM,
  384 + OPC_BGEZ = 0x01 | EXT_REGIMM,
  385 + OPC_BGEZL = 0x03 | EXT_REGIMM,
  386 + OPC_BLTZAL = 0x10 | EXT_REGIMM,
  387 + OPC_BLTZALL = 0x12 | EXT_REGIMM,
  388 + OPC_BGEZAL = 0x11 | EXT_REGIMM,
  389 + OPC_BGEZALL = 0x13 | EXT_REGIMM,
  390 + OPC_TGEI = 0x08 | EXT_REGIMM,
  391 + OPC_TGEIU = 0x09 | EXT_REGIMM,
  392 + OPC_TLTI = 0x0A | EXT_REGIMM,
  393 + OPC_TLTIU = 0x0B | EXT_REGIMM,
  394 + OPC_TEQI = 0x0C | EXT_REGIMM,
  395 + OPC_TNEI = 0x0E | EXT_REGIMM,
  396 +};
  397 +
  398 +enum {
  399 + /* Coprocessor 0 (MMU) */
  400 + OPC_MFC0 = 0x00 | EXT_CP0,
  401 + OPC_MTC0 = 0x04 | EXT_CP0,
  402 + OPC_TLBR = 0x01 | EXT_CP0,
  403 + OPC_TLBWI = 0x02 | EXT_CP0,
  404 + OPC_TLBWR = 0x06 | EXT_CP0,
  405 + OPC_TLBP = 0x08 | EXT_CP0,
  406 + OPC_ERET = 0x18 | EXT_CP0,
  407 + OPC_DERET = 0x1F | EXT_CP0,
  408 + OPC_WAIT = 0x20 | EXT_CP0,
  409 +};
  410 +
  411 +int cpu_mips_exec(CPUMIPSState *s);
  412 +CPUMIPSState *cpu_mips_init(void);
  413 +uint32_t cpu_mips_get_clock (void);
  414 +
  415 +#endif /* !defined (__MIPS_CPU_H__) */
... ...
target-mips/exec.h 0 โ†’ 100644
  1 +#if !defined(__QEMU_MIPS_EXEC_H__)
  2 +#define __QEMU_MIPS_EXEC_H__
  3 +
  4 +#define DEBUG_OP
  5 +
  6 +#include "mips-defs.h"
  7 +#include "dyngen-exec.h"
  8 +
  9 +register struct CPUMIPSState *env asm(AREG0);
  10 +
  11 +#if defined (USE_64BITS_REGS)
  12 +typedef int64_t host_int_t;
  13 +typedef uint64_t host_uint_t;
  14 +#else
  15 +typedef int32_t host_int_t;
  16 +typedef uint32_t host_uint_t;
  17 +#endif
  18 +
  19 +register host_uint_t T0 asm(AREG1);
  20 +register host_uint_t T1 asm(AREG2);
  21 +register host_uint_t T2 asm(AREG3);
  22 +register host_int_t Ts0 asm(AREG1);
  23 +register host_int_t Ts1 asm(AREG2);
  24 +register host_int_t Ts2 asm(AREG3);
  25 +
  26 +#define PARAM(n) ((uint32_t)PARAM##n)
  27 +#define SPARAM(n) ((int32_t)PARAM##n)
  28 +
  29 +#if defined (USE_HOST_FLOAT_REGS)
  30 +register double FT0 asm(FREG0);
  31 +register double FT1 asm(FREG1);
  32 +register double FT2 asm(FREG2);
  33 +register float FTS0 asm(FREG0);
  34 +register float FTS1 asm(FREG1);
  35 +register float FTS2 asm(FREG2);
  36 +#else
  37 +#define FT0 (env->ft0.d)
  38 +#define FT1 (env->ft1.d)
  39 +#define FT2 (env->ft2.d)
  40 +#define FTS0 (env->ft0.f)
  41 +#define FTS1 (env->ft1.f)
  42 +#define FTS2 (env->ft2.f)
  43 +#endif
  44 +
  45 +#if defined (DEBUG_OP)
  46 +#define RETURN() __asm__ __volatile__("nop");
  47 +#else
  48 +#define RETURN() __asm__ __volatile__("");
  49 +#endif
  50 +
  51 +#include "cpu.h"
  52 +#include "exec-all.h"
  53 +
  54 +#if !defined(CONFIG_USER_ONLY)
  55 +
  56 +#define ldul_user ldl_user
  57 +#define ldul_kernel ldl_kernel
  58 +
  59 +#define ACCESS_TYPE 0
  60 +#define MEMSUFFIX _kernel
  61 +#define DATA_SIZE 1
  62 +#include "softmmu_header.h"
  63 +
  64 +#define DATA_SIZE 2
  65 +#include "softmmu_header.h"
  66 +
  67 +#define DATA_SIZE 4
  68 +#include "softmmu_header.h"
  69 +
  70 +#define DATA_SIZE 8
  71 +#include "softmmu_header.h"
  72 +#undef ACCESS_TYPE
  73 +#undef MEMSUFFIX
  74 +
  75 +#define ACCESS_TYPE 1
  76 +#define MEMSUFFIX _user
  77 +#define DATA_SIZE 1
  78 +#include "softmmu_header.h"
  79 +
  80 +#define DATA_SIZE 2
  81 +#include "softmmu_header.h"
  82 +
  83 +#define DATA_SIZE 4
  84 +#include "softmmu_header.h"
  85 +
  86 +#define DATA_SIZE 8
  87 +#include "softmmu_header.h"
  88 +#undef ACCESS_TYPE
  89 +#undef MEMSUFFIX
  90 +
  91 +/* these access are slower, they must be as rare as possible */
  92 +#define ACCESS_TYPE 2
  93 +#define MEMSUFFIX _data
  94 +#define DATA_SIZE 1
  95 +#include "softmmu_header.h"
  96 +
  97 +#define DATA_SIZE 2
  98 +#include "softmmu_header.h"
  99 +
  100 +#define DATA_SIZE 4
  101 +#include "softmmu_header.h"
  102 +
  103 +#define DATA_SIZE 8
  104 +#include "softmmu_header.h"
  105 +#undef ACCESS_TYPE
  106 +#undef MEMSUFFIX
  107 +
  108 +#define ldub(p) ldub_data(p)
  109 +#define ldsb(p) ldsb_data(p)
  110 +#define lduw(p) lduw_data(p)
  111 +#define ldsw(p) ldsw_data(p)
  112 +#define ldl(p) ldl_data(p)
  113 +#define ldq(p) ldq_data(p)
  114 +
  115 +#define stb(p, v) stb_data(p, v)
  116 +#define stw(p, v) stw_data(p, v)
  117 +#define stl(p, v) stl_data(p, v)
  118 +#define stq(p, v) stq_data(p, v)
  119 +
  120 +#endif /* !defined(CONFIG_USER_ONLY) */
  121 +
  122 +static inline void env_to_regs(void)
  123 +{
  124 +}
  125 +
  126 +static inline void regs_to_env(void)
  127 +{
  128 +}
  129 +
  130 +#if (HOST_LONG_BITS == 32)
  131 +void do_mult (void);
  132 +void do_multu (void);
  133 +void do_madd (void);
  134 +void do_maddu (void);
  135 +void do_msub (void);
  136 +void do_msubu (void);
  137 +#endif
  138 +__attribute__ (( regparm(2) ))
  139 +void do_mfc0(int reg, int sel);
  140 +__attribute__ (( regparm(2) ))
  141 +void do_mtc0(int reg, int sel);
  142 +void do_tlbwi (void);
  143 +void do_tlbwr (void);
  144 +void do_tlbp (void);
  145 +void do_tlbr (void);
  146 +void do_lwl_raw (void);
  147 +void do_lwr_raw (void);
  148 +void do_swl_raw (void);
  149 +void do_swr_raw (void);
  150 +#if !defined(CONFIG_USER_ONLY)
  151 +void do_lwl_user (void);
  152 +void do_lwl_kernel (void);
  153 +void do_lwr_user (void);
  154 +void do_lwr_kernel (void);
  155 +void do_swl_user (void);
  156 +void do_swl_kernel (void);
  157 +void do_swr_user (void);
  158 +void do_swr_kernel (void);
  159 +#endif
  160 +__attribute__ (( regparm(1) ))
  161 +void do_pmon (int function);
  162 +
  163 +int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
  164 + int is_user, int is_softmmu);
  165 +void do_interrupt (CPUState *env);
  166 +
  167 +void cpu_loop_exit(void);
  168 +__attribute__ (( regparm(2) ))
  169 +void do_raise_exception_err (uint32_t exception, int error_code);
  170 +__attribute__ (( regparm(1) ))
  171 +void do_raise_exception (uint32_t exception);
  172 +
  173 +void cpu_dump_state(CPUState *env, FILE *f,
  174 + int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
  175 + int flags);
  176 +void cpu_mips_irqctrl_init (void);
  177 +uint32_t cpu_mips_get_random (CPUState *env);
  178 +uint32_t cpu_mips_get_count (CPUState *env);
  179 +void cpu_mips_store_count (CPUState *env, uint32_t value);
  180 +void cpu_mips_store_compare (CPUState *env, uint32_t value);
  181 +void cpu_mips_clock_init (CPUState *env);
  182 +
  183 +#endif /* !defined(__QEMU_MIPS_EXEC_H__) */
... ...
target-mips/helper.c 0 โ†’ 100644
  1 +/*
  2 + * MIPS emulation helpers for qemu.
  3 + *
  4 + * Copyright (c) 2004-2005 Jocelyn Mayer
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +
  21 +#include "exec.h"
  22 +
  23 +/* MIPS32 4K MMU emulation */
  24 +#if MIPS_USES_4K_TLB
  25 +static int map_address (CPUState *env, target_ulong *physical, int *prot,
  26 + target_ulong address, int rw, int access_type)
  27 +{
  28 + tlb_t *tlb;
  29 + target_ulong tag;
  30 + uint8_t ASID;
  31 + int i, n;
  32 + int ret;
  33 +
  34 + ret = -2;
  35 + tag = (address & 0xFFFFE000);
  36 + ASID = env->CP0_EntryHi & 0x000000FF;
  37 + for (i = 0; i < 16; i++) {
  38 + tlb = &env->tlb[i];
  39 + /* Check ASID, virtual page number & size */
  40 + if ((tlb->G == 1 || tlb->ASID == ASID) &&
  41 + tlb->VPN == tag && address < tlb->end) {
  42 + /* TLB match */
  43 + n = (address >> 12) & 1;
  44 + /* Check access rights */
  45 + if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) {
  46 + *physical = tlb->PFN[n] | (address & 0xFFF);
  47 + *prot = PROT_READ;
  48 + if (tlb->D[n])
  49 + *prot |= PROT_WRITE;
  50 + return 0;
  51 + } else if (!(tlb->V[n] & 2)) {
  52 + return -3;
  53 + } else {
  54 + return -4;
  55 + }
  56 + }
  57 + }
  58 +
  59 + return ret;
  60 +}
  61 +#endif
  62 +
  63 +int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
  64 + target_ulong address, int rw, int access_type)
  65 +{
  66 + int user_mode;
  67 + int ret;
  68 +
  69 + /* User mode can only access useg */
  70 + user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0;
  71 +#if 0
  72 + if (logfile) {
  73 + fprintf(logfile, "user mode %d h %08x\n",
  74 + user_mode, env->hflags);
  75 + }
  76 +#endif
  77 + if (user_mode && address > 0x7FFFFFFFUL)
  78 + return -1;
  79 + ret = 0;
  80 + if (address < 0x80000000UL) {
  81 + if (user_mode || !(env->hflags & MIPS_HFLAG_ERL)) {
  82 +#if MIPS_USES_4K_TLB
  83 + ret = map_address(env, physical, prot, address, rw);
  84 +#else
  85 + *physical = address + 0x40000000UL;
  86 + *prot = PAGE_READ | PAGE_WRITE;
  87 +#endif
  88 + } else {
  89 + *physical = address;
  90 + *prot = PAGE_READ | PAGE_WRITE;
  91 + }
  92 + } else if (address < 0xA0000000UL) {
  93 + /* kseg0 */
  94 + /* XXX: check supervisor mode */
  95 + *physical = address - 0x80000000UL;
  96 + *prot = PAGE_READ | PAGE_WRITE;
  97 + } else if (address < 0xC0000000UL) {
  98 + /* kseg1 */
  99 + /* XXX: check supervisor mode */
  100 + *physical = address - 0xA0000000UL;
  101 + *prot = PAGE_READ | PAGE_WRITE;
  102 + } else if (address < 0xE0000000UL) {
  103 + /* kseg2 */
  104 +#if MIPS_USES_4K_TLB
  105 + ret = map_address(env, physical, prot, address, rw);
  106 +#else
  107 + *physical = address;
  108 + *prot = PAGE_READ | PAGE_WRITE;
  109 +#endif
  110 + } else {
  111 + /* kseg3 */
  112 + /* XXX: check supervisor mode */
  113 + /* XXX: debug segment is not emulated */
  114 +#if MIPS_USES_4K_TLB
  115 + ret = map_address(env, physical, prot, address, rw);
  116 +#else
  117 + *physical = address;
  118 + *prot = PAGE_READ | PAGE_WRITE;
  119 +#endif
  120 + }
  121 +#if 0
  122 + if (logfile) {
  123 + fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
  124 + access_type, *physical, *prot, ret);
  125 + }
  126 +#endif
  127 +
  128 + return ret;
  129 +}
  130 +
  131 +#if defined(CONFIG_USER_ONLY)
  132 +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
  133 +{
  134 + return addr;
  135 +}
  136 +#else
  137 +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
  138 +{
  139 + target_ulong phys_addr;
  140 + int prot;
  141 +
  142 + if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
  143 + return -1;
  144 + return phys_addr;
  145 +}
  146 +#endif
  147 +
  148 +#if !defined(CONFIG_USER_ONLY)
  149 +
  150 +#define MMUSUFFIX _mmu
  151 +#define GETPC() (__builtin_return_address(0))
  152 +
  153 +#define SHIFT 0
  154 +#include "softmmu_template.h"
  155 +
  156 +#define SHIFT 1
  157 +#include "softmmu_template.h"
  158 +
  159 +#define SHIFT 2
  160 +#include "softmmu_template.h"
  161 +
  162 +#define SHIFT 3
  163 +#include "softmmu_template.h"
  164 +
  165 +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
  166 +{
  167 + TranslationBlock *tb;
  168 + CPUState *saved_env;
  169 + unsigned long pc;
  170 + int ret;
  171 +
  172 + /* XXX: hack to restore env in all cases, even if not called from
  173 + generated code */
  174 + saved_env = env;
  175 + env = cpu_single_env;
  176 + ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
  177 + if (ret) {
  178 + if (retaddr) {
  179 + /* now we have a real cpu fault */
  180 + pc = (unsigned long)retaddr;
  181 + tb = tb_find_pc(pc);
  182 + if (tb) {
  183 + /* the PC is inside the translated code. It means that we have
  184 + a virtual CPU fault */
  185 + cpu_restore_state(tb, env, pc, NULL);
  186 + }
  187 + }
  188 + do_raise_exception_err(env->exception_index, env->error_code);
  189 + }
  190 + env = saved_env;
  191 +}
  192 +
  193 +void cpu_mips_init_mmu (CPUState *env)
  194 +{
  195 +}
  196 +
  197 +#endif /* !defined(CONFIG_USER_ONLY) */
  198 +
  199 +int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
  200 + int is_user, int is_softmmu)
  201 +{
  202 + target_ulong physical;
  203 + int prot;
  204 + int exception = 0, error_code = 0;
  205 + int access_type;
  206 + int ret = 0;
  207 +
  208 + if (logfile) {
  209 + cpu_dump_state(env, logfile, fprintf, 0);
  210 + fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
  211 + __func__, env->PC, address, rw, is_user, is_softmmu);
  212 + }
  213 + /* data access */
  214 + /* XXX: put correct access by using cpu_restore_state()
  215 + correctly */
  216 + access_type = ACCESS_INT;
  217 + if (env->user_mode_only) {
  218 + /* user mode only emulation */
  219 + ret = -2;
  220 + goto do_fault;
  221 + }
  222 + ret = get_physical_address(env, &physical, &prot,
  223 + address, rw, access_type);
  224 + if (logfile) {
  225 + fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
  226 + __func__, address, ret, physical, prot);
  227 + }
  228 + if (ret == 0) {
  229 + ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
  230 + is_user, is_softmmu);
  231 + } else if (ret < 0) {
  232 + do_fault:
  233 + switch (ret) {
  234 + default:
  235 + case -1:
  236 + /* Reference to kernel address from user mode or supervisor mode */
  237 + /* Reference to supervisor address from user mode */
  238 + if (rw)
  239 + exception = EXCP_AdES;
  240 + else
  241 + exception = EXCP_AdEL;
  242 + break;
  243 + case -2:
  244 + /* No TLB match for a mapped address */
  245 + if (rw)
  246 + exception = EXCP_TLBS;
  247 + else
  248 + exception = EXCP_TLBL;
  249 + error_code = 1;
  250 + break;
  251 + case -3:
  252 + /* TLB match with no valid bit */
  253 + if (rw)
  254 + exception = EXCP_TLBS;
  255 + else
  256 + exception = EXCP_TLBL;
  257 + error_code = 0;
  258 + break;
  259 + case -4:
  260 + /* TLB match but 'D' bit is cleared */
  261 + exception = EXCP_LTLBL;
  262 + break;
  263 +
  264 + }
  265 + if (ret == -2) {
  266 + exception = EXCP_AdEL;
  267 + }
  268 + /* Raise exception */
  269 + env->CP0_BadVAddr = address;
  270 + env->CP0_Context =
  271 + (env->CP0_Context & 0x00000FFF) | (address & 0xFFFFF000);
  272 + env->CP0_EntryHi =
  273 + (env->CP0_EntryHi & 0x00000FFF) | (address & 0xFFFFF000);
  274 + env->exception_index = exception;
  275 + env->error_code = error_code;
  276 + ret = 1;
  277 + }
  278 +
  279 + return ret;
  280 +}
  281 +
  282 +void do_interrupt (CPUState *env)
  283 +{
  284 + target_ulong pc, offset;
  285 + int cause = -1;
  286 +
  287 + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
  288 + fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
  289 + __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
  290 + }
  291 + if (env->exception_index == EXCP_EXT_INTERRUPT &&
  292 + (env->hflags & MIPS_HFLAG_DM))
  293 + env->exception_index = EXCP_DINT;
  294 + offset = 0x180;
  295 + switch (env->exception_index) {
  296 + case EXCP_DSS:
  297 + env->CP0_Debug |= 1 << CP0DB_DSS;
  298 + /* Debug single step cannot be raised inside a delay slot and
  299 + * resume will always occur on the next instruction
  300 + * (but we assume the pc has always been updated during
  301 + * code translation).
  302 + */
  303 + env->CP0_DEPC = env->PC;
  304 + goto enter_debug_mode;
  305 + case EXCP_DINT:
  306 + env->CP0_Debug |= 1 << CP0DB_DINT;
  307 + goto set_DEPC;
  308 + case EXCP_DIB:
  309 + env->CP0_Debug |= 1 << CP0DB_DIB;
  310 + goto set_DEPC;
  311 + case EXCP_DBp:
  312 + env->CP0_Debug |= 1 << CP0DB_DBp;
  313 + goto set_DEPC;
  314 + case EXCP_DDBS:
  315 + env->CP0_Debug |= 1 << CP0DB_DDBS;
  316 + goto set_DEPC;
  317 + case EXCP_DDBL:
  318 + env->CP0_Debug |= 1 << CP0DB_DDBL;
  319 + goto set_DEPC;
  320 + set_DEPC:
  321 + if (env->hflags & MIPS_HFLAG_DS) {
  322 + /* If the exception was raised from a delay slot,
  323 + * come back to the jump
  324 + */
  325 + env->CP0_DEPC = env->PC - 4;
  326 + } else {
  327 + env->CP0_DEPC = env->PC;
  328 + }
  329 + enter_debug_mode:
  330 + env->hflags |= MIPS_HFLAG_DM;
  331 + /* EJTAG probe trap enable is not implemented... */
  332 + pc = 0xBFC00480;
  333 + break;
  334 + case EXCP_RESET:
  335 +#if defined (MIPS_USES_R4K_TLB)
  336 + env->CP0_random = MIPS_TLB_NB - 1;
  337 +#endif
  338 + env->CP0_Wired = 0;
  339 + env->CP0_Config0 = MIPS_CONFIG0;
  340 +#if defined (MIPS_CONFIG1)
  341 + env->CP0_Config1 = MIPS_CONFIG1;
  342 +#endif
  343 +#if defined (MIPS_CONFIG2)
  344 + env->CP0_Config2 = MIPS_CONFIG2;
  345 +#endif
  346 +#if defined (MIPS_CONFIG3)
  347 + env->CP0_Config3 = MIPS_CONFIG3;
  348 +#endif
  349 + env->CP0_WatchLo = 0;
  350 + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
  351 + goto set_error_EPC;
  352 + case EXCP_SRESET:
  353 + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
  354 + (1 << CP0St_SR);
  355 + env->CP0_WatchLo = 0;
  356 + goto set_error_EPC;
  357 + case EXCP_NMI:
  358 + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
  359 + (1 << CP0St_NMI);
  360 + set_error_EPC:
  361 + env->hflags = MIPS_HFLAG_ERL;
  362 + if (env->hflags & MIPS_HFLAG_DS) {
  363 + /* If the exception was raised from a delay slot,
  364 + * come back to the jump
  365 + */
  366 + env->CP0_ErrorEPC = env->PC - 4;
  367 + } else {
  368 + env->CP0_ErrorEPC = env->PC;
  369 + }
  370 + pc = 0xBFC00000;
  371 + break;
  372 + case EXCP_MCHECK:
  373 + cause = 24;
  374 + goto set_EPC;
  375 + case EXCP_EXT_INTERRUPT:
  376 + cause = 0;
  377 + if (env->CP0_Cause & (1 << CP0Ca_IV))
  378 + offset = 0x200;
  379 + goto set_EPC;
  380 + case EXCP_DWATCH:
  381 + cause = 23;
  382 + /* XXX: TODO: manage defered watch exceptions */
  383 + goto set_EPC;
  384 + case EXCP_AdEL:
  385 + case EXCP_AdES:
  386 + cause = 4;
  387 + goto set_EPC;
  388 + case EXCP_TLBL:
  389 + case EXCP_TLBF:
  390 + cause = 2;
  391 + if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
  392 + offset = 0x000;
  393 + goto set_EPC;
  394 + case EXCP_IBE:
  395 + cause = 6;
  396 + goto set_EPC;
  397 + case EXCP_DBE:
  398 + cause = 7;
  399 + goto set_EPC;
  400 + case EXCP_SYSCALL:
  401 + cause = 8;
  402 + goto set_EPC;
  403 + case EXCP_BREAK:
  404 + cause = 9;
  405 + goto set_EPC;
  406 + case EXCP_RI:
  407 + cause = 10;
  408 + goto set_EPC;
  409 + case EXCP_CpU:
  410 + cause = 11;
  411 + /* XXX: fill in the faulty unit number */
  412 + goto set_EPC;
  413 + case EXCP_OVERFLOW:
  414 + cause = 12;
  415 + goto set_EPC;
  416 + case EXCP_TRAP:
  417 + cause = 13;
  418 + goto set_EPC;
  419 + case EXCP_LTLBL:
  420 + cause = 1;
  421 + goto set_EPC;
  422 + case EXCP_TLBS:
  423 + cause = 3;
  424 + set_EPC:
  425 + if (env->CP0_Status & (1 << CP0St_BEV)) {
  426 + pc = 0xBFC00200;
  427 + } else {
  428 + pc = 0x80000000;
  429 + }
  430 + env->hflags |= MIPS_HFLAG_EXL;
  431 + pc += offset;
  432 + env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
  433 + if (env->hflags & MIPS_HFLAG_DS) {
  434 + /* If the exception was raised from a delay slot,
  435 + * come back to the jump
  436 + */
  437 + env->CP0_EPC = env->PC - 4;
  438 + env->CP0_Cause |= 0x80000000;
  439 + } else {
  440 + env->CP0_EPC = env->PC;
  441 + env->CP0_Cause &= ~0x80000000;
  442 + }
  443 + break;
  444 + default:
  445 + if (logfile) {
  446 + fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
  447 + env->exception_index);
  448 + }
  449 + printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
  450 + exit(1);
  451 + }
  452 + env->PC = pc;
  453 + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
  454 + fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
  455 + " S %08x C %08x A %08x D %08x\n",
  456 + __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
  457 + env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
  458 + env->CP0_DEPC);
  459 + }
  460 + env->exception_index = EXCP_NONE;
  461 +}
... ...
target-mips/mips-defs.h 0 โ†’ 100644
  1 +#if !defined (__QEMU_MIPS_DEFS_H__)
  2 +#define __QEMU_MIPS_DEFS_H__
  3 +
  4 +/* If we want to use 64 bits host regs... */
  5 +//#define USE_64BITS_REGS
  6 +/* If we want to use host float regs... */
  7 +//#define USE_HOST_FLOAT_REGS
  8 +
  9 +enum {
  10 + MIPS_R4Kc = 0x00018000,
  11 + MIPS_R4Kp = 0x00018300,
  12 +};
  13 +
  14 +/* Emulate MIPS R4Kc for now */
  15 +#define MIPS_CPU MIPS_R4Kc
  16 +
  17 +#if (MIPS_CPU == MIPS_R4Kc)
  18 +/* 32 bits target */
  19 +#define TARGET_LONG_BITS 32
  20 +/* real pages are variable size... */
  21 +#define TARGET_PAGE_BITS 12
  22 +/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
  23 +#define MIPS_USES_R4K_EXT
  24 +/* Uses MIPS R4Kc TLB model */
  25 +#define MIPS_USES_R4K_TLB
  26 +#define MIPS_TLB_NB 16
  27 +/* Have config1, runs in big-endian mode, uses TLB */
  28 +#define MIPS_CONFIG0 \
  29 +((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \
  30 + (1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0))
  31 +/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
  32 + * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
  33 + * no performance counters, watch registers present, no code compression,
  34 + * EJTAG present, no FPU
  35 + */
  36 +#define MIPS_CONFIG1 \
  37 +((15 << CP0C1_MMU) | \
  38 + (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
  39 + (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
  40 + (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \
  41 + (1 << CP0C1_EP) | (0 << CP0C1_FP))
  42 +#elif defined (MIPS_CPU == MIPS_R4Kp)
  43 +/* 32 bits target */
  44 +#define TARGET_LONG_BITS 32
  45 +/* real pages are variable size... */
  46 +#define TARGET_PAGE_BITS 12
  47 +/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
  48 +#define MIPS_USES_R4K_EXT
  49 +/* Uses MIPS R4Km FPM MMU model */
  50 +#define MIPS_USES_R4K_FPM
  51 +#else
  52 +#error "MIPS CPU not defined"
  53 +/* Remainder for other flags */
  54 +//#define TARGET_MIPS64
  55 +//define MIPS_USES_FPU
  56 +#endif
  57 +
  58 +#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
... ...
target-mips/op.c 0 โ†’ 100644
  1 +/*
  2 + * MIPS emulation micro-operations for qemu.
  3 + *
  4 + * Copyright (c) 2004-2005 Jocelyn Mayer
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +
  21 +#include "config.h"
  22 +#include "exec.h"
  23 +
  24 +#define REG 1
  25 +#include "op_template.c"
  26 +#undef REG
  27 +#define REG 2
  28 +#include "op_template.c"
  29 +#undef REG
  30 +#define REG 3
  31 +#include "op_template.c"
  32 +#undef REG
  33 +#define REG 4
  34 +#include "op_template.c"
  35 +#undef REG
  36 +#define REG 5
  37 +#include "op_template.c"
  38 +#undef REG
  39 +#define REG 6
  40 +#include "op_template.c"
  41 +#undef REG
  42 +#define REG 7
  43 +#include "op_template.c"
  44 +#undef REG
  45 +#define REG 8
  46 +#include "op_template.c"
  47 +#undef REG
  48 +#define REG 9
  49 +#include "op_template.c"
  50 +#undef REG
  51 +#define REG 10
  52 +#include "op_template.c"
  53 +#undef REG
  54 +#define REG 11
  55 +#include "op_template.c"
  56 +#undef REG
  57 +#define REG 12
  58 +#include "op_template.c"
  59 +#undef REG
  60 +#define REG 13
  61 +#include "op_template.c"
  62 +#undef REG
  63 +#define REG 14
  64 +#include "op_template.c"
  65 +#undef REG
  66 +#define REG 15
  67 +#include "op_template.c"
  68 +#undef REG
  69 +#define REG 16
  70 +#include "op_template.c"
  71 +#undef REG
  72 +#define REG 17
  73 +#include "op_template.c"
  74 +#undef REG
  75 +#define REG 18
  76 +#include "op_template.c"
  77 +#undef REG
  78 +#define REG 19
  79 +#include "op_template.c"
  80 +#undef REG
  81 +#define REG 20
  82 +#include "op_template.c"
  83 +#undef REG
  84 +#define REG 21
  85 +#include "op_template.c"
  86 +#undef REG
  87 +#define REG 22
  88 +#include "op_template.c"
  89 +#undef REG
  90 +#define REG 23
  91 +#include "op_template.c"
  92 +#undef REG
  93 +#define REG 24
  94 +#include "op_template.c"
  95 +#undef REG
  96 +#define REG 25
  97 +#include "op_template.c"
  98 +#undef REG
  99 +#define REG 26
  100 +#include "op_template.c"
  101 +#undef REG
  102 +#define REG 27
  103 +#include "op_template.c"
  104 +#undef REG
  105 +#define REG 28
  106 +#include "op_template.c"
  107 +#undef REG
  108 +#define REG 29
  109 +#include "op_template.c"
  110 +#undef REG
  111 +#define REG 30
  112 +#include "op_template.c"
  113 +#undef REG
  114 +#define REG 31
  115 +#include "op_template.c"
  116 +#undef REG
  117 +
  118 +#define TN T0
  119 +#include "op_template.c"
  120 +#undef TN
  121 +#define TN T1
  122 +#include "op_template.c"
  123 +#undef TN
  124 +#define TN T2
  125 +#include "op_template.c"
  126 +#undef TN
  127 +
  128 +void op_dup_T0 (void)
  129 +{
  130 + T2 = T0;
  131 + RETURN();
  132 +}
  133 +
  134 +void op_load_HI (void)
  135 +{
  136 + T0 = env->HI;
  137 + RETURN();
  138 +}
  139 +
  140 +void op_store_HI (void)
  141 +{
  142 + env->HI = T0;
  143 + RETURN();
  144 +}
  145 +
  146 +void op_load_LO (void)
  147 +{
  148 + T0 = env->LO;
  149 + RETURN();
  150 +}
  151 +
  152 +void op_store_LO (void)
  153 +{
  154 + env->LO = T0;
  155 + RETURN();
  156 +}
  157 +
  158 +/* Load and store */
  159 +#define MEMSUFFIX _raw
  160 +#include "op_mem.c"
  161 +#undef MEMSUFFIX
  162 +#if !defined(CONFIG_USER_ONLY)
  163 +#define MEMSUFFIX _user
  164 +#include "op_mem.c"
  165 +#undef MEMSUFFIX
  166 +
  167 +#define MEMSUFFIX _kernel
  168 +#include "op_mem.c"
  169 +#undef MEMSUFFIX
  170 +#endif
  171 +
  172 +/* Arithmetic */
  173 +void op_add (void)
  174 +{
  175 + T0 += T1;
  176 + RETURN();
  177 +}
  178 +
  179 +void op_addo (void)
  180 +{
  181 + target_ulong tmp;
  182 +
  183 + tmp = T0;
  184 + T0 += T1;
  185 + if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
  186 + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
  187 + }
  188 + RETURN();
  189 +}
  190 +
  191 +void op_sub (void)
  192 +{
  193 + T0 -= T1;
  194 + RETURN();
  195 +}
  196 +
  197 +void op_subo (void)
  198 +{
  199 + target_ulong tmp;
  200 +
  201 + tmp = T0;
  202 + T0 = (int32_t)T0 - (int32_t)T1;
  203 + if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
  204 + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
  205 + }
  206 + RETURN();
  207 +}
  208 +
  209 +void op_mul (void)
  210 +{
  211 + T0 = (int32_t)T0 * (int32_t)T1;
  212 + RETURN();
  213 +}
  214 +
  215 +void op_div (void)
  216 +{
  217 + if (T1 != 0) {
  218 + env->LO = (int32_t)T0 / (int32_t)T1;
  219 + env->HI = (int32_t)T0 % (int32_t)T1;
  220 + }
  221 + RETURN();
  222 +}
  223 +
  224 +void op_divu (void)
  225 +{
  226 + if (T1 != 0) {
  227 + env->LO = T0 / T1;
  228 + env->HI = T0 % T1;
  229 + }
  230 + RETURN();
  231 +}
  232 +
  233 +/* Logical */
  234 +void op_and (void)
  235 +{
  236 + T0 &= T1;
  237 + RETURN();
  238 +}
  239 +
  240 +void op_nor (void)
  241 +{
  242 + T0 = ~(T0 | T1);
  243 + RETURN();
  244 +}
  245 +
  246 +void op_or (void)
  247 +{
  248 + T0 |= T1;
  249 + RETURN();
  250 +}
  251 +
  252 +void op_xor (void)
  253 +{
  254 + T0 ^= T1;
  255 + RETURN();
  256 +}
  257 +
  258 +void op_sll (void)
  259 +{
  260 + T0 = T0 << T1;
  261 + RETURN();
  262 +}
  263 +
  264 +void op_sra (void)
  265 +{
  266 + T0 = (int32_t)T0 >> T1;
  267 + RETURN();
  268 +}
  269 +
  270 +void op_srl (void)
  271 +{
  272 + T0 = T0 >> T1;
  273 + RETURN();
  274 +}
  275 +
  276 +void op_sllv (void)
  277 +{
  278 + T0 = T1 << (T0 & 0x1F);
  279 + RETURN();
  280 +}
  281 +
  282 +void op_srav (void)
  283 +{
  284 + T0 = (int32_t)T1 >> (T0 & 0x1F);
  285 + RETURN();
  286 +}
  287 +
  288 +void op_srlv (void)
  289 +{
  290 + T0 = T1 >> (T0 & 0x1F);
  291 + RETURN();
  292 +}
  293 +
  294 +void op_clo (void)
  295 +{
  296 + int n;
  297 +
  298 + if (T0 == (target_ulong)-1) {
  299 + T0 = 32;
  300 + } else {
  301 + for (n = 0; n < 32; n++) {
  302 + if (!(T0 & (1 << 31)))
  303 + break;
  304 + T0 = T0 << 1;
  305 + }
  306 + T0 = n;
  307 + }
  308 + RETURN();
  309 +}
  310 +
  311 +void op_clz (void)
  312 +{
  313 + int n;
  314 +
  315 + if (T0 == 0) {
  316 + T0 = 32;
  317 + } else {
  318 + for (n = 0; n < 32; n++) {
  319 + if (T0 & (1 << 31))
  320 + break;
  321 + T0 = T0 << 1;
  322 + }
  323 + T0 = n;
  324 + }
  325 + RETURN();
  326 +}
  327 +
  328 +/* 64 bits arithmetic */
  329 +#if (HOST_LONG_BITS == 64)
  330 +static inline uint64_t get_HILO (void)
  331 +{
  332 + return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
  333 +}
  334 +
  335 +static inline void set_HILO (uint64_t HILO)
  336 +{
  337 + env->LO = HILO & 0xFFFFFFFF;
  338 + env->HI = HILO >> 32;
  339 +}
  340 +
  341 +void op_mult (void)
  342 +{
  343 + set_HILO((int64_t)T0 * (int64_t)T1);
  344 + RETURN();
  345 +}
  346 +
  347 +void op_multu (void)
  348 +{
  349 + set_HILO((uint64_t)T0 * (uint64_t)T1);
  350 + RETURN();
  351 +}
  352 +
  353 +void op_madd (void)
  354 +{
  355 + int64_t tmp;
  356 +
  357 + tmp = ((int64_t)T0 * (int64_t)T1);
  358 + set_HILO((int64_t)get_HILO() + tmp);
  359 + RETURN();
  360 +}
  361 +
  362 +void op_maddu (void)
  363 +{
  364 + uint64_t tmp;
  365 +
  366 + tmp = ((uint64_t)T0 * (uint64_t)T1);
  367 + set_HILO(get_HILO() + tmp);
  368 + RETURN();
  369 +}
  370 +
  371 +void op_msub (void)
  372 +{
  373 + int64_t tmp;
  374 +
  375 + tmp = ((int64_t)T0 * (int64_t)T1);
  376 + set_HILO((int64_t)get_HILO() - tmp);
  377 + RETURN();
  378 +}
  379 +
  380 +void op_msubu (void)
  381 +{
  382 + uint64_t tmp;
  383 +
  384 + tmp = ((uint64_t)T0 * (uint64_t)T1);
  385 + set_HILO(get_HILO() - tmp);
  386 + RETURN();
  387 +}
  388 +#else
  389 +void op_mult (void)
  390 +{
  391 + CALL_FROM_TB0(do_mult);
  392 + RETURN();
  393 +}
  394 +
  395 +void op_multu (void)
  396 +{
  397 + CALL_FROM_TB0(do_multu);
  398 + RETURN();
  399 +}
  400 +
  401 +void op_madd (void)
  402 +{
  403 + CALL_FROM_TB0(do_madd);
  404 + RETURN();
  405 +}
  406 +
  407 +void op_maddu (void)
  408 +{
  409 + CALL_FROM_TB0(do_maddu);
  410 + RETURN();
  411 +}
  412 +
  413 +void op_msub (void)
  414 +{
  415 + CALL_FROM_TB0(do_msub);
  416 + RETURN();
  417 +}
  418 +
  419 +void op_msubu (void)
  420 +{
  421 + CALL_FROM_TB0(do_msubu);
  422 + RETURN();
  423 +}
  424 +#endif
  425 +
  426 +/* Conditional moves */
  427 +void op_movn (void)
  428 +{
  429 + if (T1 != 0)
  430 + env->gpr[PARAM1] = T0;
  431 + RETURN();
  432 +}
  433 +
  434 +void op_movz (void)
  435 +{
  436 + if (T1 == 0)
  437 + env->gpr[PARAM1] = T0;
  438 + RETURN();
  439 +}
  440 +
  441 +/* Tests */
  442 +#define OP_COND(name, cond) \
  443 +void glue(op_, name) (void) \
  444 +{ \
  445 + if (cond) { \
  446 + T0 = 1; \
  447 + } else { \
  448 + T0 = 0; \
  449 + } \
  450 + RETURN(); \
  451 +}
  452 +
  453 +OP_COND(eq, T0 == T1);
  454 +OP_COND(ne, T0 != T1);
  455 +OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
  456 +OP_COND(geu, T0 >= T1);
  457 +OP_COND(lt, (int32_t)T0 < (int32_t)T1);
  458 +OP_COND(ltu, T0 < T1);
  459 +OP_COND(gez, (int32_t)T0 >= 0);
  460 +OP_COND(gtz, (int32_t)T0 > 0);
  461 +OP_COND(lez, (int32_t)T0 <= 0);
  462 +OP_COND(ltz, (int32_t)T0 < 0);
  463 +
  464 +/* Branchs */
  465 +//#undef USE_DIRECT_JUMP
  466 +#define EIP env->PC
  467 +
  468 +/* Branch to register */
  469 +void op_save_breg_target (void)
  470 +{
  471 + env->btarget = T2;
  472 +}
  473 +
  474 +void op_restore_breg_target (void)
  475 +{
  476 + T2 = env->btarget;
  477 +}
  478 +
  479 +void op_breg (void)
  480 +{
  481 + env->PC = T2;
  482 + RETURN();
  483 +}
  484 +
  485 +/* Unconditional branch */
  486 +void op_branch (void)
  487 +{
  488 + JUMP_TB(branch, PARAM1, 0, PARAM2);
  489 + RETURN();
  490 +}
  491 +
  492 +void op_save_btarget (void)
  493 +{
  494 + env->btarget = PARAM1;
  495 + RETURN();
  496 +}
  497 +
  498 +/* Conditional branch */
  499 +void op_set_bcond (void)
  500 +{
  501 + T2 = T0;
  502 + RETURN();
  503 +}
  504 +
  505 +void op_save_bcond (void)
  506 +{
  507 + env->bcond = T2;
  508 + RETURN();
  509 +}
  510 +
  511 +void op_restore_bcond (void)
  512 +{
  513 + T2 = env->bcond;
  514 + RETURN();
  515 +}
  516 +
  517 +void op_bcond (void)
  518 +{
  519 + if (T2) {
  520 + JUMP_TB(bcond, PARAM1, 0, PARAM2);
  521 + } else {
  522 + JUMP_TB(bcond, PARAM1, 1, PARAM3);
  523 + }
  524 + RETURN();
  525 +}
  526 +
  527 +/* Likely branch (used to skip the delay slot) */
  528 +void op_blikely (void)
  529 +{
  530 + /* If the test is false, skip the delay slot */
  531 + if (T2 == 0) {
  532 + env->hflags = PARAM3;
  533 + JUMP_TB(blikely, PARAM1, 1, PARAM2);
  534 + }
  535 + RETURN();
  536 +}
  537 +
  538 +/* CP0 functions */
  539 +void op_mfc0 (void)
  540 +{
  541 + CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
  542 + RETURN();
  543 +}
  544 +
  545 +void op_mtc0 (void)
  546 +{
  547 + CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
  548 + RETURN();
  549 +}
  550 +
  551 +#if defined(MIPS_USES_R4K_TLB)
  552 +void op_tlbwi (void)
  553 +{
  554 + CALL_FROM_TB0(do_tlbwi);
  555 + RETURN();
  556 +}
  557 +
  558 +void op_tlbwr (void)
  559 +{
  560 + CALL_FROM_TB0(do_tlbwr);
  561 + RETURN();
  562 +}
  563 +
  564 +void op_tlbp (void)
  565 +{
  566 + CALL_FROM_TB0(do_tlbp);
  567 + RETURN();
  568 +}
  569 +
  570 +void op_tlbr (void)
  571 +{
  572 + CALL_FROM_TB0(do_tlbr);
  573 + RETURN();
  574 +}
  575 +#endif
  576 +
  577 +/* Specials */
  578 +void op_pmon (void)
  579 +{
  580 + CALL_FROM_TB1(do_pmon, PARAM1);
  581 +}
  582 +
  583 +void op_trap (void)
  584 +{
  585 + if (T0) {
  586 + CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
  587 + }
  588 + RETURN();
  589 +}
  590 +
  591 +void op_set_lladdr (void)
  592 +{
  593 + env->CP0_LLAddr = T2;
  594 +}
  595 +
  596 +void debug_eret (void);
  597 +void op_eret (void)
  598 +{
  599 + CALL_FROM_TB0(debug_eret);
  600 + if (env->hflags & MIPS_HFLAG_ERL)
  601 + env->PC = env->CP0_ErrorEPC;
  602 + else
  603 + env->PC = env->CP0_EPC;
  604 + env->CP0_LLAddr = 1;
  605 +}
  606 +
  607 +void op_deret (void)
  608 +{
  609 + CALL_FROM_TB0(debug_eret);
  610 + env->PC = env->CP0_DEPC;
  611 +}
  612 +
  613 +void op_save_state (void)
  614 +{
  615 + env->hflags = PARAM1;
  616 + RETURN();
  617 +}
  618 +
  619 +void op_save_pc (void)
  620 +{
  621 + env->PC = PARAM1;
  622 + RETURN();
  623 +}
  624 +
  625 +void op_raise_exception (void)
  626 +{
  627 + CALL_FROM_TB1(do_raise_exception, PARAM1);
  628 + RETURN();
  629 +}
  630 +
  631 +void op_raise_exception_err (void)
  632 +{
  633 + CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
  634 + RETURN();
  635 +}
  636 +
  637 +void op_exit_tb (void)
  638 +{
  639 + EXIT_TB();
  640 +}
  641 +
... ...
target-mips/op_helper.c 0 โ†’ 100644
  1 +/*
  2 + * MIPS emulation helpers for qemu.
  3 + *
  4 + * Copyright (c) 2004-2005 Jocelyn Mayer
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +#include <math.h>
  21 +#include "exec.h"
  22 +
  23 +#define MIPS_DEBUG_DISAS
  24 +
  25 +/*****************************************************************************/
  26 +/* Exceptions processing helpers */
  27 +void cpu_loop_exit(void)
  28 +{
  29 + longjmp(env->jmp_env, 1);
  30 +}
  31 +
  32 +__attribute__ (( regparm(2) ))
  33 +void do_raise_exception_err (uint32_t exception, int error_code)
  34 +{
  35 +#if 1
  36 + if (logfile && exception < 0x100)
  37 + fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
  38 +#endif
  39 + env->exception_index = exception;
  40 + env->error_code = error_code;
  41 + T0 = 0;
  42 + cpu_loop_exit();
  43 +}
  44 +
  45 +__attribute__ (( regparm(1) ))
  46 +void do_raise_exception (uint32_t exception)
  47 +{
  48 + do_raise_exception_err(exception, 0);
  49 +}
  50 +
  51 +#define MEMSUFFIX _raw
  52 +#include "op_helper_mem.c"
  53 +#undef MEMSUFFIX
  54 +#if !defined(CONFIG_USER_ONLY)
  55 +#define MEMSUFFIX _user
  56 +#include "op_helper_mem.c"
  57 +#undef MEMSUFFIX
  58 +#define MEMSUFFIX _kernel
  59 +#include "op_helper_mem.c"
  60 +#undef MEMSUFFIX
  61 +#endif
  62 +
  63 +/* 64 bits arithmetic for 32 bits hosts */
  64 +#if (HOST_LONG_BITS == 32)
  65 +static inline uint64_t get_HILO (void)
  66 +{
  67 + return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
  68 +}
  69 +
  70 +static inline void set_HILO (uint64_t HILO)
  71 +{
  72 + env->LO = HILO & 0xFFFFFFFF;
  73 + env->HI = HILO >> 32;
  74 +}
  75 +
  76 +void do_mult (void)
  77 +{
  78 + set_HILO((int64_t)T0 * (int64_t)T1);
  79 +}
  80 +
  81 +void do_multu (void)
  82 +{
  83 + set_HILO((uint64_t)T0 * (uint64_t)T1);
  84 +}
  85 +
  86 +void do_madd (void)
  87 +{
  88 + int64_t tmp;
  89 +
  90 + tmp = ((int64_t)T0 * (int64_t)T1);
  91 + set_HILO((int64_t)get_HILO() + tmp);
  92 +}
  93 +
  94 +void do_maddu (void)
  95 +{
  96 + uint64_t tmp;
  97 +
  98 + tmp = ((uint64_t)T0 * (uint64_t)T1);
  99 + set_HILO(get_HILO() + tmp);
  100 +}
  101 +
  102 +void do_msub (void)
  103 +{
  104 + int64_t tmp;
  105 +
  106 + tmp = ((int64_t)T0 * (int64_t)T1);
  107 + set_HILO((int64_t)get_HILO() - tmp);
  108 +}
  109 +
  110 +void do_msubu (void)
  111 +{
  112 + uint64_t tmp;
  113 +
  114 + tmp = ((uint64_t)T0 * (uint64_t)T1);
  115 + set_HILO(get_HILO() - tmp);
  116 +}
  117 +#endif
  118 +
  119 +/* CP0 helpers */
  120 +__attribute__ (( regparm(2) ))
  121 +void do_mfc0 (int reg, int sel)
  122 +{
  123 + const unsigned char *rn;
  124 +
  125 + if (sel != 0 && reg != 16 && reg != 28) {
  126 + rn = "invalid";
  127 + goto print;
  128 + }
  129 + switch (reg) {
  130 + case 0:
  131 + T0 = env->CP0_index;
  132 + rn = "Index";
  133 + break;
  134 + case 1:
  135 + T0 = cpu_mips_get_random(env);
  136 + rn = "Random";
  137 + break;
  138 + case 2:
  139 + T0 = env->CP0_EntryLo0;
  140 + rn = "EntryLo0";
  141 + break;
  142 + case 3:
  143 + T0 = env->CP0_EntryLo1;
  144 + rn = "EntryLo1";
  145 + break;
  146 + case 4:
  147 + T0 = env->CP0_Context;
  148 + rn = "Context";
  149 + break;
  150 + case 5:
  151 + T0 = env->CP0_PageMask;
  152 + rn = "PageMask";
  153 + break;
  154 + case 6:
  155 + T0 = env->CP0_Wired;
  156 + rn = "Wired";
  157 + break;
  158 + case 8:
  159 + T0 = env->CP0_BadVAddr;
  160 + rn = "BadVaddr";
  161 + break;
  162 + case 9:
  163 + T0 = cpu_mips_get_count(env);
  164 + rn = "Count";
  165 + break;
  166 + case 10:
  167 + T0 = env->CP0_EntryHi;
  168 + rn = "EntryHi";
  169 + break;
  170 + case 11:
  171 + T0 = env->CP0_Compare;
  172 + rn = "Compare";
  173 + break;
  174 + case 12:
  175 + T0 = env->CP0_Status;
  176 + if (env->hflags & MIPS_HFLAG_UM)
  177 + T0 |= CP0St_UM;
  178 + if (env->hflags & MIPS_HFLAG_ERL)
  179 + T0 |= CP0St_ERL;
  180 + if (env->hflags & MIPS_HFLAG_EXL)
  181 + T0 |= CP0St_EXL;
  182 + rn = "Status";
  183 + break;
  184 + case 13:
  185 + T0 = env->CP0_Cause;
  186 + rn = "Cause";
  187 + break;
  188 + case 14:
  189 + T0 = env->CP0_EPC;
  190 + rn = "EPC";
  191 + break;
  192 + case 15:
  193 + T0 = env->CP0_PRid;
  194 + rn = "PRid";
  195 + break;
  196 + case 16:
  197 + switch (sel) {
  198 + case 0:
  199 + T0 = env->CP0_Config0;
  200 + rn = "Config";
  201 + break;
  202 + case 1:
  203 + T0 = env->CP0_Config1;
  204 + rn = "Config1";
  205 + break;
  206 + default:
  207 + rn = "Unknown config register";
  208 + break;
  209 + }
  210 + break;
  211 + case 17:
  212 + T0 = env->CP0_LLAddr >> 4;
  213 + rn = "LLAddr";
  214 + break;
  215 + case 18:
  216 + T0 = env->CP0_WatchLo;
  217 + rn = "WatchLo";
  218 + break;
  219 + case 19:
  220 + T0 = env->CP0_WatchHi;
  221 + rn = "WatchHi";
  222 + break;
  223 + case 23:
  224 + T0 = env->CP0_Debug;
  225 + if (env->hflags & MIPS_HFLAG_DM)
  226 + T0 |= 1 << CP0DB_DM;
  227 + rn = "Debug";
  228 + break;
  229 + case 24:
  230 + T0 = env->CP0_DEPC;
  231 + rn = "DEPC";
  232 + break;
  233 + case 28:
  234 + switch (sel) {
  235 + case 0:
  236 + T0 = env->CP0_TagLo;
  237 + rn = "TagLo";
  238 + break;
  239 + case 1:
  240 + T0 = env->CP0_DataLo;
  241 + rn = "DataLo";
  242 + break;
  243 + default:
  244 + rn = "unknown sel";
  245 + break;
  246 + }
  247 + break;
  248 + case 30:
  249 + T0 = env->CP0_ErrorEPC;
  250 + rn = "ErrorEPC";
  251 + break;
  252 + case 31:
  253 + T0 = env->CP0_DESAVE;
  254 + rn = "DESAVE";
  255 + break;
  256 + default:
  257 + rn = "unknown";
  258 + break;
  259 + }
  260 + print:
  261 +#if defined MIPS_DEBUG_DISAS
  262 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  263 + fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
  264 + env->PC, rn, T0, reg, sel);
  265 + }
  266 +#endif
  267 + return;
  268 +}
  269 +
  270 +__attribute__ (( regparm(2) ))
  271 +void do_mtc0 (int reg, int sel)
  272 +{
  273 + const unsigned char *rn;
  274 + uint32_t val, old, mask;
  275 + int i, raise;
  276 +
  277 + if (sel != 0 && reg != 16 && reg != 28) {
  278 + val = -1;
  279 + old = -1;
  280 + rn = "invalid";
  281 + goto print;
  282 + }
  283 + switch (reg) {
  284 + case 0:
  285 + val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
  286 + old = env->CP0_index;
  287 + env->CP0_index = val;
  288 + rn = "Index";
  289 + break;
  290 + case 2:
  291 + val = T0 & 0x03FFFFFFF;
  292 + old = env->CP0_EntryLo0;
  293 + env->CP0_EntryLo0 = val;
  294 + rn = "EntryLo0";
  295 + break;
  296 + case 3:
  297 + val = T0 & 0x03FFFFFFF;
  298 + old = env->CP0_EntryLo1;
  299 + env->CP0_EntryLo1 = val;
  300 + rn = "EntryLo1";
  301 + break;
  302 + case 4:
  303 + val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0);
  304 + old = env->CP0_Context;
  305 + env->CP0_Context = val;
  306 + rn = "Context";
  307 + break;
  308 + case 5:
  309 + val = T0 & 0x01FFE000;
  310 + old = env->CP0_PageMask;
  311 + env->CP0_PageMask = val;
  312 + rn = "PageMask";
  313 + break;
  314 + case 6:
  315 + val = T0 & 0x0000000F;
  316 + old = env->CP0_Wired;
  317 + env->CP0_Wired = val;
  318 + rn = "Wired";
  319 + break;
  320 + case 9:
  321 + val = T0;
  322 + old = cpu_mips_get_count(env);
  323 + cpu_mips_store_count(env, val);
  324 + rn = "Count";
  325 + break;
  326 + case 10:
  327 + val = T0 & 0xFFFFF0FF;
  328 + old = env->CP0_EntryHi;
  329 + env->CP0_EntryHi = val;
  330 + rn = "EntryHi";
  331 + break;
  332 + case 11:
  333 + val = T0;
  334 + old = env->CP0_Compare;
  335 + cpu_mips_store_compare(env, val);
  336 + rn = "Compare";
  337 + break;
  338 + case 12:
  339 + val = T0 & 0xFA78FF01;
  340 + if (T0 & (1 << CP0St_UM))
  341 + env->hflags |= MIPS_HFLAG_UM;
  342 + else
  343 + env->hflags &= ~MIPS_HFLAG_UM;
  344 + if (T0 & (1 << CP0St_ERL))
  345 + env->hflags |= MIPS_HFLAG_ERL;
  346 + else
  347 + env->hflags &= ~MIPS_HFLAG_ERL;
  348 + if (T0 & (1 << CP0St_EXL))
  349 + env->hflags |= MIPS_HFLAG_EXL;
  350 + else
  351 + env->hflags &= ~MIPS_HFLAG_EXL;
  352 + old = env->CP0_Status;
  353 + env->CP0_Status = val;
  354 + /* If we unmasked an asserted IRQ, raise it */
  355 + mask = 0x0000FC00;
  356 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  357 + fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
  358 + old, val, env->CP0_Cause, old & mask, val & mask,
  359 + env->CP0_Cause & mask);
  360 + }
  361 +#if 1
  362 + if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
  363 + !(env->hflags & MIPS_HFLAG_EXL) &&
  364 + !(env->hflags & MIPS_HFLAG_ERL) &&
  365 + !(env->hflags & MIPS_HFLAG_DM) &&
  366 + (env->CP0_Cause & mask)) {
  367 + if (logfile)
  368 + fprintf(logfile, "Raise pending IRQs\n");
  369 + env->interrupt_request |= CPU_INTERRUPT_HARD;
  370 + do_raise_exception(EXCP_EXT_INTERRUPT);
  371 + } else if (!(val & 0x00000001) && (old & 0x00000001)) {
  372 + env->interrupt_request &= ~CPU_INTERRUPT_HARD;
  373 + }
  374 +#endif
  375 + rn = "Status";
  376 + break;
  377 + case 13:
  378 + val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
  379 + old = env->CP0_Cause;
  380 + env->CP0_Cause = val;
  381 +#if 0
  382 + /* Check if we ever asserted a software IRQ */
  383 + for (i = 0; i < 2; i++) {
  384 + mask = 0x100 << i;
  385 + if ((val & mask) & !(old & mask))
  386 + mips_set_irq(i);
  387 + }
  388 +#endif
  389 + rn = "Cause";
  390 + break;
  391 + case 14:
  392 + val = T0;
  393 + old = env->CP0_EPC;
  394 + env->CP0_EPC = val;
  395 + rn = "EPC";
  396 + break;
  397 + case 16:
  398 + switch (sel) {
  399 + case 0:
  400 +#if defined(MIPS_USES_R4K_TLB)
  401 + val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
  402 +#else
  403 + val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
  404 +#endif
  405 + old = env->CP0_Config0;
  406 + env->CP0_Config0 = val;
  407 + rn = "Config0";
  408 + break;
  409 + default:
  410 + val = -1;
  411 + old = -1;
  412 + rn = "bad config selector";
  413 + break;
  414 + }
  415 + break;
  416 + case 18:
  417 + val = T0;
  418 + old = env->CP0_WatchLo;
  419 + env->CP0_WatchLo = val;
  420 + rn = "WatchLo";
  421 + break;
  422 + case 19:
  423 + val = T0 & 0x40FF0FF8;
  424 + old = env->CP0_WatchHi;
  425 + env->CP0_WatchHi = val;
  426 + rn = "WatchHi";
  427 + break;
  428 + case 23:
  429 + val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
  430 + if (T0 & (1 << CP0DB_DM))
  431 + env->hflags |= MIPS_HFLAG_DM;
  432 + else
  433 + env->hflags &= ~MIPS_HFLAG_DM;
  434 + old = env->CP0_Debug;
  435 + env->CP0_Debug = val;
  436 + rn = "Debug";
  437 + break;
  438 + case 24:
  439 + val = T0;
  440 + old = env->CP0_DEPC;
  441 + env->CP0_DEPC = val;
  442 + rn = "DEPC";
  443 + break;
  444 + case 28:
  445 + switch (sel) {
  446 + case 0:
  447 + val = T0 & 0xFFFFFCF6;
  448 + old = env->CP0_TagLo;
  449 + env->CP0_TagLo = val;
  450 + rn = "TagLo";
  451 + break;
  452 + default:
  453 + val = -1;
  454 + old = -1;
  455 + rn = "invalid sel";
  456 + break;
  457 + }
  458 + break;
  459 + case 30:
  460 + val = T0;
  461 + old = env->CP0_ErrorEPC;
  462 + env->CP0_ErrorEPC = val;
  463 + rn = "EPC";
  464 + break;
  465 + case 31:
  466 + val = T0;
  467 + old = env->CP0_DESAVE;
  468 + env->CP0_DESAVE = val;
  469 + rn = "DESAVE";
  470 + break;
  471 + default:
  472 + val = -1;
  473 + old = -1;
  474 + rn = "unknown";
  475 + break;
  476 + }
  477 + print:
  478 +#if defined MIPS_DEBUG_DISAS
  479 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  480 + fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
  481 + env->PC, rn, T0, val, reg, sel, old);
  482 + }
  483 +#endif
  484 + return;
  485 +}
  486 +
  487 +/* TLB management */
  488 +#if defined(MIPS_USES_R4K_TLB)
  489 +__attribute__ (( regparm(1) ))
  490 +static void invalidate_tb (int idx)
  491 +{
  492 + tlb_t *tlb;
  493 + target_ulong addr, end;
  494 +
  495 + tlb = &env->tlb[idx];
  496 + if (tlb->V[0]) {
  497 + addr = tlb->PFN[0];
  498 + end = addr + (tlb->end - tlb->VPN);
  499 + tb_invalidate_page_range(addr, end);
  500 + }
  501 + if (tlb->V[1]) {
  502 + addr = tlb->PFN[1];
  503 + end = addr + (tlb->end - tlb->VPN);
  504 + tb_invalidate_page_range(addr, end);
  505 + }
  506 +}
  507 +
  508 +__attribute__ (( regparm(1) ))
  509 +static void fill_tb (int idx)
  510 +{
  511 + tlb_t *tlb;
  512 + int size;
  513 +
  514 + /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
  515 + tlb = &env->tlb[idx];
  516 + tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
  517 + tlb->ASID = env->CP0_EntryHi & 0x000000FF;
  518 + size = env->CP0_PageMask >> 13;
  519 + size = 4 * (size + 1);
  520 + tlb->end = tlb->VPN + (1 << (8 + size));
  521 + tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
  522 + tlb->V[0] = env->CP0_EntryLo0 & 2;
  523 + tlb->D[0] = env->CP0_EntryLo0 & 4;
  524 + tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7;
  525 + tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
  526 + tlb->V[1] = env->CP0_EntryLo1 & 2;
  527 + tlb->D[1] = env->CP0_EntryLo1 & 4;
  528 + tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7;
  529 + tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
  530 +}
  531 +
  532 +void do_tlbwi (void)
  533 +{
  534 + invalidate_tb(env->CP0_index & 0xF);
  535 + fill_tb(env->CP0_index & 0xF);
  536 +}
  537 +
  538 +void do_tlbwr (void)
  539 +{
  540 + int r = cpu_mips_get_random(env);
  541 +
  542 + invalidate_tb(r);
  543 + fill_tb(r);
  544 +}
  545 +
  546 +void do_tlbp (void)
  547 +{
  548 + tlb_t *tlb;
  549 + target_ulong tag;
  550 + uint8_t ASID;
  551 + int i;
  552 +
  553 + tag = (env->CP0_EntryHi & 0xFFFFE000);
  554 + ASID = env->CP0_EntryHi & 0x000000FF;
  555 + for (i = 0; i < 16; i++) {
  556 + tlb = &env->tlb[i];
  557 + /* Check ASID, virtual page number & size */
  558 + if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
  559 + /* TLB match */
  560 + env->CP0_index = i;
  561 + break;
  562 + }
  563 + }
  564 + if (i == 16) {
  565 + env->CP0_index |= 0x80000000;
  566 + }
  567 +}
  568 +
  569 +void do_tlbr (void)
  570 +{
  571 + tlb_t *tlb;
  572 + int size;
  573 +
  574 + tlb = &env->tlb[env->CP0_index & 0xF];
  575 + env->CP0_EntryHi = tlb->VPN | tlb->ASID;
  576 + size = (tlb->end - tlb->VPN) >> 12;
  577 + env->CP0_PageMask = (size - 1) << 13;
  578 + env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) |
  579 + (tlb->PFN[0] >> 6);
  580 + env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) |
  581 + (tlb->PFN[1] >> 6);
  582 +}
  583 +#endif
  584 +
  585 +__attribute__ (( regparm(1) ))
  586 +void op_dump_ldst (const unsigned char *func)
  587 +{
  588 + if (loglevel)
  589 + fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
  590 +}
  591 +
  592 +void dump_sc (void)
  593 +{
  594 + if (loglevel) {
  595 + fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
  596 + T1, T0, env->CP0_LLAddr);
  597 + }
  598 +}
  599 +
  600 +void debug_eret (void)
  601 +{
  602 + if (loglevel) {
  603 + fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
  604 + env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
  605 + env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
  606 + }
  607 +}
  608 +
  609 +__attribute__ (( regparm(1) ))
  610 +void do_pmon (int function)
  611 +{
  612 + function /= 2;
  613 + switch (function) {
  614 + case 2: /* TODO: char inbyte(int waitflag); */
  615 + if (env->gpr[4] == 0)
  616 + env->gpr[2] = -1;
  617 + /* Fall through */
  618 + case 11: /* TODO: char inbyte (void); */
  619 + env->gpr[2] = -1;
  620 + break;
  621 + case 3:
  622 + case 12:
  623 + printf("%c", env->gpr[4] & 0xFF);
  624 + break;
  625 + case 17:
  626 + break;
  627 + case 158:
  628 + {
  629 + unsigned char *fmt = (void *)env->gpr[4];
  630 + printf("%s", fmt);
  631 + }
  632 + break;
  633 + }
  634 +}
... ...
target-mips/op_helper_mem.c 0 โ†’ 100644
  1 +void glue(do_lwl, MEMSUFFIX) (void)
  2 +{
  3 +#if defined (DEBUG_OP)
  4 + target_ulong sav = T0;
  5 +#endif
  6 + uint32_t tmp;
  7 +
  8 + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
  9 + /* XXX: this is valid only in big-endian mode
  10 + * should be reverted for little-endian...
  11 + */
  12 + switch (T0 & 3) {
  13 + case 0:
  14 + T0 = tmp;
  15 + break;
  16 + case 1:
  17 + T0 = (tmp << 8) | (T1 & 0x000000FF);
  18 + break;
  19 + case 2:
  20 + T0 = (tmp << 16) | (T1 & 0x0000FFFF);
  21 + break;
  22 + case 3:
  23 + T0 = (tmp << 24) | (T1 & 0x00FFFFFF);
  24 + break;
  25 + }
  26 +#if defined (DEBUG_OP)
  27 + if (logfile) {
  28 + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
  29 + __func__, sav, tmp, T1, T0);
  30 + }
  31 +#endif
  32 + RETURN();
  33 +}
  34 +
  35 +void glue(do_lwr, MEMSUFFIX) (void)
  36 +{
  37 +#if defined (DEBUG_OP)
  38 + target_ulong sav = T0;
  39 +#endif
  40 + uint32_t tmp;
  41 +
  42 + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
  43 + /* XXX: this is valid only in big-endian mode
  44 + * should be reverted for little-endian...
  45 + */
  46 + switch (T0 & 3) {
  47 + case 0:
  48 + T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
  49 + break;
  50 + case 1:
  51 + T0 = (tmp >> 16) | (T1 & 0xFFFF0000);
  52 + break;
  53 + case 2:
  54 + T0 = (tmp >> 8) | (T1 & 0xFF000000);
  55 + break;
  56 + case 3:
  57 + T0 = tmp;
  58 + break;
  59 + }
  60 +#if defined (DEBUG_OP)
  61 + if (logfile) {
  62 + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
  63 + __func__, sav, tmp, T1, T0);
  64 + }
  65 +#endif
  66 + RETURN();
  67 +}
  68 +
  69 +void glue(do_swl, MEMSUFFIX) (void)
  70 +{
  71 +#if defined (DEBUG_OP)
  72 + target_ulong sav;
  73 +#endif
  74 + uint32_t tmp;
  75 +
  76 + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
  77 +#if defined (DEBUG_OP)
  78 + sav = tmp;
  79 +#endif
  80 + /* XXX: this is valid only in big-endian mode
  81 + * should be reverted for little-endian...
  82 + */
  83 + switch (T0 & 3) {
  84 + case 0:
  85 + tmp = T1;
  86 + break;
  87 + case 1:
  88 + tmp = (tmp & 0xFF000000) | (T1 >> 8);
  89 + break;
  90 + case 2:
  91 + tmp = (tmp & 0xFFFF0000) | (T1 >> 16);
  92 + break;
  93 + case 3:
  94 + tmp = (tmp & 0xFFFFFF00) | (T1 >> 24);
  95 + break;
  96 + }
  97 + glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
  98 +#if defined (DEBUG_OP)
  99 + if (logfile) {
  100 + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
  101 + __func__, T0, sav, T1, tmp);
  102 + }
  103 +#endif
  104 + RETURN();
  105 +}
  106 +
  107 +void glue(do_swr, MEMSUFFIX) (void)
  108 +{
  109 +#if defined (DEBUG_OP)
  110 + target_ulong sav;
  111 +#endif
  112 + uint32_t tmp;
  113 +
  114 + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
  115 +#if defined (DEBUG_OP)
  116 + sav = tmp;
  117 +#endif
  118 + /* XXX: this is valid only in big-endian mode
  119 + * should be reverted for little-endian...
  120 + */
  121 + switch (T0 & 3) {
  122 + case 0:
  123 + tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
  124 + break;
  125 + case 1:
  126 + tmp = (tmp & 0x0000FFFF) | (T1 << 16);
  127 + break;
  128 + case 2:
  129 + tmp = (tmp & 0x000000FF) | (T1 << 8);
  130 + break;
  131 + case 3:
  132 + tmp = T1;
  133 + break;
  134 + }
  135 + glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
  136 +#if defined (DEBUG_OP)
  137 + if (logfile) {
  138 + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
  139 + __func__, T0, sav, T1, tmp);
  140 + }
  141 +#endif
  142 + RETURN();
  143 +}
... ...
target-mips/op_mem.c 0 โ†’ 100644
  1 +/*
  2 + * MIPS emulation memory micro-operations for qemu.
  3 + *
  4 + * Copyright (c) 2004-2005 Jocelyn Mayer
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +
  21 +/* Standard loads and stores */
  22 +void glue(op_lb, MEMSUFFIX) (void)
  23 +{
  24 + T0 = glue(ldsb, MEMSUFFIX)(T0);
  25 + RETURN();
  26 +}
  27 +
  28 +void glue(op_lbu, MEMSUFFIX) (void)
  29 +{
  30 + T0 = glue(ldub, MEMSUFFIX)(T0);
  31 + RETURN();
  32 +}
  33 +
  34 +void glue(op_sb, MEMSUFFIX) (void)
  35 +{
  36 + glue(stb, MEMSUFFIX)(T0, T1);
  37 + RETURN();
  38 +}
  39 +
  40 +void glue(op_lh, MEMSUFFIX) (void)
  41 +{
  42 + T0 = glue(ldsw, MEMSUFFIX)(T0);
  43 + RETURN();
  44 +}
  45 +
  46 +void glue(op_lhu, MEMSUFFIX) (void)
  47 +{
  48 + T0 = glue(lduw, MEMSUFFIX)(T0);
  49 + RETURN();
  50 +}
  51 +
  52 +void glue(op_sh, MEMSUFFIX) (void)
  53 +{
  54 + glue(stw, MEMSUFFIX)(T0, T1);
  55 + RETURN();
  56 +}
  57 +
  58 +void glue(op_lw, MEMSUFFIX) (void)
  59 +{
  60 + T0 = glue(ldl, MEMSUFFIX)(T0);
  61 + RETURN();
  62 +}
  63 +
  64 +void glue(op_sw, MEMSUFFIX) (void)
  65 +{
  66 + glue(stl, MEMSUFFIX)(T0, T1);
  67 + RETURN();
  68 +}
  69 +
  70 +/* "half" load and stores */
  71 +void glue(op_lwl, MEMSUFFIX) (void)
  72 +{
  73 + CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX));
  74 + RETURN();
  75 +}
  76 +
  77 +void glue(op_lwr, MEMSUFFIX) (void)
  78 +{
  79 + CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX));
  80 + RETURN();
  81 +}
  82 +
  83 +void glue(op_swl, MEMSUFFIX) (void)
  84 +{
  85 + CALL_FROM_TB0(glue(do_swl, MEMSUFFIX));
  86 + RETURN();
  87 +}
  88 +
  89 +void glue(op_swr, MEMSUFFIX) (void)
  90 +{
  91 + CALL_FROM_TB0(glue(do_swr, MEMSUFFIX));
  92 + RETURN();
  93 +}
  94 +
  95 +void glue(op_ll, MEMSUFFIX) (void)
  96 +{
  97 + T1 = T0;
  98 + T0 = glue(ldl, MEMSUFFIX)(T0);
  99 + env->CP0_LLAddr = T1;
  100 + RETURN();
  101 +}
  102 +
  103 +void glue(op_sc, MEMSUFFIX) (void)
  104 +{
  105 + CALL_FROM_TB0(dump_sc);
  106 + if (T0 == env->CP0_LLAddr) {
  107 + glue(stl, MEMSUFFIX)(T0, T1);
  108 + T0 = 1;
  109 + } else {
  110 + T0 = 0;
  111 + }
  112 + RETURN();
  113 +}
... ...
target-mips/op_template.c 0 โ†’ 100644
  1 +/*
  2 + * MIPS emulation micro-operations templates for reg load & store for qemu.
  3 + *
  4 + * Copyright (c) 2004-2005 Jocelyn Mayer
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +
  21 +#if defined(REG)
  22 +void glue(op_load_gpr_T0_gpr, REG) (void)
  23 +{
  24 + T0 = env->gpr[REG];
  25 + RETURN();
  26 +}
  27 +
  28 +void glue(op_store_T0_gpr_gpr, REG) (void)
  29 +{
  30 + env->gpr[REG] = T0;
  31 + RETURN();
  32 +}
  33 +
  34 +void glue(op_load_gpr_T1_gpr, REG) (void)
  35 +{
  36 + T1 = env->gpr[REG];
  37 + RETURN();
  38 +}
  39 +
  40 +void glue(op_store_T1_gpr_gpr, REG) (void)
  41 +{
  42 + env->gpr[REG] = T1;
  43 + RETURN();
  44 +}
  45 +
  46 +void glue(op_load_gpr_T2_gpr, REG) (void)
  47 +{
  48 + T2 = env->gpr[REG];
  49 + RETURN();
  50 +}
  51 +#endif
  52 +
  53 +#if defined (TN)
  54 +void glue(op_set_, TN) (void)
  55 +{
  56 + TN = PARAM1;
  57 + RETURN();
  58 +}
  59 +
  60 +void glue (op_reset_, TN) (void)
  61 +{
  62 + TN = 0;
  63 + RETURN();
  64 +}
  65 +#endif
... ...
target-mips/translate.c 0 โ†’ 100644
  1 +/*
  2 + * MIPS32 emulation for qemu: main translation routines.
  3 + *
  4 + * Copyright (c) 2004-2005 Jocelyn Mayer
  5 + *
  6 + * This library is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU Lesser General Public
  8 + * License as published by the Free Software Foundation; either
  9 + * version 2 of the License, or (at your option) any later version.
  10 + *
  11 + * This library is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 + * Lesser General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU Lesser General Public
  17 + * License along with this library; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +
  21 +#include <stdarg.h>
  22 +#include <stdlib.h>
  23 +#include <stdio.h>
  24 +#include <string.h>
  25 +#include <inttypes.h>
  26 +
  27 +#include "cpu.h"
  28 +#include "exec-all.h"
  29 +#include "disas.h"
  30 +
  31 +#define MIPS_DEBUG_DISAS
  32 +//#define MIPS_SINGLE_STEP
  33 +
  34 +enum {
  35 +#define DEF(s, n, copy_size) INDEX_op_ ## s,
  36 +#include "opc.h"
  37 +#undef DEF
  38 + NB_OPS,
  39 +};
  40 +
  41 +static uint16_t *gen_opc_ptr;
  42 +static uint32_t *gen_opparam_ptr;
  43 +
  44 +#include "gen-op.h"
  45 +
  46 +const unsigned char *regnames[] =
  47 + { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
  48 + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
  49 + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
  50 + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
  51 +
  52 +/* Warning: no function for r0 register (hard wired to zero) */
  53 +#define GEN32(func, NAME) \
  54 +static GenOpFunc *NAME ## _table [32] = { \
  55 +NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
  56 +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
  57 +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
  58 +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
  59 +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
  60 +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
  61 +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
  62 +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
  63 +}; \
  64 +static inline void func(int n) \
  65 +{ \
  66 + NAME ## _table[n](); \
  67 +}
  68 +
  69 +/* General purpose registers moves */
  70 +GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
  71 +GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
  72 +GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
  73 +
  74 +GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
  75 +GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
  76 +
  77 +typedef struct DisasContext {
  78 + struct TranslationBlock *tb;
  79 + target_ulong pc, saved_pc;
  80 + uint32_t opcode;
  81 + /* Routine used to access memory */
  82 + int mem_idx;
  83 + uint32_t hflags, saved_hflags;
  84 + uint32_t CP0_Status;
  85 + int bstate;
  86 + target_ulong btarget;
  87 +} DisasContext;
  88 +
  89 +enum {
  90 + BS_NONE = 0, /* We go out of the TB without reaching a branch or an
  91 + * exception condition
  92 + */
  93 + BS_STOP = 1, /* We want to stop translation for any reason */
  94 + BS_BRANCH = 2, /* We reached a branch condition */
  95 + BS_EXCP = 3, /* We reached an exception condition */
  96 +};
  97 +
  98 +#if defined MIPS_DEBUG_DISAS
  99 +#define MIPS_DEBUG(fmt, args...) \
  100 +do { \
  101 + if (loglevel & CPU_LOG_TB_IN_ASM) { \
  102 + fprintf(logfile, "%08x: %08x " fmt "\n", \
  103 + ctx->pc, ctx->opcode , ##args); \
  104 + } \
  105 +} while (0)
  106 +#else
  107 +#define MIPS_DEBUG(fmt, args...) do { } while(0)
  108 +#endif
  109 +
  110 +#define MIPS_INVAL(op) \
  111 +do { \
  112 + MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \
  113 + ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \
  114 +} while (0)
  115 +
  116 +#define GEN_LOAD_REG_TN(Tn, Rn) \
  117 +do { \
  118 + if (Rn == 0) { \
  119 + glue(gen_op_reset_, Tn)(); \
  120 + } else { \
  121 + glue(gen_op_load_gpr_, Tn)(Rn); \
  122 + } \
  123 +} while (0)
  124 +
  125 +#define GEN_LOAD_IMM_TN(Tn, Imm) \
  126 +do { \
  127 + if (Imm == 0) { \
  128 + glue(gen_op_reset_, Tn)(); \
  129 + } else { \
  130 + glue(gen_op_set_, Tn)(Imm); \
  131 + } \
  132 +} while (0)
  133 +
  134 +#define GEN_STORE_TN_REG(Rn, Tn) \
  135 +do { \
  136 + if (Rn != 0) { \
  137 + glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
  138 + } \
  139 +} while (0)
  140 +
  141 +static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
  142 +{
  143 +#if defined MIPS_DEBUG_DISAS
  144 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  145 + fprintf(logfile, "hflags %08x saved %08x\n",
  146 + ctx->hflags, ctx->saved_hflags);
  147 + }
  148 +#endif
  149 + if (do_save_pc && ctx->pc != ctx->saved_pc) {
  150 + gen_op_save_pc(ctx->pc);
  151 + ctx->saved_pc = ctx->pc;
  152 + }
  153 + if (ctx->hflags != ctx->saved_hflags) {
  154 + gen_op_save_state(ctx->hflags);
  155 + ctx->saved_hflags = ctx->hflags;
  156 + if (ctx->hflags & MIPS_HFLAG_BR) {
  157 + gen_op_save_breg_target();
  158 + } else if (ctx->hflags & MIPS_HFLAG_B) {
  159 + gen_op_save_btarget(ctx->btarget);
  160 + } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
  161 + gen_op_save_bcond();
  162 + gen_op_save_btarget(ctx->btarget);
  163 + }
  164 + }
  165 +}
  166 +
  167 +static inline void generate_exception (DisasContext *ctx, int excp)
  168 +{
  169 +#if defined MIPS_DEBUG_DISAS
  170 + if (loglevel & CPU_LOG_TB_IN_ASM)
  171 + fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
  172 +#endif
  173 + save_cpu_state(ctx, 1);
  174 + gen_op_raise_exception(excp);
  175 + ctx->bstate = BS_EXCP;
  176 +}
  177 +
  178 +#if defined(CONFIG_USER_ONLY)
  179 +#define op_ldst(name) gen_op_##name##_raw()
  180 +#define OP_LD_TABLE(width)
  181 +#define OP_ST_TABLE(width)
  182 +#else
  183 +#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
  184 +#define OP_LD_TABLE(width) \
  185 +static GenOpFunc *gen_op_l##width[] = { \
  186 + &gen_op_l##width##_user, \
  187 + &gen_op_l##width##_kernel, \
  188 +}
  189 +#define OP_ST_TABLE(width) \
  190 +static GenOpFunc *gen_op_s##width[] = { \
  191 + &gen_op_s##width##_user, \
  192 + &gen_op_s##width##_kernel, \
  193 +}
  194 +#endif
  195 +
  196 +#ifdef TARGET_MIPS64
  197 +OP_LD_TABLE(d);
  198 +OP_LD_TABLE(dl);
  199 +OP_LD_TABLE(dr);
  200 +OP_ST_TABLE(d);
  201 +OP_ST_TABLE(dl);
  202 +OP_ST_TABLE(dr);
  203 +#endif
  204 +OP_LD_TABLE(w);
  205 +OP_LD_TABLE(wl);
  206 +OP_LD_TABLE(wr);
  207 +OP_ST_TABLE(w);
  208 +OP_ST_TABLE(wl);
  209 +OP_ST_TABLE(wr);
  210 +OP_LD_TABLE(h);
  211 +OP_LD_TABLE(hu);
  212 +OP_ST_TABLE(h);
  213 +OP_LD_TABLE(b);
  214 +OP_LD_TABLE(bu);
  215 +OP_ST_TABLE(b);
  216 +OP_LD_TABLE(l);
  217 +OP_ST_TABLE(c);
  218 +
  219 +/* Load and store */
  220 +static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
  221 + int base, int16_t offset)
  222 +{
  223 + const unsigned char *opn = "unk";
  224 +
  225 + if (base == 0) {
  226 + GEN_LOAD_IMM_TN(T0, offset);
  227 + } else if (offset == 0) {
  228 + gen_op_load_gpr_T0(base);
  229 + } else {
  230 + gen_op_load_gpr_T0(base);
  231 + gen_op_set_T1(offset);
  232 + gen_op_add();
  233 + }
  234 + /* Don't do NOP if destination is zero: we must perform the actual
  235 + * memory access
  236 + */
  237 + switch (opc) {
  238 +#if defined(TARGET_MIPS64)
  239 + case OPC_LD:
  240 +#if defined (MIPS_HAS_UNALIGNED_LS)
  241 + case OPC_ULD:
  242 +#endif
  243 + op_ldst(ld);
  244 + GEN_STORE_TN_REG(rt, T0);
  245 + opn = "ld";
  246 + break;
  247 + case OPC_SD:
  248 +#if defined (MIPS_HAS_UNALIGNED_LS)
  249 + case OPC_USD:
  250 +#endif
  251 + GEN_LOAD_REG_TN(T1, rt);
  252 + op_ldst(sd);
  253 + opn = "sd";
  254 + break;
  255 + case OPC_LDL:
  256 + op_ldst(ldl);
  257 + GEN_STORE_TN_REG(rt, T0);
  258 + opn = "ldl";
  259 + break;
  260 + case OPC_SDL:
  261 + GEN_LOAD_REG_TN(T1, rt);
  262 + op_ldst(sdl);
  263 + opn = "sdl";
  264 + break;
  265 + case OPC_LDR:
  266 + op_ldst(ldr);
  267 + GEN_STORE_TN_REG(rt, T0);
  268 + opn = "ldr";
  269 + break;
  270 + case OPC_SDR:
  271 + GEN_LOAD_REG_TN(T1, rt);
  272 + op_ldst(sdr);
  273 + opn = "sdr";
  274 + break;
  275 +#endif
  276 + case OPC_LW:
  277 +#if defined (MIPS_HAS_UNALIGNED_LS)
  278 + case OPC_ULW:
  279 +#endif
  280 + op_ldst(lw);
  281 + GEN_STORE_TN_REG(rt, T0);
  282 + opn = "lw";
  283 + break;
  284 + case OPC_SW:
  285 +#if defined (MIPS_HAS_UNALIGNED_LS)
  286 + case OPC_USW:
  287 +#endif
  288 + GEN_LOAD_REG_TN(T1, rt);
  289 + op_ldst(sw);
  290 + opn = "sw";
  291 + break;
  292 + case OPC_LH:
  293 +#if defined (MIPS_HAS_UNALIGNED_LS)
  294 + case OPC_ULH:
  295 +#endif
  296 + op_ldst(lh);
  297 + GEN_STORE_TN_REG(rt, T0);
  298 + opn = "lh";
  299 + break;
  300 + case OPC_SH:
  301 +#if defined (MIPS_HAS_UNALIGNED_LS)
  302 + case OPC_USH:
  303 +#endif
  304 + GEN_LOAD_REG_TN(T1, rt);
  305 + op_ldst(sh);
  306 + opn = "sh";
  307 + break;
  308 + case OPC_LHU:
  309 +#if defined (MIPS_HAS_UNALIGNED_LS)
  310 + case OPC_ULHU:
  311 +#endif
  312 + op_ldst(lhu);
  313 + GEN_STORE_TN_REG(rt, T0);
  314 + opn = "lhu";
  315 + break;
  316 + case OPC_LB:
  317 + op_ldst(lb);
  318 + GEN_STORE_TN_REG(rt, T0);
  319 + opn = "lb";
  320 + break;
  321 + case OPC_SB:
  322 + GEN_LOAD_REG_TN(T1, rt);
  323 + op_ldst(sb);
  324 + opn = "sb";
  325 + break;
  326 + case OPC_LBU:
  327 + op_ldst(lbu);
  328 + GEN_STORE_TN_REG(rt, T0);
  329 + opn = "lbu";
  330 + break;
  331 + case OPC_LWL:
  332 + op_ldst(lwl);
  333 + GEN_STORE_TN_REG(rt, T0);
  334 + opn = "lwl";
  335 + break;
  336 + case OPC_SWL:
  337 + GEN_LOAD_REG_TN(T1, rt);
  338 + op_ldst(swl);
  339 + opn = "swr";
  340 + break;
  341 + case OPC_LWR:
  342 + op_ldst(lwr);
  343 + GEN_STORE_TN_REG(rt, T0);
  344 + opn = "lwr";
  345 + break;
  346 + case OPC_SWR:
  347 + GEN_LOAD_REG_TN(T1, rt);
  348 + op_ldst(swr);
  349 + opn = "swr";
  350 + break;
  351 + case OPC_LL:
  352 + op_ldst(ll);
  353 + GEN_STORE_TN_REG(rt, T0);
  354 + opn = "ll";
  355 + break;
  356 + case OPC_SC:
  357 + GEN_LOAD_REG_TN(T1, rt);
  358 + op_ldst(sc);
  359 + GEN_STORE_TN_REG(rt, T0);
  360 + opn = "sc";
  361 + break;
  362 + default:
  363 + MIPS_INVAL("load/store");
  364 + generate_exception(ctx, EXCP_RI);
  365 + return;
  366 + }
  367 + MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
  368 +}
  369 +
  370 +/* Arithmetic with immediate operand */
  371 +static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
  372 + int rs, int16_t imm)
  373 +{
  374 + uint32_t uimm;
  375 + const unsigned char *opn = "unk";
  376 +
  377 + if (rt == 0 && opc != OPC_ADDI) {
  378 + /* if no destination, treat it as a NOP
  379 + * For addi, we must generate the overflow exception when needed.
  380 + */
  381 + MIPS_DEBUG("NOP");
  382 + return;
  383 + }
  384 + if (opc == OPC_ADDI || opc == OPC_ADDIU ||
  385 + opc == OPC_SLTI || opc == OPC_SLTIU)
  386 + uimm = (int32_t)imm; /* Sign extent to 32 bits */
  387 + else
  388 + uimm = (uint16_t)imm;
  389 + if (opc != OPC_LUI) {
  390 + GEN_LOAD_REG_TN(T0, rs);
  391 + GEN_LOAD_IMM_TN(T1, uimm);
  392 + } else {
  393 + uimm = uimm << 16;
  394 + GEN_LOAD_IMM_TN(T0, uimm);
  395 + }
  396 + switch (opc) {
  397 + case OPC_ADDI:
  398 + save_cpu_state(ctx, 1);
  399 + gen_op_addo();
  400 + opn = "addi";
  401 + break;
  402 + case OPC_ADDIU:
  403 + gen_op_add();
  404 + opn = "addiu";
  405 + break;
  406 + case OPC_SLTI:
  407 + gen_op_lt();
  408 + opn = "slti";
  409 + break;
  410 + case OPC_SLTIU:
  411 + gen_op_ltu();
  412 + opn = "sltiu";
  413 + break;
  414 + case OPC_ANDI:
  415 + gen_op_and();
  416 + opn = "andi";
  417 + break;
  418 + case OPC_ORI:
  419 + gen_op_or();
  420 + opn = "ori";
  421 + break;
  422 + case OPC_XORI:
  423 + gen_op_xor();
  424 + opn = "xori";
  425 + break;
  426 + case OPC_LUI:
  427 + opn = "lui";
  428 + break;
  429 + case OPC_SLL:
  430 + gen_op_sll();
  431 + opn = "sll";
  432 + break;
  433 + case OPC_SRA:
  434 + gen_op_sra();
  435 + opn = "sra";
  436 + break;
  437 + case OPC_SRL:
  438 + gen_op_srl();
  439 + opn = "srl";
  440 + break;
  441 + default:
  442 + MIPS_INVAL("imm arith");
  443 + generate_exception(ctx, EXCP_RI);
  444 + return;
  445 + }
  446 + GEN_STORE_TN_REG(rt, T0);
  447 + MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
  448 +}
  449 +
  450 +/* Arithmetic */
  451 +static void gen_arith (DisasContext *ctx, uint16_t opc,
  452 + int rd, int rs, int rt)
  453 +{
  454 + const unsigned char *opn = "unk";
  455 +
  456 + if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
  457 + /* if no destination, treat it as a NOP
  458 + * For add & sub, we must generate the overflow exception when needed.
  459 + */
  460 + MIPS_DEBUG("NOP");
  461 + return;
  462 + }
  463 + GEN_LOAD_REG_TN(T0, rs);
  464 + GEN_LOAD_REG_TN(T1, rt);
  465 + switch (opc) {
  466 + case OPC_ADD:
  467 + save_cpu_state(ctx, 1);
  468 + gen_op_addo();
  469 + opn = "add";
  470 + break;
  471 + case OPC_ADDU:
  472 + gen_op_add();
  473 + opn = "addu";
  474 + break;
  475 + case OPC_SUB:
  476 + save_cpu_state(ctx, 1);
  477 + gen_op_subo();
  478 + opn = "sub";
  479 + break;
  480 + case OPC_SUBU:
  481 + gen_op_sub();
  482 + opn = "subu";
  483 + break;
  484 + case OPC_SLT:
  485 + gen_op_lt();
  486 + opn = "slt";
  487 + break;
  488 + case OPC_SLTU:
  489 + gen_op_ltu();
  490 + opn = "sltu";
  491 + break;
  492 + case OPC_AND:
  493 + gen_op_and();
  494 + opn = "and";
  495 + break;
  496 + case OPC_NOR:
  497 + gen_op_nor();
  498 + opn = "nor";
  499 + break;
  500 + case OPC_OR:
  501 + gen_op_or();
  502 + opn = "or";
  503 + break;
  504 + case OPC_XOR:
  505 + gen_op_xor();
  506 + opn = "xor";
  507 + break;
  508 + case OPC_MUL:
  509 + gen_op_mul();
  510 + opn = "mul";
  511 + break;
  512 + case OPC_MOVN:
  513 + gen_op_movn(rd);
  514 + opn = "movn";
  515 + goto print;
  516 + case OPC_MOVZ:
  517 + gen_op_movz(rd);
  518 + opn = "movz";
  519 + goto print;
  520 + case OPC_SLLV:
  521 + gen_op_sllv();
  522 + opn = "sllv";
  523 + break;
  524 + case OPC_SRAV:
  525 + gen_op_srav();
  526 + opn = "srav";
  527 + break;
  528 + case OPC_SRLV:
  529 + gen_op_srlv();
  530 + opn = "srlv";
  531 + break;
  532 + default:
  533 + MIPS_INVAL("arith");
  534 + generate_exception(ctx, EXCP_RI);
  535 + return;
  536 + }
  537 + GEN_STORE_TN_REG(rd, T0);
  538 + print:
  539 + MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
  540 +}
  541 +
  542 +/* Arithmetic on HI/LO registers */
  543 +static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
  544 +{
  545 + const unsigned char *opn = "unk";
  546 +
  547 + if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
  548 + /* Treat as a NOP */
  549 + MIPS_DEBUG("NOP");
  550 + return;
  551 + }
  552 + switch (opc) {
  553 + case OPC_MFHI:
  554 + gen_op_load_HI();
  555 + GEN_STORE_TN_REG(reg, T0);
  556 + opn = "mfhi";
  557 + break;
  558 + case OPC_MFLO:
  559 + gen_op_load_LO();
  560 + GEN_STORE_TN_REG(reg, T0);
  561 + opn = "mflo";
  562 + break;
  563 + case OPC_MTHI:
  564 + GEN_LOAD_REG_TN(T0, reg);
  565 + gen_op_store_HI();
  566 + opn = "mthi";
  567 + break;
  568 + case OPC_MTLO:
  569 + GEN_LOAD_REG_TN(T0, reg);
  570 + gen_op_store_LO();
  571 + opn = "mtlo";
  572 + break;
  573 + default:
  574 + MIPS_INVAL("HILO");
  575 + generate_exception(ctx, EXCP_RI);
  576 + return;
  577 + }
  578 + MIPS_DEBUG("%s %s", opn, regnames[reg]);
  579 +}
  580 +
  581 +static void gen_muldiv (DisasContext *ctx, uint16_t opc,
  582 + int rs, int rt)
  583 +{
  584 + const unsigned char *opn = "unk";
  585 +
  586 + GEN_LOAD_REG_TN(T0, rs);
  587 + GEN_LOAD_REG_TN(T1, rt);
  588 + switch (opc) {
  589 + case OPC_DIV:
  590 + gen_op_div();
  591 + opn = "div";
  592 + break;
  593 + case OPC_DIVU:
  594 + gen_op_divu();
  595 + opn = "divu";
  596 + break;
  597 + case OPC_MULT:
  598 + gen_op_mult();
  599 + opn = "mult";
  600 + break;
  601 + case OPC_MULTU:
  602 + gen_op_multu();
  603 + opn = "multu";
  604 + break;
  605 + case OPC_MADD:
  606 + gen_op_madd();
  607 + opn = "madd";
  608 + break;
  609 + case OPC_MADDU:
  610 + gen_op_maddu();
  611 + opn = "maddu";
  612 + break;
  613 + case OPC_MSUB:
  614 + gen_op_msub();
  615 + opn = "msub";
  616 + break;
  617 + case OPC_MSUBU:
  618 + gen_op_msubu();
  619 + opn = "msubu";
  620 + break;
  621 + default:
  622 + MIPS_INVAL("mul/div");
  623 + generate_exception(ctx, EXCP_RI);
  624 + return;
  625 + }
  626 + MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
  627 +}
  628 +
  629 +static void gen_cl (DisasContext *ctx, uint16_t opc,
  630 + int rd, int rs)
  631 +{
  632 + const unsigned char *opn = "unk";
  633 + if (rd == 0) {
  634 + /* Treat as a NOP */
  635 + MIPS_DEBUG("NOP");
  636 + return;
  637 + }
  638 + GEN_LOAD_REG_TN(T0, rs);
  639 + switch (opc) {
  640 + case OPC_CLO:
  641 + /* CLO */
  642 + gen_op_clo();
  643 + opn = "clo";
  644 + break;
  645 + case OPC_CLZ:
  646 + /* CLZ */
  647 + gen_op_clz();
  648 + opn = "clz";
  649 + break;
  650 + default:
  651 + MIPS_INVAL("CLx");
  652 + generate_exception(ctx, EXCP_RI);
  653 + return;
  654 + }
  655 + gen_op_store_T0_gpr(rd);
  656 + MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
  657 +}
  658 +
  659 +/* Traps */
  660 +static void gen_trap (DisasContext *ctx, uint16_t opc,
  661 + int rs, int rt, int16_t imm)
  662 +{
  663 + int cond;
  664 +
  665 + cond = 0;
  666 + /* Load needed operands */
  667 + switch (opc) {
  668 + case OPC_TEQ:
  669 + case OPC_TGE:
  670 + case OPC_TGEU:
  671 + case OPC_TLT:
  672 + case OPC_TLTU:
  673 + case OPC_TNE:
  674 + /* Compare two registers */
  675 + if (rs != rt) {
  676 + GEN_LOAD_REG_TN(T0, rs);
  677 + GEN_LOAD_REG_TN(T1, rt);
  678 + cond = 1;
  679 + }
  680 + case OPC_TEQI:
  681 + case OPC_TGEI:
  682 + case OPC_TGEIU:
  683 + case OPC_TLTI:
  684 + case OPC_TLTIU:
  685 + case OPC_TNEI:
  686 + /* Compare register to immediate */
  687 + if (rs != 0 || imm != 0) {
  688 + GEN_LOAD_REG_TN(T0, rs);
  689 + GEN_LOAD_IMM_TN(T1, (int32_t)imm);
  690 + cond = 1;
  691 + }
  692 + break;
  693 + }
  694 + if (cond == 0) {
  695 + switch (opc) {
  696 + case OPC_TEQ: /* rs == rs */
  697 + case OPC_TEQI: /* r0 == 0 */
  698 + case OPC_TGE: /* rs >= rs */
  699 + case OPC_TGEI: /* r0 >= 0 */
  700 + case OPC_TGEU: /* rs >= rs unsigned */
  701 + case OPC_TGEIU: /* r0 >= 0 unsigned */
  702 + /* Always trap */
  703 + gen_op_set_T0(1);
  704 + break;
  705 + case OPC_TLT: /* rs < rs */
  706 + case OPC_TLTI: /* r0 < 0 */
  707 + case OPC_TLTU: /* rs < rs unsigned */
  708 + case OPC_TLTIU: /* r0 < 0 unsigned */
  709 + case OPC_TNE: /* rs != rs */
  710 + case OPC_TNEI: /* r0 != 0 */
  711 + /* Never trap: treat as NOP */
  712 + return;
  713 + default:
  714 + MIPS_INVAL("TRAP");
  715 + generate_exception(ctx, EXCP_RI);
  716 + return;
  717 + }
  718 + } else {
  719 + switch (opc) {
  720 + case OPC_TEQ:
  721 + case OPC_TEQI:
  722 + gen_op_eq();
  723 + break;
  724 + case OPC_TGE:
  725 + case OPC_TGEI:
  726 + gen_op_ge();
  727 + break;
  728 + case OPC_TGEU:
  729 + case OPC_TGEIU:
  730 + gen_op_geu();
  731 + break;
  732 + case OPC_TLT:
  733 + case OPC_TLTI:
  734 + gen_op_lt();
  735 + break;
  736 + case OPC_TLTU:
  737 + case OPC_TLTIU:
  738 + gen_op_ltu();
  739 + break;
  740 + case OPC_TNE:
  741 + case OPC_TNEI:
  742 + gen_op_ne();
  743 + break;
  744 + default:
  745 + MIPS_INVAL("TRAP");
  746 + generate_exception(ctx, EXCP_RI);
  747 + return;
  748 + }
  749 + }
  750 + save_cpu_state(ctx, 1);
  751 + gen_op_trap();
  752 + ctx->bstate = BS_STOP;
  753 +}
  754 +
  755 +/* Branches (before delay slot) */
  756 +static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
  757 + int rs, int rt, int32_t offset)
  758 +{
  759 + target_ulong btarget;
  760 + int blink, bcond;
  761 +
  762 + btarget = -1;
  763 + blink = 0;
  764 + bcond = 0;
  765 + /* Load needed operands */
  766 + switch (opc) {
  767 + case OPC_BEQ:
  768 + case OPC_BEQL:
  769 + case OPC_BNE:
  770 + case OPC_BNEL:
  771 + /* Compare two registers */
  772 + if (rs != rt) {
  773 + GEN_LOAD_REG_TN(T0, rs);
  774 + GEN_LOAD_REG_TN(T1, rt);
  775 + bcond = 1;
  776 + }
  777 + btarget = ctx->pc + 4 + offset;
  778 + break;
  779 + case OPC_BGEZ:
  780 + case OPC_BGEZAL:
  781 + case OPC_BGEZALL:
  782 + case OPC_BGEZL:
  783 + case OPC_BGTZ:
  784 + case OPC_BGTZL:
  785 + case OPC_BLEZ:
  786 + case OPC_BLEZL:
  787 + case OPC_BLTZ:
  788 + case OPC_BLTZAL:
  789 + case OPC_BLTZALL:
  790 + case OPC_BLTZL:
  791 + /* Compare to zero */
  792 + if (rs != 0) {
  793 + gen_op_load_gpr_T0(rs);
  794 + bcond = 1;
  795 + }
  796 + btarget = ctx->pc + 4 + offset;
  797 + break;
  798 + case OPC_J:
  799 + case OPC_JAL:
  800 + /* Jump to immediate */
  801 + btarget = ((ctx->pc + 4) & 0xFF000000) | offset;
  802 + break;
  803 + case OPC_JR:
  804 + case OPC_JALR:
  805 + /* Jump to register */
  806 + if (offset != 0) {
  807 + /* Only hint = 0 is valid */
  808 + generate_exception(ctx, EXCP_RI);
  809 + return;
  810 + }
  811 + GEN_LOAD_REG_TN(T2, rs);
  812 + break;
  813 + default:
  814 + MIPS_INVAL("branch/jump");
  815 + generate_exception(ctx, EXCP_RI);
  816 + return;
  817 + }
  818 + if (bcond == 0) {
  819 + /* No condition to be computed */
  820 + switch (opc) {
  821 + case OPC_BEQ: /* rx == rx */
  822 + case OPC_BEQL: /* rx == rx likely */
  823 + case OPC_BGEZ: /* 0 >= 0 */
  824 + case OPC_BGEZL: /* 0 >= 0 likely */
  825 + case OPC_BLEZ: /* 0 <= 0 */
  826 + case OPC_BLEZL: /* 0 <= 0 likely */
  827 + /* Always take */
  828 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
  829 + MIPS_DEBUG("balways");
  830 + break;
  831 + case OPC_BGEZAL: /* 0 >= 0 */
  832 + case OPC_BGEZALL: /* 0 >= 0 likely */
  833 + /* Always take and link */
  834 + blink = 31;
  835 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
  836 + MIPS_DEBUG("balways and link");
  837 + break;
  838 + case OPC_BNE: /* rx != rx */
  839 + case OPC_BGTZ: /* 0 > 0 */
  840 + case OPC_BLTZ: /* 0 < 0 */
  841 + case OPC_BLTZAL: /* 0 < 0 */
  842 + /* Treated as NOP */
  843 + MIPS_DEBUG("bnever (NOP)");
  844 + return;
  845 + case OPC_BNEL: /* rx != rx likely */
  846 + case OPC_BGTZL: /* 0 > 0 likely */
  847 + case OPC_BLTZALL: /* 0 < 0 likely */
  848 + case OPC_BLTZL: /* 0 < 0 likely */
  849 + /* Skip the instruction in the delay slot */
  850 + MIPS_DEBUG("bnever and skip");
  851 + gen_op_branch((long)ctx->tb, ctx->pc + 4);
  852 + return;
  853 + case OPC_J:
  854 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
  855 + MIPS_DEBUG("j %08x", btarget);
  856 + break;
  857 + case OPC_JAL:
  858 + blink = 31;
  859 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
  860 + MIPS_DEBUG("jal %08x", btarget);
  861 + break;
  862 + case OPC_JR:
  863 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
  864 + MIPS_DEBUG("jr %s", regnames[rs]);
  865 + break;
  866 + case OPC_JALR:
  867 + blink = rt;
  868 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
  869 + MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
  870 + break;
  871 + default:
  872 + MIPS_INVAL("branch/jump");
  873 + generate_exception(ctx, EXCP_RI);
  874 + return;
  875 + }
  876 + } else {
  877 + switch (opc) {
  878 + case OPC_BEQ:
  879 + gen_op_eq();
  880 + MIPS_DEBUG("beq %s, %s, %08x",
  881 + regnames[rs], regnames[rt], btarget);
  882 + goto not_likely;
  883 + case OPC_BEQL:
  884 + gen_op_eq();
  885 + MIPS_DEBUG("beql %s, %s, %08x",
  886 + regnames[rs], regnames[rt], btarget);
  887 + goto likely;
  888 + case OPC_BNE:
  889 + gen_op_ne();
  890 + MIPS_DEBUG("bne %s, %s, %08x",
  891 + regnames[rs], regnames[rt], btarget);
  892 + goto not_likely;
  893 + case OPC_BNEL:
  894 + gen_op_ne();
  895 + MIPS_DEBUG("bnel %s, %s, %08x",
  896 + regnames[rs], regnames[rt], btarget);
  897 + goto likely;
  898 + case OPC_BGEZ:
  899 + gen_op_gez();
  900 + MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
  901 + goto not_likely;
  902 + case OPC_BGEZL:
  903 + gen_op_gez();
  904 + MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
  905 + goto likely;
  906 + case OPC_BGEZAL:
  907 + gen_op_gez();
  908 + MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
  909 + blink = 31;
  910 + goto not_likely;
  911 + case OPC_BGEZALL:
  912 + gen_op_gez();
  913 + blink = 31;
  914 + MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
  915 + goto likely;
  916 + case OPC_BGTZ:
  917 + gen_op_gtz();
  918 + MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
  919 + goto not_likely;
  920 + case OPC_BGTZL:
  921 + gen_op_gtz();
  922 + MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
  923 + goto likely;
  924 + case OPC_BLEZ:
  925 + gen_op_lez();
  926 + MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
  927 + goto not_likely;
  928 + case OPC_BLEZL:
  929 + gen_op_lez();
  930 + MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
  931 + goto likely;
  932 + case OPC_BLTZ:
  933 + gen_op_ltz();
  934 + MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
  935 + goto not_likely;
  936 + case OPC_BLTZL:
  937 + gen_op_ltz();
  938 + MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
  939 + goto likely;
  940 + case OPC_BLTZAL:
  941 + gen_op_ltz();
  942 + blink = 31;
  943 + MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
  944 + not_likely:
  945 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC;
  946 + break;
  947 + case OPC_BLTZALL:
  948 + gen_op_ltz();
  949 + blink = 31;
  950 + MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
  951 + likely:
  952 + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL;
  953 + break;
  954 + }
  955 + gen_op_set_bcond();
  956 + }
  957 + MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
  958 + blink, ctx->hflags, btarget);
  959 + ctx->btarget = btarget;
  960 + if (blink > 0) {
  961 + gen_op_set_T0(ctx->pc + 8);
  962 + gen_op_store_T0_gpr(blink);
  963 + }
  964 + return;
  965 +}
  966 +
  967 +/* CP0 (MMU and control) */
  968 +static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
  969 +{
  970 + const unsigned char *opn = "unk";
  971 +
  972 + if (!(ctx->CP0_Status & (1 << CP0St_CU0))) {
  973 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  974 + fprintf(logfile, "CP0 is not usable\n");
  975 + }
  976 + gen_op_raise_exception_err(EXCP_CpU, 0);
  977 + return;
  978 + }
  979 + switch (opc) {
  980 + case OPC_MFC0:
  981 + if (rt == 0) {
  982 + /* Treat as NOP */
  983 + return;
  984 + }
  985 + gen_op_mfc0(rd, ctx->opcode & 0x7);
  986 + gen_op_store_T0_gpr(rt);
  987 + opn = "mfc0";
  988 + break;
  989 + case OPC_MTC0:
  990 + /* If we get an exception, we want to restart at next instruction */
  991 + ctx->pc += 4;
  992 + save_cpu_state(ctx, 1);
  993 + ctx->pc -= 4;
  994 + GEN_LOAD_REG_TN(T0, rt);
  995 + gen_op_mtc0(rd, ctx->opcode & 0x7);
  996 + /* Stop translation as we may have switched the execution mode */
  997 + ctx->bstate = BS_STOP;
  998 + opn = "mtc0";
  999 + break;
  1000 +#if defined(MIPS_USES_R4K_TLB)
  1001 + case OPC_TLBWI:
  1002 + gen_op_tlbwi();
  1003 + opn = "tlbwi";
  1004 + break;
  1005 + case OPC_TLBWR:
  1006 + gen_op_tlbwr();
  1007 + opn = "tlbwr";
  1008 + break;
  1009 + case OPC_TLBP:
  1010 + gen_op_tlbp();
  1011 + opn = "tlbp";
  1012 + break;
  1013 + case OPC_TLBR:
  1014 + gen_op_tlbr();
  1015 + opn = "tlbr";
  1016 + break;
  1017 +#endif
  1018 + case OPC_ERET:
  1019 + opn = "eret";
  1020 + save_cpu_state(ctx, 0);
  1021 + gen_op_eret();
  1022 + ctx->bstate = BS_EXCP;
  1023 + break;
  1024 + case OPC_DERET:
  1025 + opn = "deret";
  1026 + if (!(ctx->hflags & MIPS_HFLAG_DM)) {
  1027 + generate_exception(ctx, EXCP_RI);
  1028 + } else {
  1029 + save_cpu_state(ctx, 0);
  1030 + gen_op_deret();
  1031 + ctx->bstate = BS_EXCP;
  1032 + }
  1033 + break;
  1034 + /* XXX: TODO: WAIT */
  1035 + default:
  1036 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  1037 + fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
  1038 + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
  1039 + ((ctx->opcode >> 16) & 0x1F));
  1040 + }
  1041 + generate_exception(ctx, EXCP_RI);
  1042 + return;
  1043 + }
  1044 + MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
  1045 +}
  1046 +
  1047 +/* Coprocessor 1 (FPU) */
  1048 +
  1049 +/* ISA extensions */
  1050 +/* MIPS16 extension to MIPS32 */
  1051 +/* SmartMIPS extension to MIPS32 */
  1052 +
  1053 +#ifdef TARGET_MIPS64
  1054 +static void gen_arith64 (DisasContext *ctx, uint16_t opc)
  1055 +{
  1056 + if (func == 0x02 && rd == 0) {
  1057 + /* NOP */
  1058 + return;
  1059 + }
  1060 + if (rs == 0 || rt == 0) {
  1061 + gen_op_reset_T0();
  1062 + gen_op_save64();
  1063 + } else {
  1064 + gen_op_load_gpr_T0(rs);
  1065 + gen_op_load_gpr_T1(rt);
  1066 + gen_op_save64();
  1067 + if (func & 0x01)
  1068 + gen_op_mul64u();
  1069 + else
  1070 + gen_op_mul64s();
  1071 + }
  1072 + if (func & 0x02)
  1073 + gen_op_add64();
  1074 + else
  1075 + gen_op_sub64();
  1076 +}
  1077 +
  1078 +/* Coprocessor 3 (FPU) */
  1079 +
  1080 +/* MDMX extension to MIPS64 */
  1081 +/* MIPS-3D extension to MIPS64 */
  1082 +
  1083 +#endif
  1084 +
  1085 +static void decode_opc (DisasContext *ctx)
  1086 +{
  1087 + int32_t offset;
  1088 + int rs, rt, rd, sa;
  1089 + uint16_t op, op1;
  1090 + int16_t imm;
  1091 +
  1092 + if ((ctx->hflags & MIPS_HFLAG_DS) &&
  1093 + (ctx->hflags & MIPS_HFLAG_BL)) {
  1094 + /* Handle blikely not taken case */
  1095 + MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
  1096 + gen_op_blikely((long)ctx->tb, ctx->pc + 4,
  1097 + ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS));
  1098 + }
  1099 + op = ctx->opcode >> 26;
  1100 + rs = ((ctx->opcode >> 21) & 0x1F);
  1101 + rt = ((ctx->opcode >> 16) & 0x1F);
  1102 + rd = ((ctx->opcode >> 11) & 0x1F);
  1103 + sa = ((ctx->opcode >> 6) & 0x1F);
  1104 + imm = (int16_t)ctx->opcode;
  1105 + switch (op) {
  1106 + case 0x00: /* Special opcode */
  1107 + op1 = ctx->opcode & 0x3F;
  1108 + switch (op1) {
  1109 + case 0x00: /* Arithmetic with immediate */
  1110 + case 0x02 ... 0x03:
  1111 + gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
  1112 + break;
  1113 + case 0x04: /* Arithmetic */
  1114 + case 0x06 ... 0x07:
  1115 + case 0x0A ... 0x0B:
  1116 + case 0x20 ... 0x27:
  1117 + case 0x2A ... 0x2B:
  1118 + gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
  1119 + break;
  1120 + case 0x18 ... 0x1B: /* MULT / DIV */
  1121 + gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
  1122 + break;
  1123 + case 0x08 ... 0x09: /* Jumps */
  1124 + gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
  1125 + return;
  1126 + case 0x30 ... 0x34: /* Traps */
  1127 + case 0x36:
  1128 + gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
  1129 + break;
  1130 + case 0x10: /* Move from HI/LO */
  1131 + case 0x12:
  1132 + gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
  1133 + break;
  1134 + case 0x11:
  1135 + case 0x13: /* Move to HI/LO */
  1136 + gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
  1137 + break;
  1138 + case 0x0C: /* SYSCALL */
  1139 + generate_exception(ctx, EXCP_SYSCALL);
  1140 + break;
  1141 + case 0x0D: /* BREAK */
  1142 + generate_exception(ctx, EXCP_BREAK);
  1143 + break;
  1144 + case 0x0F: /* SYNC */
  1145 + /* Treat as a noop */
  1146 + break;
  1147 + case 0x05: /* Pmon entry point */
  1148 + gen_op_pmon((ctx->opcode >> 6) & 0x1F);
  1149 + break;
  1150 +#if defined (MIPS_HAS_MOVCI)
  1151 + case 0x01: /* MOVCI */
  1152 +#endif
  1153 +#if defined (TARGET_MIPS64)
  1154 + case 0x14: /* MIPS64 specific opcodes */
  1155 + case 0x16:
  1156 + case 0x17:
  1157 + case 0x1C ... 0x1F:
  1158 + case 0x2C ... 0x2F:
  1159 + case 0x37:
  1160 + case 0x39 ... 0x3B:
  1161 + case 0x3E ... 0x3F:
  1162 +#endif
  1163 + default: /* Invalid */
  1164 + MIPS_INVAL("special");
  1165 + generate_exception(ctx, EXCP_RI);
  1166 + break;
  1167 + }
  1168 + break;
  1169 + case 0x1C: /* Special2 opcode */
  1170 + op1 = ctx->opcode & 0x3F;
  1171 + switch (op1) {
  1172 +#if defined (MIPS_USES_R4K_EXT)
  1173 + /* Those instructions are not part of MIPS32 core */
  1174 + case 0x00 ... 0x01: /* Multiply and add/sub */
  1175 + case 0x04 ... 0x05:
  1176 + gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
  1177 + break;
  1178 + case 0x02: /* MUL */
  1179 + gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
  1180 + break;
  1181 + case 0x20 ... 0x21: /* CLO / CLZ */
  1182 + gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
  1183 + break;
  1184 +#endif
  1185 + case 0x3F: /* SDBBP */
  1186 + /* XXX: not clear which exception should be raised
  1187 + * when in debug mode...
  1188 + */
  1189 + if (!(ctx->hflags & MIPS_HFLAG_DM)) {
  1190 + generate_exception(ctx, EXCP_DBp);
  1191 + } else {
  1192 + generate_exception(ctx, EXCP_DBp);
  1193 + }
  1194 + /* Treat as a noop */
  1195 + break;
  1196 + default: /* Invalid */
  1197 + MIPS_INVAL("special2");
  1198 + generate_exception(ctx, EXCP_RI);
  1199 + break;
  1200 + }
  1201 + break;
  1202 + case 0x01: /* B REGIMM opcode */
  1203 + op1 = ((ctx->opcode >> 16) & 0x1F);
  1204 + switch (op1) {
  1205 + case 0x00 ... 0x03: /* REGIMM branches */
  1206 + case 0x10 ... 0x13:
  1207 + gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
  1208 + return;
  1209 + case 0x08 ... 0x0C: /* Traps */
  1210 + case 0x0E:
  1211 + gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
  1212 + break;
  1213 + default: /* Invalid */
  1214 + MIPS_INVAL("REGIMM");
  1215 + generate_exception(ctx, EXCP_RI);
  1216 + break;
  1217 + }
  1218 + break;
  1219 + case 0x10: /* CP0 opcode */
  1220 + op1 = ((ctx->opcode >> 21) & 0x1F);
  1221 + switch (op1) {
  1222 + case 0x00:
  1223 + case 0x04:
  1224 + gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
  1225 + break;
  1226 + default:
  1227 + gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd);
  1228 + break;
  1229 + }
  1230 + break;
  1231 + case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
  1232 + gen_arith_imm(ctx, op, rt, rs, imm);
  1233 + break;
  1234 + case 0x02 ... 0x03: /* Jump */
  1235 + offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
  1236 + gen_compute_branch(ctx, op, rs, rt, offset);
  1237 + return;
  1238 + case 0x04 ... 0x07: /* Branch */
  1239 + case 0x14 ... 0x17:
  1240 + gen_compute_branch(ctx, op, rs, rt, imm << 2);
  1241 + return;
  1242 + case 0x20 ... 0x26: /* Load and stores */
  1243 + case 0x28 ... 0x2E:
  1244 + case 0x30:
  1245 + case 0x38:
  1246 + gen_ldst(ctx, op, rt, rs, imm);
  1247 + break;
  1248 + case 0x2F: /* Cache operation */
  1249 + /* Treat as a noop */
  1250 + break;
  1251 + case 0x33: /* Prefetch */
  1252 + /* Treat as a noop */
  1253 + break;
  1254 + case 0x3F: /* HACK */
  1255 + break;
  1256 +#if defined(MIPS_USES_FPU)
  1257 + case 0x31 ... 0x32: /* Floating point load/store */
  1258 + case 0x35 ... 0x36:
  1259 + case 0x3A ... 0x3B:
  1260 + case 0x3D ... 0x3E:
  1261 + /* Not implemented */
  1262 + /* XXX: not correct */
  1263 +#endif
  1264 + case 0x11: /* CP1 opcode */
  1265 + /* Not implemented */
  1266 + /* XXX: not correct */
  1267 + case 0x12: /* CP2 opcode */
  1268 + /* Not implemented */
  1269 + /* XXX: not correct */
  1270 + case 0x13: /* CP3 opcode */
  1271 + /* Not implemented */
  1272 + /* XXX: not correct */
  1273 +#if defined (TARGET_MIPS64)
  1274 + case 0x18 ... 0x1B:
  1275 + case 0x27:
  1276 + case 0x34:
  1277 + case 0x37:
  1278 + /* MIPS64 opcodes */
  1279 +#endif
  1280 +#if defined (MIPS_HAS_JALX)
  1281 + case 0x1D:
  1282 + /* JALX: not implemented */
  1283 +#endif
  1284 + case 0x1E:
  1285 + /* ASE specific */
  1286 +#if defined (MIPS_HAS_LSC)
  1287 + case 0x31: /* LWC1 */
  1288 + case 0x32: /* LWC2 */
  1289 + case 0x35: /* SDC1 */
  1290 + case 0x36: /* SDC2 */
  1291 +#endif
  1292 + default: /* Invalid */
  1293 + MIPS_INVAL("");
  1294 + generate_exception(ctx, EXCP_RI);
  1295 + break;
  1296 + }
  1297 + if (ctx->hflags & MIPS_HFLAG_DS) {
  1298 + int hflags = ctx->hflags;
  1299 + /* Branches completion */
  1300 + ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS);
  1301 + ctx->bstate = BS_BRANCH;
  1302 + save_cpu_state(ctx, 0);
  1303 + switch (hflags & MIPS_HFLAG_BMASK) {
  1304 + case MIPS_HFLAG_B:
  1305 + /* unconditional branch */
  1306 + MIPS_DEBUG("unconditional branch");
  1307 + gen_op_branch((long)ctx->tb, ctx->btarget);
  1308 + break;
  1309 + case MIPS_HFLAG_BL:
  1310 + /* blikely taken case */
  1311 + MIPS_DEBUG("blikely branch taken");
  1312 + gen_op_branch((long)ctx->tb, ctx->btarget);
  1313 + break;
  1314 + case MIPS_HFLAG_BC:
  1315 + /* Conditional branch */
  1316 + MIPS_DEBUG("conditional branch");
  1317 + gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4);
  1318 + break;
  1319 + case MIPS_HFLAG_BR:
  1320 + /* unconditional branch to register */
  1321 + MIPS_DEBUG("branch to register");
  1322 + gen_op_breg();
  1323 + break;
  1324 + default:
  1325 + MIPS_DEBUG("unknown branch");
  1326 + break;
  1327 + }
  1328 + }
  1329 +}
  1330 +
  1331 +int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
  1332 + int search_pc)
  1333 +{
  1334 + DisasContext ctx, *ctxp = &ctx;
  1335 + target_ulong pc_start;
  1336 + uint16_t *gen_opc_end;
  1337 + int j, lj = -1;
  1338 +
  1339 + pc_start = tb->pc;
  1340 + gen_opc_ptr = gen_opc_buf;
  1341 + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
  1342 + gen_opparam_ptr = gen_opparam_buf;
  1343 + ctx.pc = pc_start;
  1344 + ctx.tb = tb;
  1345 + ctx.bstate = BS_NONE;
  1346 + /* Restore delay slot state */
  1347 + ctx.hflags = env->hflags;
  1348 + ctx.saved_hflags = ctx.hflags;
  1349 + if (ctx.hflags & MIPS_HFLAG_BR) {
  1350 + gen_op_restore_breg_target();
  1351 + } else if (ctx.hflags & MIPS_HFLAG_B) {
  1352 + ctx.btarget = env->btarget;
  1353 + } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
  1354 + /* If we are in the delay slot of a conditional branch,
  1355 + * restore the branch condition from env->bcond to T2
  1356 + */
  1357 + ctx.btarget = env->btarget;
  1358 + gen_op_restore_bcond();
  1359 + }
  1360 +#if defined(CONFIG_USER_ONLY)
  1361 + ctx.mem_idx = 0;
  1362 +#else
  1363 + ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1;
  1364 +#endif
  1365 + ctx.CP0_Status = env->CP0_Status;
  1366 +#ifdef DEBUG_DISAS
  1367 + if (loglevel & CPU_LOG_TB_CPU) {
  1368 + fprintf(logfile, "------------------------------------------------\n");
  1369 + cpu_dump_state(env, logfile, fprintf, 0);
  1370 + }
  1371 +#endif
  1372 +#if defined MIPS_DEBUG_DISAS
  1373 + if (loglevel & CPU_LOG_TB_IN_ASM)
  1374 + fprintf(logfile, "\ntb %p super %d cond %04x %04x\n",
  1375 + tb, ctx.mem_idx, ctx.hflags, env->hflags);
  1376 +#endif
  1377 + while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
  1378 + if (search_pc) {
  1379 + j = gen_opc_ptr - gen_opc_buf;
  1380 + save_cpu_state(ctxp, 1);
  1381 + if (lj < j) {
  1382 + lj++;
  1383 + while (lj < j)
  1384 + gen_opc_instr_start[lj++] = 0;
  1385 + gen_opc_pc[lj] = ctx.pc;
  1386 + gen_opc_instr_start[lj] = 1;
  1387 + }
  1388 + }
  1389 + ctx.opcode = ldl_code(ctx.pc);
  1390 + decode_opc(&ctx);
  1391 + ctx.pc += 4;
  1392 + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
  1393 + break;
  1394 +#if defined (MIPS_SINGLE_STEP)
  1395 + break;
  1396 +#endif
  1397 + }
  1398 + if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
  1399 + save_cpu_state(ctxp, 0);
  1400 + gen_op_branch((long)ctx.tb, ctx.pc);
  1401 + }
  1402 + gen_op_reset_T0();
  1403 + /* Generate the return instruction */
  1404 + gen_op_exit_tb();
  1405 + *gen_opc_ptr = INDEX_op_end;
  1406 + if (search_pc) {
  1407 + j = gen_opc_ptr - gen_opc_buf;
  1408 + lj++;
  1409 + while (lj <= j)
  1410 + gen_opc_instr_start[lj++] = 0;
  1411 + tb->size = 0;
  1412 + } else {
  1413 + tb->size = ctx.pc - pc_start;
  1414 + }
  1415 +#ifdef DEBUG_DISAS
  1416 +#if defined MIPS_DEBUG_DISAS
  1417 + if (loglevel & CPU_LOG_TB_IN_ASM)
  1418 + fprintf(logfile, "\n");
  1419 +#endif
  1420 + if (loglevel & CPU_LOG_TB_IN_ASM) {
  1421 + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
  1422 + target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
  1423 + fprintf(logfile, "\n");
  1424 + }
  1425 + if (loglevel & CPU_LOG_TB_OP) {
  1426 + fprintf(logfile, "OP:\n");
  1427 + dump_ops(gen_opc_buf, gen_opparam_buf);
  1428 + fprintf(logfile, "\n");
  1429 + }
  1430 + if (loglevel & CPU_LOG_TB_CPU) {
  1431 + fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
  1432 + }
  1433 +#endif
  1434 +
  1435 + return 0;
  1436 +}
  1437 +
  1438 +int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
  1439 +{
  1440 + return gen_intermediate_code_internal(env, tb, 0);
  1441 +}
  1442 +
  1443 +int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
  1444 +{
  1445 + return gen_intermediate_code_internal(env, tb, 1);
  1446 +}
  1447 +
  1448 +void cpu_dump_state (CPUState *env, FILE *f,
  1449 + int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
  1450 + int flags)
  1451 +{
  1452 + int i;
  1453 +
  1454 + cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
  1455 + env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
  1456 + for (i = 0; i < 32; i++) {
  1457 + if ((i & 3) == 0)
  1458 + cpu_fprintf(f, "GPR%02d:", i);
  1459 + cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
  1460 + if ((i & 3) == 3)
  1461 + cpu_fprintf(f, "\n");
  1462 + }
  1463 + cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n",
  1464 + env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
  1465 + cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
  1466 + env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
  1467 +}
  1468 +
  1469 +CPUMIPSState *cpu_mips_init (void)
  1470 +{
  1471 + CPUMIPSState *env;
  1472 +
  1473 + cpu_exec_init();
  1474 + env = qemu_mallocz(sizeof(CPUMIPSState));
  1475 + if (!env)
  1476 + return NULL;
  1477 + tlb_flush(env, 1);
  1478 + /* Minimal init */
  1479 + env->PC = 0xBFC00000;
  1480 +#if defined (MIPS_USES_R4K_TLB)
  1481 + env->CP0_random = MIPS_TLB_NB - 1;
  1482 +#endif
  1483 + env->CP0_Wired = 0;
  1484 + env->CP0_Config0 = MIPS_CONFIG0;
  1485 +#if defined (MIPS_CONFIG1)
  1486 + env->CP0_Config1 = MIPS_CONFIG1;
  1487 +#endif
  1488 +#if defined (MIPS_CONFIG2)
  1489 + env->CP0_Config2 = MIPS_CONFIG2;
  1490 +#endif
  1491 +#if defined (MIPS_CONFIG3)
  1492 + env->CP0_Config3 = MIPS_CONFIG3;
  1493 +#endif
  1494 + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
  1495 + env->CP0_WatchLo = 0;
  1496 + env->hflags = MIPS_HFLAG_ERL;
  1497 + /* Count register increments in debug mode, EJTAG version 1 */
  1498 + env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
  1499 + env->CP0_PRid = MIPS_CPU;
  1500 + env->exception_index = EXCP_NONE;
  1501 +
  1502 + cpu_single_env = env;
  1503 +
  1504 + return env;
  1505 +}
... ...
translate-all.c
... ... @@ -300,6 +300,8 @@ int cpu_restore_state(TranslationBlock *tb,
300 300 }
301 301 env->access_type = type;
302 302 }
  303 +#elif defined(TARGET_MIPS)
  304 + env->PC = gen_opc_pc[j];
303 305 #endif
304 306 return 0;
305 307 }
... ...
... ... @@ -2348,6 +2348,17 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
2348 2348 {
2349 2349 return 0;
2350 2350 }
  2351 +
  2352 +#elif defined(TARGET_MIPS)
  2353 +void cpu_save(QEMUFile *f, void *opaque)
  2354 +{
  2355 +}
  2356 +
  2357 +int cpu_load(QEMUFile *f, void *opaque, int version_id)
  2358 +{
  2359 + return 0;
  2360 +}
  2361 +
2351 2362 #elif defined(TARGET_SPARC)
2352 2363 void cpu_save(QEMUFile *f, void *opaque)
2353 2364 {
... ... @@ -3058,6 +3069,8 @@ void register_machines(void)
3058 3069 qemu_register_machine(&heathrow_machine);
3059 3070 qemu_register_machine(&core99_machine);
3060 3071 qemu_register_machine(&prep_machine);
  3072 +#elif defined(TARGET_MIPS)
  3073 + qemu_register_machine(&mips_machine);
3061 3074 #elif defined(TARGET_SPARC)
3062 3075 #ifdef TARGET_SPARC64
3063 3076 qemu_register_machine(&sun4u_machine);
... ...
... ... @@ -138,6 +138,8 @@ extern int win2k_install_hack;
138 138 /* XXX: make it dynamic */
139 139 #if defined (TARGET_PPC)
140 140 #define BIOS_SIZE (512 * 1024)
  141 +#elif defined(TARGET_MIPS)
  142 +#define BIOS_SIZE (128 * 1024)
141 143 #else
142 144 #define BIOS_SIZE ((256 + 64) * 1024)
143 145 #endif
... ... @@ -715,6 +717,9 @@ extern QEMUMachine prep_machine;
715 717 extern QEMUMachine core99_machine;
716 718 extern QEMUMachine heathrow_machine;
717 719  
  720 +/* mips_r4k.c */
  721 +extern QEMUMachine mips_machine;
  722 +
718 723 #ifdef TARGET_PPC
719 724 ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
720 725 #endif
... ...