summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--block/raw-posix.c16
-rwxr-xr-xconfigure13
-rw-r--r--exec-all.h6
-rw-r--r--exec.c2
-rw-r--r--fpu/softfloat-native.c2
-rw-r--r--fpu/softfloat-native.h6
-rw-r--r--net.c5
-rw-r--r--net/tap-bsd.c7
-rw-r--r--qemu-char.c18
-rw-r--r--savevm.c5
-rw-r--r--target-mips/cpu.h2
-rw-r--r--target-mips/helper.c122
-rw-r--r--target-mips/helper.h9
-rw-r--r--target-mips/op_helper.c291
-rw-r--r--target-mips/translate.c41
-rw-r--r--tcg/mips/tcg-target.c1342
-rw-r--r--tcg/mips/tcg-target.h104
-rw-r--r--usb-bsd.c4
-rw-r--r--vl.c8
19 files changed, 1733 insertions, 270 deletions
diff --git a/block/raw-posix.c b/block/raw-posix.c
index f558976845..266d8415dc 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -51,7 +51,7 @@
 #include <linux/cdrom.h>
 #include <linux/fd.h>
 #endif
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <signal.h>
 #include <sys/disk.h>
 #include <sys/cdio.h>
@@ -124,7 +124,7 @@ typedef struct BDRVRawState {
 static int fd_open(BlockDriverState *bs);
 static int64_t raw_getlength(BlockDriverState *bs);
 
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int cdrom_reopen(BlockDriverState *bs);
 #endif
 
@@ -636,7 +636,7 @@ static int64_t  raw_getlength(BlockDriverState *bs)
     int64_t size;
 #ifdef CONFIG_BSD
     struct stat sb;
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
     int reopened = 0;
 #endif
 #endif
@@ -651,7 +651,7 @@ static int64_t  raw_getlength(BlockDriverState *bs)
         return ret;
 
 #ifdef CONFIG_BSD
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 again:
 #endif
     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
@@ -672,7 +672,7 @@ again:
 #else
         size = lseek(fd, 0LL, SEEK_END);
 #endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
         switch(s->type) {
         case FTYPE_CD:
             /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
@@ -957,7 +957,7 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
     return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
 }
 
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int fd_open(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
@@ -1213,7 +1213,7 @@ static BlockDriver bdrv_host_cdrom = {
 };
 #endif /* __linux__ */
 
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
@@ -1342,7 +1342,7 @@ static void bdrv_raw_init(void)
     bdrv_register(&bdrv_host_floppy);
     bdrv_register(&bdrv_host_cdrom);
 #endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
     bdrv_register(&bdrv_host_cdrom);
 #endif
 }
diff --git a/configure b/configure
index 1223fc8293..dca5a430f6 100755
--- a/configure
+++ b/configure
@@ -134,13 +134,15 @@ elif check_define _ARCH_PPC ; then
   else
     cpu="ppc"
   fi
+elif check_define __mips__ ; then
+  cpu="mips"
 else
   cpu=`uname -m`
 fi
 
 target_list=""
 case "$cpu" in
-  alpha|cris|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|sparc64)
+  alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
     cpu="$cpu"
   ;;
   i386|i486|i586|i686|i86pc|BePC)
@@ -158,6 +160,9 @@ case "$cpu" in
   parisc|parisc64)
     cpu="hppa"
   ;;
+  mips*)
+    cpu="mips"
+  ;;
   s390*)
     cpu="s390"
   ;;
@@ -255,27 +260,32 @@ MINGW32*)
   audio_drv_list="winwave"
 ;;
 GNU/kFreeBSD)
+  bsd="yes"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
 ;;
 FreeBSD)
   bsd="yes"
+  make="gmake"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
 ;;
 DragonFly)
   bsd="yes"
+  make="gmake"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
 ;;
 NetBSD)
   bsd="yes"
+  make="gmake"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd"
   oss_lib="-lossaudio"
 ;;
 OpenBSD)
   bsd="yes"
+  make="gmake"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd"
   oss_lib="-lossaudio"
@@ -360,7 +370,6 @@ esac
 
 if [ "$bsd" = "yes" ] ; then
   if [ "$darwin" != "yes" ] ; then
-    make="gmake"
     usb="bsd"
   fi
   bsd_user="yes"
diff --git a/exec-all.h b/exec-all.h
index dd134a99f8..820b59eea6 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -41,10 +41,10 @@ typedef struct TranslationBlock TranslationBlock;
 #define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
 
 /* Maximum size a TCG op can expand to.  This is complicated because a
-   single op may require several host instructions and regirster reloads.
-   For now take a wild guess at 128 bytes, which should allow at least
+   single op may require several host instructions and register reloads.
+   For now take a wild guess at 192 bytes, which should allow at least
    a couple of fixup instructions per argument.  */
-#define TCG_MAX_OP_SIZE 128
+#define TCG_MAX_OP_SIZE 192
 
 #define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM)
 
diff --git a/exec.c b/exec.c
index 076d26b5ba..eb1ee51fa4 100644
--- a/exec.c
+++ b/exec.c
@@ -463,7 +463,7 @@ static void code_gen_alloc(unsigned long tb_size)
             exit(1);
         }
     }
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
     {
         int flags;
         void *addr = NULL;
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index 4c70b6c4f7..8d64f4eff4 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -9,7 +9,7 @@
 void set_float_rounding_mode(int val STATUS_PARAM)
 {
     STATUS(float_rounding_mode) = val;
-#if defined(CONFIG_BSD) && !defined(__APPLE__) ||         \
+#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) || \
     (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
     fpsetround(val);
 #elif defined(__arm__)
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 0893ce36ff..35670c80d1 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -1,7 +1,8 @@
 /* Native implementation of soft float functions */
 #include <math.h>
 
-#if (defined(CONFIG_BSD) && !defined(__APPLE__)) || defined(CONFIG_SOLARIS)
+#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \
+    || defined(CONFIG_SOLARIS)
 #include <ieeefp.h>
 #define fabsf(f) ((float)fabs(f))
 #else
@@ -112,7 +113,8 @@ typedef union {
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE floating-point rounding mode.
 *----------------------------------------------------------------------------*/
-#if (defined(CONFIG_BSD) && !defined(__APPLE__)) || defined(CONFIG_SOLARIS)
+#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \
+    || defined(CONFIG_SOLARIS)
 #if defined(__OpenBSD__)
 #define FE_RM FP_RM
 #define FE_RP FP_RP
diff --git a/net.c b/net.c
index 9ea66e36fa..7c44c1ad5f 100644
--- a/net.c
+++ b/net.c
@@ -48,14 +48,11 @@
 #include <sys/select.h>
 #ifdef CONFIG_BSD
 #include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #include <libutil.h>
 #else
 #include <util.h>
 #endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
-#else
 #ifdef __linux__
 #include <pty.h>
 #include <malloc.h>
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index 0f8ad4ad71..815997dc7b 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -30,14 +30,11 @@
 #include <net/if_tap.h>
 #endif
 
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #include <libutil.h>
 #else
 #include <util.h>
 #endif
-#if defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
-#endif
 
 #if defined(__OpenBSD__)
 #include <util.h>
@@ -49,7 +46,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
     char *dev;
     struct stat s;
 
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
     /* if no ifname is given, always start the search from tap0. */
     int i;
     char dname[100];
diff --git a/qemu-char.c b/qemu-char.c
index 5a81e8f5f3..e202585fdf 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -57,10 +57,13 @@
 #include <sys/select.h>
 #ifdef CONFIG_BSD
 #include <sys/stat.h>
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <libutil.h>
 #include <dev/ppbus/ppi.h>
 #include <dev/ppbus/ppbconf.h>
+#if defined(__GLIBC__)
+#include <pty.h>
+#endif
 #elif defined(__DragonFly__)
 #include <libutil.h>
 #include <dev/misc/ppi/ppi.h>
@@ -68,8 +71,6 @@
 #else
 #include <util.h>
 #endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
 #else
 #ifdef __linux__
 #include <pty.h>
@@ -820,7 +821,8 @@ static void cfmakeraw (struct termios *termios_p)
 #endif
 
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__GLIBC__)
 
 typedef struct {
     int fd;
@@ -1336,7 +1338,7 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 }
 #endif /* __linux__ */
 
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
     int fd = (int)chr->opaque;
@@ -2380,10 +2382,12 @@ static const struct {
     { .name = "braille",   .open = chr_baum_init },
 #endif
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
+    || defined(__FreeBSD_kernel__)
     { .name = "tty",       .open = qemu_chr_open_tty },
 #endif
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \
+    || defined(__FreeBSD_kernel__)
     { .name = "parport",   .open = qemu_chr_open_pp },
 #endif
 };
diff --git a/savevm.c b/savevm.c
index 4668843c3f..18c2e5486e 100644
--- a/savevm.c
+++ b/savevm.c
@@ -48,14 +48,11 @@
 #include <sys/select.h>
 #ifdef CONFIG_BSD
 #include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #include <libutil.h>
 #else
 #include <util.h>
 #endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
-#else
 #ifdef __linux__
 #include <pty.h>
 #include <malloc.h>
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 82f9a38164..97e106f47a 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -590,6 +590,8 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
 void do_interrupt (CPUState *env);
 void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
+target_phys_addr_t do_translate_address (CPUState *env, target_ulong address,
+		                         int rw);
 
 static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
 {
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 4a372777c7..1e7e016084 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -201,6 +201,58 @@ static int get_physical_address (CPUState *env, target_phys_addr_t *physical,
 }
 #endif
 
+static void raise_mmu_exception(CPUState *env, target_ulong address,
+                                int rw, int tlb_error)
+{
+    int exception = 0, error_code = 0;
+
+    switch (tlb_error) {
+    default:
+    case TLBRET_BADADDR:
+        /* Reference to kernel address from user mode or supervisor mode */
+        /* Reference to supervisor address from user mode */
+        if (rw)
+            exception = EXCP_AdES;
+        else
+            exception = EXCP_AdEL;
+        break;
+    case TLBRET_NOMATCH:
+        /* No TLB match for a mapped address */
+        if (rw)
+            exception = EXCP_TLBS;
+        else
+            exception = EXCP_TLBL;
+        error_code = 1;
+        break;
+    case TLBRET_INVALID:
+        /* TLB match with no valid bit */
+        if (rw)
+            exception = EXCP_TLBS;
+        else
+            exception = EXCP_TLBL;
+        break;
+    case TLBRET_DIRTY:
+        /* TLB match but 'D' bit is cleared */
+        exception = EXCP_LTLBL;
+        break;
+
+    }
+    /* Raise exception */
+    env->CP0_BadVAddr = address;
+    env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
+                       ((address >> 9) & 0x007ffff0);
+    env->CP0_EntryHi =
+        (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
+#if defined(TARGET_MIPS64)
+    env->CP0_EntryHi &= env->SEGMask;
+    env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
+                        ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
+                        ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
+#endif
+    env->exception_index = exception;
+    env->error_code = error_code;
+}
+
 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
 #if defined(CONFIG_USER_ONLY)
@@ -222,7 +274,6 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     target_phys_addr_t physical;
     int prot;
 #endif
-    int exception = 0, error_code = 0;
     int access_type;
     int ret = 0;
 
@@ -252,57 +303,36 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     } else if (ret < 0)
 #endif
     {
-        switch (ret) {
-        default:
-        case TLBRET_BADADDR:
-            /* Reference to kernel address from user mode or supervisor mode */
-            /* Reference to supervisor address from user mode */
-            if (rw)
-                exception = EXCP_AdES;
-            else
-                exception = EXCP_AdEL;
-            break;
-        case TLBRET_NOMATCH:
-            /* No TLB match for a mapped address */
-            if (rw)
-                exception = EXCP_TLBS;
-            else
-                exception = EXCP_TLBL;
-            error_code = 1;
-            break;
-        case TLBRET_INVALID:
-            /* TLB match with no valid bit */
-            if (rw)
-                exception = EXCP_TLBS;
-            else
-                exception = EXCP_TLBL;
-            break;
-        case TLBRET_DIRTY:
-            /* TLB match but 'D' bit is cleared */
-            exception = EXCP_LTLBL;
-            break;
-
-        }
-        /* Raise exception */
-        env->CP0_BadVAddr = address;
-        env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
-                           ((address >> 9) &   0x007ffff0);
-        env->CP0_EntryHi =
-            (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
-#if defined(TARGET_MIPS64)
-        env->CP0_EntryHi &= env->SEGMask;
-        env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
-                            ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
-                            ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
-#endif
-        env->exception_index = exception;
-        env->error_code = error_code;
+        raise_mmu_exception(env, address, rw, ret);
         ret = 1;
     }
 
     return ret;
 }
 
+#if !defined(CONFIG_USER_ONLY)
+target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int rw)
+{
+    target_phys_addr_t physical;
+    int prot;
+    int access_type;
+    int ret = 0;
+
+    rw &= 1;
+
+    /* data access */
+    access_type = ACCESS_INT;
+    ret = get_physical_address(env, &physical, &prot,
+                               address, rw, access_type);
+    if (ret != TLBRET_MATCH) {
+        raise_mmu_exception(env, address, rw, ret);
+        cpu_loop_exit();
+    }
+
+    return physical;
+}
+#endif
+
 static const char * const excp_names[EXCP_LAST + 1] = {
     [EXCP_RESET] = "reset",
     [EXCP_SRESET] = "soft reset",
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 4f1de5193f..ab47b1a3ab 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -15,6 +15,15 @@ DEF_HELPER_3(lwr, tl, tl, tl, int)
 DEF_HELPER_3(swl, void, tl, tl, int)
 DEF_HELPER_3(swr, void, tl, tl, int)
 
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_2(ll, tl, tl, int)
+DEF_HELPER_3(sc, tl, tl, tl, int)
+#ifdef TARGET_MIPS64
+DEF_HELPER_2(lld, tl, tl, int)
+DEF_HELPER_3(scd, tl, tl, tl, int)
+#endif
+#endif
+
 DEF_HELPER_FLAGS_1(clo, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 #ifdef TARGET_MIPS64
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 52d687d337..be75af5e6e 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -66,6 +66,58 @@ static void do_restore_state (void *pc_ptr)
 }
 #endif
 
+#if defined(CONFIG_USER_ONLY)
+#define HELPER_LD(name, insn, type)                                     \
+static inline type do_##name(target_ulong addr, int mem_idx)            \
+{                                                                       \
+    return (type) insn##_raw(addr);                                     \
+}
+#else
+#define HELPER_LD(name, insn, type)                                     \
+static inline type do_##name(target_ulong addr, int mem_idx)            \
+{                                                                       \
+    switch (mem_idx)                                                    \
+    {                                                                   \
+    case 0: return (type) insn##_kernel(addr); break;                   \
+    case 1: return (type) insn##_super(addr); break;                    \
+    default:                                                            \
+    case 2: return (type) insn##_user(addr); break;                     \
+    }                                                                   \
+}
+#endif
+HELPER_LD(lbu, ldub, uint8_t)
+HELPER_LD(lw, ldl, int32_t)
+#ifdef TARGET_MIPS64
+HELPER_LD(ld, ldq, int64_t)
+#endif
+#undef HELPER_LD
+
+#if defined(CONFIG_USER_ONLY)
+#define HELPER_ST(name, insn, type)                                     \
+static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
+{                                                                       \
+    insn##_raw(addr, val);                                              \
+}
+#else
+#define HELPER_ST(name, insn, type)                                     \
+static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
+{                                                                       \
+    switch (mem_idx)                                                    \
+    {                                                                   \
+    case 0: insn##_kernel(addr, val); break;                            \
+    case 1: insn##_super(addr, val); break;                             \
+    default:                                                            \
+    case 2: insn##_user(addr, val); break;                              \
+    }                                                                   \
+}
+#endif
+HELPER_ST(sb, stb, uint8_t)
+HELPER_ST(sw, stl, uint32_t)
+#ifdef TARGET_MIPS64
+HELPER_ST(sd, stq, uint64_t)
+#endif
+#undef HELPER_ST
+
 target_ulong helper_clo (target_ulong arg1)
 {
     return clo32(arg1);
@@ -223,6 +275,45 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2)
 }
 #endif
 
+#ifndef CONFIG_USER_ONLY
+#define HELPER_LD_ATOMIC(name, insn)                                          \
+target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
+{                                                                             \
+    env->lladdr = do_translate_address(env, arg, 0);                          \
+    env->llval = do_##insn(arg, mem_idx);                                     \
+    return env->llval;                                                        \
+}
+HELPER_LD_ATOMIC(ll, lw)
+#ifdef TARGET_MIPS64
+HELPER_LD_ATOMIC(lld, ld)
+#endif
+#undef HELPER_LD_ATOMIC
+
+#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
+target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
+{                                                                             \
+    target_long tmp;                                                          \
+                                                                              \
+    if (arg2 & almask) {                                                      \
+        env->CP0_BadVAddr = arg2;                                             \
+        helper_raise_exception(EXCP_AdES);                                    \
+    }                                                                         \
+    if (do_translate_address(env, arg2, 1) == env->lladdr) {                  \
+        tmp = do_##ld_insn(arg2, mem_idx);                                    \
+        if (tmp == env->llval) {                                              \
+            do_##st_insn(arg2, arg1, mem_idx);                                \
+            return 1;                                                         \
+        }                                                                     \
+    }                                                                         \
+    return 0;                                                                 \
+}
+HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
+#ifdef TARGET_MIPS64
+HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
+#endif
+#undef HELPER_ST_ATOMIC
+#endif
+
 #ifdef TARGET_WORDS_BIGENDIAN
 #define GET_LMASK(v) ((v) & 3)
 #define GET_OFFSET(addr, offset) (addr + (offset))
@@ -235,34 +326,21 @@ target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     target_ulong tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
 
     if (GET_LMASK(arg2) <= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, 1));
+        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
         arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
     }
 
     if (GET_LMASK(arg2) <= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, 2));
+        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
         arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
     }
 
     if (GET_LMASK(arg2) == 0) {
-        tmp = ldfun(GET_OFFSET(arg2, 3));
+        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
         arg1 = (arg1 & 0xFFFFFF00) | tmp;
     }
     return (int32_t)arg1;
@@ -272,34 +350,21 @@ target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     target_ulong tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0xFFFFFF00) | tmp;
 
     if (GET_LMASK(arg2) >= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, -1));
+        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
         arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
     }
 
     if (GET_LMASK(arg2) >= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, -2));
+        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
         arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
     }
 
     if (GET_LMASK(arg2) == 3) {
-        tmp = ldfun(GET_OFFSET(arg2, -3));
+        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
         arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
     }
     return (int32_t)arg1;
@@ -307,56 +372,30 @@ target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
 
 void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-    default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)(arg1 >> 24));
+    do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
 
     if (GET_LMASK(arg2) <= 2)
-        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK(arg2) <= 1)
-        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK(arg2) == 0)
-        stfun(GET_OFFSET(arg2, 3), (uint8_t)arg1);
+        do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
 }
 
 void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-    default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)arg1);
+    do_sb(arg2, (uint8_t)arg1, mem_idx);
 
     if (GET_LMASK(arg2) >= 1)
-        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK(arg2) >= 2)
-        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK(arg2) == 3)
-        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
+        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
 }
 
 #if defined(TARGET_MIPS64)
@@ -373,54 +412,41 @@ target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     uint64_t tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
 
     if (GET_LMASK64(arg2) <= 6) {
-        tmp = ldfun(GET_OFFSET(arg2, 1));
+        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
         arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
     }
 
     if (GET_LMASK64(arg2) <= 5) {
-        tmp = ldfun(GET_OFFSET(arg2, 2));
+        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
         arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
     }
 
     if (GET_LMASK64(arg2) <= 4) {
-        tmp = ldfun(GET_OFFSET(arg2, 3));
+        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
         arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
     }
 
     if (GET_LMASK64(arg2) <= 3) {
-        tmp = ldfun(GET_OFFSET(arg2, 4));
+        tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
     }
 
     if (GET_LMASK64(arg2) <= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, 5));
+        tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
     }
 
     if (GET_LMASK64(arg2) <= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, 6));
+        tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
     }
 
     if (GET_LMASK64(arg2) == 0) {
-        tmp = ldfun(GET_OFFSET(arg2, 7));
+        tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
     }
 
@@ -431,54 +457,41 @@ target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
     uint64_t tmp;
 
-#ifdef CONFIG_USER_ONLY
-#define ldfun ldub_raw
-#else
-    int (*ldfun)(target_ulong);
-
-    switch (mem_idx)
-    {
-    case 0: ldfun = ldub_kernel; break;
-    case 1: ldfun = ldub_super; break;
-    default:
-    case 2: ldfun = ldub_user; break;
-    }
-#endif
-    tmp = ldfun(arg2);
+    tmp = do_lbu(arg2, mem_idx);
     arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
 
     if (GET_LMASK64(arg2) >= 1) {
-        tmp = ldfun(GET_OFFSET(arg2, -1));
+        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
     }
 
     if (GET_LMASK64(arg2) >= 2) {
-        tmp = ldfun(GET_OFFSET(arg2, -2));
+        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
     }
 
     if (GET_LMASK64(arg2) >= 3) {
-        tmp = ldfun(GET_OFFSET(arg2, -3));
+        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
         arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
     }
 
     if (GET_LMASK64(arg2) >= 4) {
-        tmp = ldfun(GET_OFFSET(arg2, -4));
+        tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
         arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
     }
 
     if (GET_LMASK64(arg2) >= 5) {
-        tmp = ldfun(GET_OFFSET(arg2, -5));
+        tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
         arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
     }
 
     if (GET_LMASK64(arg2) >= 6) {
-        tmp = ldfun(GET_OFFSET(arg2, -6));
+        tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
         arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
     }
 
     if (GET_LMASK64(arg2) == 7) {
-        tmp = ldfun(GET_OFFSET(arg2, -7));
+        tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
         arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
     }
 
@@ -487,80 +500,54 @@ target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
 
 void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-    default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)(arg1 >> 56));
+    do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
 
     if (GET_LMASK64(arg2) <= 6)
-        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48));
+        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
 
     if (GET_LMASK64(arg2) <= 5)
-        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40));
+        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
 
     if (GET_LMASK64(arg2) <= 4)
-        stfun(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32));
+        do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
 
     if (GET_LMASK64(arg2) <= 3)
-        stfun(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24));
+        do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
 
     if (GET_LMASK64(arg2) <= 2)
-        stfun(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK64(arg2) <= 1)
-        stfun(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK64(arg2) <= 0)
-        stfun(GET_OFFSET(arg2, 7), (uint8_t)arg1);
+        do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
 }
 
 void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
 {
-#ifdef CONFIG_USER_ONLY
-#define stfun stb_raw
-#else
-    void (*stfun)(target_ulong, int);
-
-    switch (mem_idx)
-    {
-    case 0: stfun = stb_kernel; break;
-    case 1: stfun = stb_super; break;
-     default:
-    case 2: stfun = stb_user; break;
-    }
-#endif
-    stfun(arg2, (uint8_t)arg1);
+    do_sb(arg2, (uint8_t)arg1, mem_idx);
 
     if (GET_LMASK64(arg2) >= 1)
-        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
+        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
 
     if (GET_LMASK64(arg2) >= 2)
-        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
+        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
 
     if (GET_LMASK64(arg2) >= 3)
-        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
+        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
 
     if (GET_LMASK64(arg2) >= 4)
-        stfun(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32));
+        do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
 
     if (GET_LMASK64(arg2) >= 5)
-        stfun(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40));
+        do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
 
     if (GET_LMASK64(arg2) >= 6)
-        stfun(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48));
+        do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
 
     if (GET_LMASK64(arg2) == 7)
-        stfun(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56));
+        do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
 }
 #endif /* TARGET_MIPS64 */
 
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e9d92249ef..9d62b64b51 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -912,16 +912,24 @@ OP_ST(sd,st64);
 #endif
 #undef OP_ST
 
+#ifdef CONFIG_USER_ONLY
 #define OP_LD_ATOMIC(insn,fname)                                           \
 static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)  \
 {                                                                          \
     TCGv t0 = tcg_temp_new();                                              \
     tcg_gen_mov_tl(t0, arg1);                                              \
     tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                         \
-    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, lladdr));            \
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, lladdr));                \
     tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval));                \
     tcg_temp_free(t0);                                                     \
 }
+#else
+#define OP_LD_ATOMIC(insn,fname)                                           \
+static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)  \
+{                                                                          \
+    gen_helper_2i(insn, ret, arg1, ctx->mem_idx);                          \
+}
+#endif
 OP_LD_ATOMIC(ll,ld32s);
 #if defined(TARGET_MIPS64)
 OP_LD_ATOMIC(lld,ld64);
@@ -941,7 +949,7 @@ static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ct
     tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr));          \
     generate_exception(ctx, EXCP_AdES);                                      \
     gen_set_label(l1);                                                       \
-    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr));              \
+    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr));                  \
     tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2);                            \
     tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20));                        \
     tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, llreg));                   \
@@ -957,34 +965,11 @@ static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ct
 static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
 {                                                                            \
     TCGv t0 = tcg_temp_new();                                                \
-    TCGv t1 = tcg_temp_new();                                                \
-    int l1 = gen_new_label();                                                \
-    int l2 = gen_new_label();                                                \
-    int l3 = gen_new_label();                                                \
-                                                                             \
-    tcg_gen_andi_tl(t0, arg2, almask);                                       \
-    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);                              \
-    tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr));          \
-    generate_exception(ctx, EXCP_AdES);                                      \
-    gen_set_label(l1);                                                       \
-    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr));              \
-    tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2);                            \
-    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, llval));                   \
-    tcg_gen_qemu_##ldname(t1, arg2, ctx->mem_idx);                           \
-    tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l2);                              \
-    tcg_temp_free(t1);                                                       \
-    tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx);                          \
-    tcg_gen_movi_tl(t0, 1);                                                  \
-    gen_store_gpr(t0, rt);                                                   \
-    tcg_gen_br(l3);                                                          \
-    gen_set_label(l2);                                                       \
-    tcg_gen_movi_tl(t0, 0);                                                  \
+    gen_helper_3i(insn, t0, arg1, arg2, ctx->mem_idx);                       \
     gen_store_gpr(t0, rt);                                                   \
-    gen_set_label(l3);                                                       \
     tcg_temp_free(t0);                                                       \
 }
 #endif
-
 OP_ST_ATOMIC(sc,st32,ld32s,0x3);
 #if defined(TARGET_MIPS64)
 OP_ST_ATOMIC(scd,st64,ld64,0x7);
@@ -1137,7 +1122,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
         opn = "swr";
         break;
     case OPC_LL:
-        save_cpu_state(ctx, 0);
+        save_cpu_state(ctx, 1);
         op_ldst_ll(t0, t0, ctx);
         gen_store_gpr(t0, rt);
         opn = "ll";
@@ -1179,7 +1164,7 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
         break;
 #endif
     case OPC_SC:
-        save_cpu_state(ctx, 0);
+        save_cpu_state(ctx, 1);
         op_ldst_sc(t1, t0, rt, ctx);
         opn = "sc";
         break;
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
new file mode 100644
index 0000000000..8fcb5c99c3
--- /dev/null
+++ b/tcg/mips/tcg-target.c
@@ -0,0 +1,1342 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
+ * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if defined(TCG_TARGET_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+# define TCG_NEED_BSWAP 0
+#else
+# define TCG_NEED_BSWAP 1
+#endif
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+    "zero",
+    "at",
+    "v0",
+    "v1",
+    "a0",
+    "a1",
+    "a2",
+    "a3",
+    "t0",
+    "t1",
+    "t2",
+    "t3",
+    "t4",
+    "t5",
+    "t6",
+    "t7",
+    "s0",
+    "s1",
+    "s2",
+    "s3",
+    "s4",
+    "s5",
+    "s6",
+    "s7",
+    "t8",
+    "t9",
+    "k0",
+    "k1",
+    "gp",
+    "sp",
+    "fp",
+    "ra",
+};
+#endif
+
+/* check if we really need so many registers :P */
+static const int tcg_target_reg_alloc_order[] = {
+    TCG_REG_S0,
+    TCG_REG_S1,
+    TCG_REG_S2,
+    TCG_REG_S3,
+    TCG_REG_S4,
+    TCG_REG_S5,
+    TCG_REG_S6,
+    TCG_REG_S7,
+    TCG_REG_T1,
+    TCG_REG_T2,
+    TCG_REG_T3,
+    TCG_REG_T4,
+    TCG_REG_T5,
+    TCG_REG_T6,
+    TCG_REG_T7,
+    TCG_REG_T8,
+    TCG_REG_T9,
+    TCG_REG_A0,
+    TCG_REG_A1,
+    TCG_REG_A2,
+    TCG_REG_A3,
+    TCG_REG_V0,
+    TCG_REG_V1
+};
+
+static const int tcg_target_call_iarg_regs[4] = {
+    TCG_REG_A0,
+    TCG_REG_A1,
+    TCG_REG_A2,
+    TCG_REG_A3
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+    TCG_REG_V0,
+    TCG_REG_V1
+};
+
+static uint8_t *tb_ret_addr;
+
+static inline uint32_t reloc_lo16_val (void *pc, tcg_target_long target)
+{
+    return target & 0xffff;
+}
+
+static inline void reloc_lo16 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+                       | reloc_lo16_val(pc, target);
+}
+
+static inline uint32_t reloc_hi16_val (void *pc, tcg_target_long target)
+{
+    return (target >> 16) & 0xffff;
+}
+
+static inline void reloc_hi16 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+                       | reloc_hi16_val(pc, target);
+}
+
+static inline uint32_t reloc_pc16_val (void *pc, tcg_target_long target)
+{
+    int32_t disp;
+
+    disp = target - (tcg_target_long) pc - 4;
+    if (disp != (disp << 14) >> 14) {
+        tcg_abort ();
+    }
+
+    return (disp >> 2) & 0xffff;
+}
+
+static inline void reloc_pc16 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff)
+                       | reloc_pc16_val(pc, target);
+}
+
+static inline uint32_t reloc_26_val (void *pc, tcg_target_long target)
+{
+    if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) {
+        tcg_abort ();
+    }
+
+    return (target >> 2) & 0x3ffffff;
+}
+
+static inline void reloc_pc26 (void *pc, tcg_target_long target)
+{
+    *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff)
+                       | reloc_26_val(pc, target);
+}
+
+static void patch_reloc(uint8_t *code_ptr, int type,
+                        tcg_target_long value, tcg_target_long addend)
+{
+    value += addend;
+    switch(type) {
+    case R_MIPS_LO16:
+        reloc_lo16(code_ptr, value);
+        break;
+    case R_MIPS_HI16:
+        reloc_hi16(code_ptr, value);
+        break;
+    case R_MIPS_PC16:
+        reloc_pc16(code_ptr, value);
+        break;
+    case R_MIPS_26:
+        reloc_pc26(code_ptr, value);
+        break;
+    default:
+        tcg_abort();
+    }
+}
+
+/* maximum number of register used for input function arguments */
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+    return 4;
+}
+
+/* parse target specific constraints */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+    const char *ct_str;
+
+    ct_str = *pct_str;
+    switch(ct_str[0]) {
+    case 'r':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+        break;
+    case 'C':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_clear(ct->u.regs);
+        tcg_regset_set_reg(ct->u.regs, TCG_REG_T9);
+        break;
+    case 'L': /* qemu_ld output arg constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_V0);
+        break;
+    case 'l': /* qemu_ld input arg constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+#if defined(CONFIG_SOFTMMU)
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+#endif
+        break;
+    case 'S': /* qemu_st constraint */
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set(ct->u.regs, 0xffffffff);
+#if defined(CONFIG_SOFTMMU)
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+# if TARGET_LONG_BITS == 64
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
+# endif
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+#endif
+        break;
+    case 'I':
+        ct->ct |= TCG_CT_CONST_U16;
+        break;
+    case 'J':
+        ct->ct |= TCG_CT_CONST_S16;
+        break;
+    case 'Z':
+        /* We are cheating a bit here, using the fact that the register
+           ZERO is also the register number 0. Hence there is no need
+           to check for const_args in each instruction. */
+        ct->ct |= TCG_CT_CONST_ZERO;
+        break;
+    default:
+        return -1;
+    }
+    ct_str++;
+    *pct_str = ct_str;
+    return 0;
+}
+
+/* test if a constant matches the constraint */
+static inline int tcg_target_const_match(tcg_target_long val,
+                                         const TCGArgConstraint *arg_ct)
+{
+    int ct;
+    ct = arg_ct->ct;
+    if (ct & TCG_CT_CONST)
+        return 1;
+    else if ((ct & TCG_CT_CONST_ZERO) && val == 0)
+        return 1;
+    else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val)
+        return 1;
+    else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val)
+        return 1;
+    else
+        return 0;
+}
+
+/* instruction opcodes */
+enum {
+    OPC_SPECIAL  = 0x00 << 26,
+    OPC_BEQ      = 0x04 << 26,
+    OPC_BNE      = 0x05 << 26,
+    OPC_ADDIU    = 0x09 << 26,
+    OPC_ANDI     = 0x0C << 26,
+    OPC_ORI      = 0x0D << 26,
+    OPC_XORI     = 0x0E << 26,
+    OPC_LUI      = 0x0F << 26,
+    OPC_LB       = 0x20 << 26,
+    OPC_LH       = 0x21 << 26,
+    OPC_LW       = 0x23 << 26,
+    OPC_LBU      = 0x24 << 26,
+    OPC_LHU      = 0x25 << 26,
+    OPC_LWU      = 0x27 << 26,
+    OPC_SB       = 0x28 << 26,
+    OPC_SH       = 0x29 << 26,
+    OPC_SW       = 0x2B << 26,
+    OPC_SLL      = OPC_SPECIAL | 0x00,
+    OPC_SRL      = OPC_SPECIAL | 0x02,
+    OPC_SRA      = OPC_SPECIAL | 0x03,
+    OPC_SLLV     = OPC_SPECIAL | 0x04,
+    OPC_SRLV     = OPC_SPECIAL | 0x06,
+    OPC_SRAV     = OPC_SPECIAL | 0x07,
+    OPC_JR       = OPC_SPECIAL | 0x08,
+    OPC_JALR     = OPC_SPECIAL | 0x09,
+    OPC_MFHI     = OPC_SPECIAL | 0x10,
+    OPC_MFLO     = OPC_SPECIAL | 0x12,
+    OPC_MULT     = OPC_SPECIAL | 0x18,
+    OPC_MULTU    = OPC_SPECIAL | 0x19,
+    OPC_DIV      = OPC_SPECIAL | 0x1A,
+    OPC_DIVU     = OPC_SPECIAL | 0x1B,
+    OPC_ADDU     = OPC_SPECIAL | 0x21,
+    OPC_SUBU     = OPC_SPECIAL | 0x23,
+    OPC_AND      = OPC_SPECIAL | 0x24,
+    OPC_OR       = OPC_SPECIAL | 0x25,
+    OPC_XOR      = OPC_SPECIAL | 0x26,
+    OPC_NOR      = OPC_SPECIAL | 0x27,
+    OPC_SLT      = OPC_SPECIAL | 0x2A,
+    OPC_SLTU     = OPC_SPECIAL | 0x2B,
+};
+
+/*
+ * Type reg
+ */
+static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rs & 0x1F) << 21;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (rd & 0x1F) << 11;
+    tcg_out32(s, inst);
+}
+
+/*
+ * Type immediate
+ */
+static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rs & 0x1F) << 21;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (imm & 0xffff);
+    tcg_out32(s, inst);
+}
+
+/*
+ * Type sa
+ */
+static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (rd & 0x1F) << 11;
+    inst |= (sa & 0x1F) <<  6;
+    tcg_out32(s, inst);
+
+}
+
+static inline void tcg_out_nop(TCGContext *s)
+{
+    tcg_out32(s, 0);
+}
+
+static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
+{
+    tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+}
+
+static inline void tcg_out_movi(TCGContext *s, TCGType type,
+                                int reg, int32_t arg)
+{
+    if (arg == (int16_t)arg) {
+        tcg_out_opc_imm(s, OPC_ADDIU, reg, TCG_REG_ZERO, arg);
+    } else if (arg == (uint16_t)arg) {
+        tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg);
+    } else {
+        tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16);
+        tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff);
+    }
+}
+
+static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg)
+{
+    /* ret and arg can't be register at */
+    if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        tcg_abort();
+    }
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff);
+
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg)
+{
+    /* ret and arg can't be register at */
+    if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        tcg_abort();
+    }
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff);
+
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+    tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg)
+{
+    /* ret and arg must be different and can't be register at */
+    if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        tcg_abort();
+    }
+
+    tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00);
+    tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00);
+    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+}
+
+static inline void tcg_out_ldst(TCGContext *s, int opc, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    if (arg2 == (int16_t) arg2) {
+        tcg_out_opc_imm(s, opc, arg, arg1, arg2);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2);
+        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1);
+        tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0);
+    }
+}
+
+static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    tcg_out_ldst(s, OPC_LW, arg, arg1, arg2);
+}
+
+static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
+                              int arg1, tcg_target_long arg2)
+{
+    tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
+}
+
+static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+    if (val == (int16_t)val) {
+        tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val);
+        tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT);
+    }
+}
+
+static void tcg_out_brcond(TCGContext *s, int cond, int arg1,
+                           int arg2, int label_index)
+{
+    TCGLabel *l = &s->labels[label_index];
+
+    switch (cond) {
+    case TCG_COND_EQ:
+        tcg_out_opc_imm(s, OPC_BEQ, arg1, arg2, 0);
+        break;
+    case TCG_COND_NE:
+        tcg_out_opc_imm(s, OPC_BNE, arg1, arg2, 0);
+        break;
+    case TCG_COND_LT:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_LTU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_GE:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_GEU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
+        tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_LE:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_LEU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_GT:
+        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    case TCG_COND_GTU:
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
+        tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
+        break;
+    default:
+        tcg_abort();
+        break;
+    }
+    if (l->has_value) {
+        reloc_pc16(s->code_ptr - 4, l->u.value);
+    } else {
+        tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0);
+    }
+    tcg_out_nop(s);
+}
+
+/* XXX: we implement it at the target level to avoid having to
+   handle cross basic blocks temporaries */
+static void tcg_out_brcond2(TCGContext *s, int cond, int arg1,
+                            int arg2, int arg3, int arg4, int label_index)
+{
+    void *label_ptr;
+
+    switch(cond) {
+    case TCG_COND_NE:
+        tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index);
+        tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index);
+        return;
+    case TCG_COND_EQ:
+        break;
+    case TCG_COND_LT:
+    case TCG_COND_LE:
+        tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index);
+        break;
+    case TCG_COND_GT:
+    case TCG_COND_GE:
+        tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index);
+        break;
+    case TCG_COND_LTU:
+    case TCG_COND_LEU:
+        tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index);
+        break;
+    case TCG_COND_GTU:
+    case TCG_COND_GEU:
+        tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    label_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BNE, arg2, arg4, 0);
+    tcg_out_nop(s);
+
+    switch(cond) {
+    case TCG_COND_EQ:
+        tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index);
+        break;
+    case TCG_COND_LT:
+    case TCG_COND_LTU:
+        tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index);
+        break;
+    case TCG_COND_LE:
+    case TCG_COND_LEU:
+        tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index);
+        break;
+    case TCG_COND_GT:
+    case TCG_COND_GTU:
+        tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index);
+        break;
+    case TCG_COND_GE:
+    case TCG_COND_GEU:
+        tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr);
+}
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+    __ldb_mmu,
+    __ldw_mmu,
+    __ldl_mmu,
+    __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+    __stb_mmu,
+    __stw_mmu,
+    __stl_mmu,
+    __stq_mmu,
+};
+#endif
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int addr_regl, addr_reg1, addr_meml;
+    int data_regl, data_regh, data_reg1, data_reg2;
+    int mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+    void *label1_ptr, *label2_ptr;
+    int sp_args;
+#endif
+#if TARGET_LONG_BITS == 64
+# if defined(CONFIG_SOFTMMU)
+    uint8_t *label3_ptr;
+# endif
+    int addr_regh, addr_reg2, addr_memh;
+#endif
+    data_regl = *args++;
+    if (opc == 3)
+        data_regh = *args++;
+    else
+        data_regh = 0;
+    addr_regl = *args++;
+#if TARGET_LONG_BITS == 64
+    addr_regh = *args++;
+#endif
+    mem_index = *args;
+    s_bits = opc & 3;
+
+    if (opc == 3) {
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+        data_reg1 = data_regh;
+        data_reg2 = data_regl;
+#else
+        data_reg1 = data_regl;
+        data_reg2 = data_regh;
+#endif
+    } else {
+        data_reg1 = data_regl;
+        data_reg2 = 0;
+    }
+#if TARGET_LONG_BITS == 64
+# if defined(TCG_TARGET_WORDS_BIGENDIAN)
+    addr_reg1 = addr_regh;
+    addr_reg2 = addr_regl;
+    addr_memh = 0;
+    addr_meml = 4;
+# else
+    addr_reg1 = addr_regl;
+    addr_reg2 = addr_regh;
+    addr_memh = 4;
+    addr_meml = 0;
+# endif
+#else
+    addr_reg1 = addr_regl;
+    addr_meml = 0;
+#endif
+
+#if defined(CONFIG_SOFTMMU)
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_meml);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+    tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
+
+# if TARGET_LONG_BITS == 64
+    label3_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0);
+    tcg_out_nop(s);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh);
+
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0);
+    tcg_out_nop(s);
+
+    reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
+# else
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0);
+    tcg_out_nop(s);
+# endif
+
+    /* slow path */
+    sp_args = TCG_REG_A0;
+    tcg_out_mov(s, sp_args++, addr_reg1);
+# if TARGET_LONG_BITS == 64
+    tcg_out_mov(s, sp_args++, addr_reg2);
+# endif
+    tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
+    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+    tcg_out_nop(s);
+
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff);
+        break;
+    case 0 | 4:
+        tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 24);
+        tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 24);
+        break;
+    case 1:
+        tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff);
+        break;
+    case 1 | 4:
+        tcg_out_opc_sa(s, OPC_SLL, TCG_REG_V0, TCG_REG_V0, 16);
+        tcg_out_opc_sa(s, OPC_SRA, data_reg1, TCG_REG_V0, 16);
+        break;
+    case 2:
+        tcg_out_mov(s, data_reg1, TCG_REG_V0);
+        break;
+    case 3:
+        tcg_out_mov(s, data_reg2, TCG_REG_V1);
+        tcg_out_mov(s, data_reg1, TCG_REG_V0);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    label2_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+    tcg_out_nop(s);
+
+    /* label1: fast path */
+    reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml);
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl);
+
+    addr_reg1 = TCG_REG_V0;
+#endif
+
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_LBU, data_reg1, addr_reg1, 0);
+        break;
+    case 0 | 4:
+        tcg_out_opc_imm(s, OPC_LB, data_reg1, addr_reg1, 0);
+        break;
+    case 1:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0);
+            tcg_out_bswap16(s, data_reg1, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LHU, data_reg1, addr_reg1, 0);
+        }
+        break;
+    case 1 | 4:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, addr_reg1, 0);
+            tcg_out_bswap16s(s, data_reg1, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LH, data_reg1, addr_reg1, 0);
+        }
+        break;
+    case 2:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0);
+            tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0);
+        }
+        break;
+    case 3:
+#if !defined(CONFIG_SOFTMMU)
+        tcg_out_mov(s, TCG_REG_V0, addr_reg1);
+        addr_reg1 = TCG_REG_V0;
+#endif
+        if (TCG_NEED_BSWAP) {
+            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 4);
+            tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
+            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, addr_reg1, 0);
+            tcg_out_bswap32(s, data_reg2, TCG_REG_T0);
+        } else {
+            tcg_out_opc_imm(s, OPC_LW, data_reg1, addr_reg1, 0);
+            tcg_out_opc_imm(s, OPC_LW, data_reg2, addr_reg1, 4);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
+                            int opc)
+{
+    int addr_regl, addr_reg1, addr_meml;
+    int data_regl, data_regh, data_reg1, data_reg2;
+    int mem_index, s_bits;
+#if defined(CONFIG_SOFTMMU)
+    uint8_t *label1_ptr, *label2_ptr;
+    int sp_args;
+#endif
+#if TARGET_LONG_BITS == 64
+# if defined(CONFIG_SOFTMMU)
+    uint8_t *label3_ptr;
+# endif
+    int addr_regh, addr_reg2, addr_memh;
+#endif
+
+    data_regl = *args++;
+    if (opc == 3) {
+        data_regh = *args++;
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+        data_reg1 = data_regh;
+        data_reg2 = data_regl;
+#else
+        data_reg1 = data_regl;
+        data_reg2 = data_regh;
+#endif
+    } else {
+        data_reg1 = data_regl;
+        data_reg2 = 0;
+        data_regh = 0;
+    }
+    addr_regl = *args++;
+#if TARGET_LONG_BITS == 64
+    addr_regh = *args++;
+# if defined(TCG_TARGET_WORDS_BIGENDIAN)
+    addr_reg1 = addr_regh;
+    addr_reg2 = addr_regl;
+    addr_memh = 0;
+    addr_meml = 4;
+# else
+    addr_reg1 = addr_regl;
+    addr_reg2 = addr_regh;
+    addr_memh = 4;
+    addr_meml = 0;
+# endif
+#else
+    addr_reg1 = addr_regl;
+    addr_meml = 0;
+#endif
+    mem_index = *args;
+    s_bits = opc;
+
+#if defined(CONFIG_SOFTMMU)
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_meml);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+    tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
+
+# if TARGET_LONG_BITS == 64
+    label3_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0);
+    tcg_out_nop(s);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh);
+
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0);
+    tcg_out_nop(s);
+
+    reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
+# else
+    label1_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0);
+    tcg_out_nop(s);
+# endif
+
+    /* slow path */
+    sp_args = TCG_REG_A0;
+    tcg_out_mov(s, sp_args++, addr_reg1);
+# if TARGET_LONG_BITS == 64
+    tcg_out_mov(s, sp_args++, addr_reg2);
+# endif
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff);
+        break;
+    case 1:
+        tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
+        break;
+    case 2:
+        tcg_out_mov(s, sp_args++, data_reg1);
+        break;
+    case 3:
+        sp_args = (sp_args + 1) & ~1;
+        tcg_out_mov(s, sp_args++, data_reg1);
+        tcg_out_mov(s, sp_args++, data_reg2);
+        break;
+    default:
+        tcg_abort();
+    }
+    if (sp_args > TCG_REG_A3) {
+        /* Push mem_index on the stack */
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index);
+        tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index);
+    }
+
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
+    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+    tcg_out_nop(s);
+
+    label2_ptr = s->code_ptr;
+    tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+    tcg_out_nop(s);
+
+    /* label1: fast path */
+    reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
+
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
+                    offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml);
+    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
+
+    addr_reg1 = TCG_REG_A0;
+#endif
+
+    switch(opc) {
+    case 0:
+        tcg_out_opc_imm(s, OPC_SB, data_reg1, addr_reg1, 0);
+        break;
+    case 1:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_bswap16(s, TCG_REG_T0, data_reg1);
+            tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, addr_reg1, 0);
+        } else {
+            tcg_out_opc_imm(s, OPC_SH, data_reg1, addr_reg1, 0);
+        }
+        break;
+    case 2:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
+            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0);
+        } else {
+            tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0);
+        }
+        break;
+    case 3:
+        if (TCG_NEED_BSWAP) {
+            tcg_out_bswap32(s, TCG_REG_T0, data_reg2);
+            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 0);
+            tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
+            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, addr_reg1, 4);
+        } else {
+            tcg_out_opc_imm(s, OPC_SW, data_reg1, addr_reg1, 0);
+            tcg_out_opc_imm(s, OPC_SW, data_reg2, addr_reg1, 4);
+        }
+        break;
+    default:
+        tcg_abort();
+    }
+
+#if defined(CONFIG_SOFTMMU)
+    reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr);
+#endif
+}
+
+static inline void tcg_out_op(TCGContext *s, int opc,
+                              const TCGArg *args, const int *const_args)
+{
+    switch(opc) {
+    case INDEX_op_exit_tb:
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]);
+        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr);
+        tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_goto_tb:
+        if (s->tb_jmp_offset) {
+            /* direct jump method */
+            tcg_abort();
+        } else {
+            /* indirect jump method */
+            tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0]));
+            tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0);
+            tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+        }
+        tcg_out_nop(s);
+        s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+        break;
+    case INDEX_op_call:
+        tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_jmp:
+        tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0);
+        tcg_out_nop(s);
+        break;
+    case INDEX_op_br:
+        tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]);
+        break;
+
+    case INDEX_op_mov_i32:
+        tcg_out_mov(s, args[0], args[1]);
+        break;
+    case INDEX_op_movi_i32:
+        tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
+        break;
+
+    case INDEX_op_ld8u_i32:
+	tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld8s_i32:
+        tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16u_i32:
+        tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld16s_i32:
+        tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_ld_i32:
+        tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st8_i32:
+        tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st16_i32:
+        tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]);
+        break;
+    case INDEX_op_st_i32:
+        tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]);
+        break;
+
+    case INDEX_op_add_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_add2_i32:
+        if (const_args[4]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]);
+        } else {
+            tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]);
+        }
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]);
+        if (const_args[5]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]);
+        } else {
+             tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]);
+        }
+        tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0);
+        tcg_out_mov(s, args[0], TCG_REG_AT);
+        break;
+    case INDEX_op_sub_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_sub2_i32:
+        if (const_args[4]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]);
+        }
+        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT);
+        if (const_args[5]) {
+            tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]);
+        } else {
+             tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]);
+        }
+        tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0);
+        tcg_out_mov(s, args[0], TCG_REG_AT);
+        break;
+    case INDEX_op_mul_i32:
+        tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        break;
+    case INDEX_op_mulu2_i32:
+        tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0);
+        break;
+    case INDEX_op_div_i32:
+        tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        break;
+    case INDEX_op_divu_i32:
+        tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+        break;
+    case INDEX_op_rem_i32:
+        tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+        break;
+    case INDEX_op_remu_i32:
+        tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
+        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+        break;
+
+    case INDEX_op_and_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_or_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]);
+        }
+        break;
+    case INDEX_op_not_i32:
+        tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[1]);
+        break;
+    case INDEX_op_xor_i32:
+        if (const_args[2]) {
+            tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]);
+        }
+        break;
+
+    case INDEX_op_sar_i32:
+        if (const_args[2]) {
+            tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]);
+        }
+        break;
+    case INDEX_op_shl_i32:
+        if (const_args[2]) {
+            tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]);
+        }
+        break;
+    case INDEX_op_shr_i32:
+        if (const_args[2]) {
+            tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]);
+        } else {
+            tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]);
+        }
+        break;
+
+    case INDEX_op_brcond_i32:
+        tcg_out_brcond(s, args[2], args[0], args[1], args[3]);
+        break;
+    case INDEX_op_brcond2_i32:
+        tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]);
+        break;
+
+    case INDEX_op_qemu_ld8u:
+        tcg_out_qemu_ld(s, args, 0);
+        break;
+    case INDEX_op_qemu_ld8s:
+        tcg_out_qemu_ld(s, args, 0 | 4);
+        break;
+    case INDEX_op_qemu_ld16u:
+        tcg_out_qemu_ld(s, args, 1);
+        break;
+    case INDEX_op_qemu_ld16s:
+        tcg_out_qemu_ld(s, args, 1 | 4);
+        break;
+    case INDEX_op_qemu_ld32u:
+        tcg_out_qemu_ld(s, args, 2);
+        break;
+    case INDEX_op_qemu_ld64:
+        tcg_out_qemu_ld(s, args, 3);
+        break;
+    case INDEX_op_qemu_st8:
+        tcg_out_qemu_st(s, args, 0);
+        break;
+    case INDEX_op_qemu_st16:
+        tcg_out_qemu_st(s, args, 1);
+        break;
+    case INDEX_op_qemu_st32:
+        tcg_out_qemu_st(s, args, 2);
+        break;
+    case INDEX_op_qemu_st64:
+        tcg_out_qemu_st(s, args, 3);
+        break;
+
+    default:
+        tcg_abort();
+    }
+}
+
+static const TCGTargetOpDef mips_op_defs[] = {
+    { INDEX_op_exit_tb, { } },
+    { INDEX_op_goto_tb, { } },
+    { INDEX_op_call, { "C" } },
+    { INDEX_op_jmp, { "r" } },
+    { INDEX_op_br, { } },
+
+    { INDEX_op_mov_i32, { "r", "r" } },
+    { INDEX_op_movi_i32, { "r" } },
+    { INDEX_op_ld8u_i32, { "r", "r" } },
+    { INDEX_op_ld8s_i32, { "r", "r" } },
+    { INDEX_op_ld16u_i32, { "r", "r" } },
+    { INDEX_op_ld16s_i32, { "r", "r" } },
+    { INDEX_op_ld_i32, { "r", "r" } },
+    { INDEX_op_st8_i32, { "rZ", "r" } },
+    { INDEX_op_st16_i32, { "rZ", "r" } },
+    { INDEX_op_st_i32, { "rZ", "r" } },
+
+    { INDEX_op_add_i32, { "r", "rZ", "rJZ" } },
+    { INDEX_op_mul_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } },
+    { INDEX_op_div_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_divu_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_rem_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_remu_i32, { "r", "rZ", "rZ" } },
+    { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } },
+
+    { INDEX_op_and_i32, { "r", "rZ", "rIZ" } },
+    { INDEX_op_not_i32, { "r", "rZ" } },
+    { INDEX_op_or_i32, { "r", "rZ", "rIZ" } },
+    { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } },
+
+    { INDEX_op_shl_i32, { "r", "rZ", "riZ" } },
+    { INDEX_op_shr_i32, { "r", "rZ", "riZ" } },
+    { INDEX_op_sar_i32, { "r", "rZ", "riZ" } },
+
+    { INDEX_op_brcond_i32, { "rZ", "rZ" } },
+
+    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
+    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } },
+    { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
+
+#if TARGET_LONG_BITS == 32
+    { INDEX_op_qemu_ld8u, { "L", "lZ" } },
+    { INDEX_op_qemu_ld8s, { "L", "lZ" } },
+    { INDEX_op_qemu_ld16u, { "L", "lZ" } },
+    { INDEX_op_qemu_ld16s, { "L", "lZ" } },
+    { INDEX_op_qemu_ld32u, { "L", "lZ" } },
+    { INDEX_op_qemu_ld64, { "L", "L", "lZ" } },
+
+    { INDEX_op_qemu_st8, { "SZ", "SZ" } },
+    { INDEX_op_qemu_st16, { "SZ", "SZ" } },
+    { INDEX_op_qemu_st32, { "SZ", "SZ" } },
+    { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } },
+#else
+    { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld32u, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } },
+
+    { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } },
+#endif
+    { -1 },
+};
+
+static int tcg_target_callee_save_regs[] = {
+    TCG_REG_S0,
+    TCG_REG_S1,
+    TCG_REG_S2,
+    TCG_REG_S3,
+    TCG_REG_S4,
+    TCG_REG_S5,
+    TCG_REG_S6,
+    TCG_REG_S7,
+    TCG_REG_GP,
+    /* TCG_REG_FP, */ /* currently used for the global env, so np
+                         need to save */
+    TCG_REG_RA,       /* should be last for ABI compliance */
+};
+
+/* Generate global QEMU prologue and epilogue code */
+void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int i, frame_size;
+
+    /* reserve some stack space */
+    frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4
+                 + TCG_STATIC_CALL_ARGS_SIZE;
+    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
+                 ~(TCG_TARGET_STACK_ALIGN - 1);
+
+    /* TB prologue */
+    tcg_out_addi(s, TCG_REG_SP, -frame_size);
+    for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
+        tcg_out_st(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
+                   TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
+    }
+
+    /* Call generated code */
+    tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_A0, 0);
+    tcg_out_nop(s);
+    tb_ret_addr = s->code_ptr;
+
+    /* TB epilogue */
+    for(i = 0 ; i < ARRAY_SIZE(tcg_target_callee_save_regs) ; i++) {
+        tcg_out_ld(s, TCG_TYPE_I32, tcg_target_callee_save_regs[i],
+                   TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE + i * 4);
+    }
+
+    tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_RA, 0);
+    tcg_out_addi(s, TCG_REG_SP, frame_size);
+}
+
+void tcg_target_init(TCGContext *s)
+{
+    tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff);
+    tcg_regset_set(tcg_target_call_clobber_regs,
+                   (1 << TCG_REG_V0) |
+                   (1 << TCG_REG_V1) |
+                   (1 << TCG_REG_A0) |
+                   (1 << TCG_REG_A1) |
+                   (1 << TCG_REG_A2) |
+                   (1 << TCG_REG_A3) |
+                   (1 << TCG_REG_T1) |
+                   (1 << TCG_REG_T2) |
+                   (1 << TCG_REG_T3) |
+                   (1 << TCG_REG_T4) |
+                   (1 << TCG_REG_T5) |
+                   (1 << TCG_REG_T6) |
+                   (1 << TCG_REG_T7) |
+                   (1 << TCG_REG_T8) |
+                   (1 << TCG_REG_T9));
+
+    tcg_regset_clear(s->reserved_regs);
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0);   /* kernel use only */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1);   /* kernel use only */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA);   /* return address */
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);   /* stack pointer */
+
+    tcg_add_target_add_op_defs(mips_op_defs);
+}
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
new file mode 100644
index 0000000000..46760a50e1
--- /dev/null
+++ b/tcg/mips/tcg-target.h
@@ -0,0 +1,104 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
+ * Based on i386/tcg-target.c - Copyright (c) 2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define TCG_TARGET_MIPS 1
+
+#define TCG_TARGET_REG_BITS 32
+#ifdef __MIPSEB__
+# define TCG_TARGET_WORDS_BIGENDIAN
+#endif
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+    TCG_REG_ZERO = 0,
+    TCG_REG_AT,
+    TCG_REG_V0,
+    TCG_REG_V1,
+    TCG_REG_A0,
+    TCG_REG_A1,
+    TCG_REG_A2,
+    TCG_REG_A3,
+    TCG_REG_T0,
+    TCG_REG_T1,
+    TCG_REG_T2,
+    TCG_REG_T3,
+    TCG_REG_T4,
+    TCG_REG_T5,
+    TCG_REG_T6,
+    TCG_REG_T7,
+    TCG_REG_S0,
+    TCG_REG_S1,
+    TCG_REG_S2,
+    TCG_REG_S3,
+    TCG_REG_S4,
+    TCG_REG_S5,
+    TCG_REG_S6,
+    TCG_REG_S7,
+    TCG_REG_T8,
+    TCG_REG_T9,
+    TCG_REG_K0,
+    TCG_REG_K1,
+    TCG_REG_GP,
+    TCG_REG_SP,
+    TCG_REG_FP,
+    TCG_REG_RA,
+};
+
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_U16  0x200
+#define TCG_CT_CONST_S16  0x400
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_SP
+#define TCG_TARGET_STACK_ALIGN 8
+#define TCG_TARGET_CALL_STACK_OFFSET 16
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+
+/* optional instructions */
+#define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_not_i32
+#undef TCG_TARGET_HAS_ext8s_i32
+#undef TCG_TARGET_HAS_ext16s_i32
+#undef TCG_TARGET_HAS_bswap32_i32
+#undef TCG_TARGET_HAS_bswap16_i32
+#undef TCG_TARGET_HAS_rot_i32
+
+/* optional instructions automatically implemented */
+#undef TCG_TARGET_HAS_neg_i32      /* sub  rd, zero, rt   */
+#undef TCG_TARGET_HAS_ext8u_i32    /* andi rt, rs, 0xff   */
+#undef TCG_TARGET_HAS_ext16u_i32   /* andi rt, rs, 0xffff */
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_FP
+#define TCG_AREG1 TCG_REG_S0
+#define TCG_AREG2 TCG_REG_S1
+
+#include <sys/cachectl.h>
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    cacheflush ((void *)start, stop-start, ICACHE);
+}
diff --git a/usb-bsd.c b/usb-bsd.c
index 6e8c5266e9..a66364f0dc 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -335,7 +335,7 @@ USBDevice *usb_host_device_open(const char *devname)
         return NULL;
     }
 
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
     snprintf(ctlpath, PATH_MAX, "/dev/%s", bus_info.udi_devnames[0]);
 #else
     snprintf(ctlpath, PATH_MAX, "/dev/%s.00", bus_info.udi_devnames[0]);
@@ -437,7 +437,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
             if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0)
                 continue;
 
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
             snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]);
 #else
             snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]);
diff --git a/vl.c b/vl.c
index ee43808ef0..44763af714 100644
--- a/vl.c
+++ b/vl.c
@@ -50,13 +50,11 @@
 #include <sys/select.h>
 #ifdef CONFIG_BSD
 #include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #include <libutil.h>
 #else
 #include <util.h>
 #endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
 #else
 #ifdef __linux__
 #include <pty.h>
@@ -569,7 +567,7 @@ static void init_get_clock(void)
 {
     use_rt_clock = 0;
 #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
-    || defined(__DragonFly__)
+    || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
     {
         struct timespec ts;
         if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
@@ -582,7 +580,7 @@ static void init_get_clock(void)
 static int64_t get_clock(void)
 {
 #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
-	|| defined(__DragonFly__)
+	|| defined(__DragonFly__) || defined(__FreeBSD_kernel__)
     if (use_rt_clock) {
         struct timespec ts;
         clock_gettime(CLOCK_MONOTONIC, &ts);