aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-12-02 13:02:01 +0200
committerAvi Kivity <avi@redhat.com>2009-12-02 13:02:01 +0200
commit52e7939e712d0eb282c8b6cd9b57f17fb55cd68f (patch)
treee953241be24915f4b4123f8702b51e8bc780995f
parentMerge commit '98304c846d8866dae6322ef400ce6595b23cfc41' into upstream-merge (diff)
parentMerge commit 'mst/for_anthony' into mst (diff)
downloadqemu-kvm-52e7939e712d0eb282c8b6cd9b57f17fb55cd68f.tar.gz
qemu-kvm-52e7939e712d0eb282c8b6cd9b57f17fb55cd68f.tar.bz2
qemu-kvm-52e7939e712d0eb282c8b6cd9b57f17fb55cd68f.zip
Merge commit '365369847f2827b14b96c52d0fbaf9cce404e68a' into upstream-merge
* commit '365369847f2827b14b96c52d0fbaf9cce404e68a': tcg: increase TCG_MAX_OP_SIZE to 192 tcg: initial mips support target-mips: use physical address in lladdr target-mips: add a function to do virtual -> physical translations target-mips: split code raising MMU exception in a separate function target-mips: factorize load/store code in op_helper.c Fix commit a167ba50851cdac2fa36633587e98c5956cd6b18 Add support for GNU/kFreeBSD Signed-off-by: Avi Kivity <avi@redhat.com>
-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 59608d1b6..7446ca931 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -53,7 +53,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>
@@ -126,7 +126,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
@@ -638,7 +638,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
@@ -653,7 +653,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)) {
@@ -674,7 +674,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 */
@@ -959,7 +959,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;
@@ -1215,7 +1215,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;
@@ -1344,7 +1344,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 beb9bd782..f8a68cb9b 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="x86_64-softmmu"
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"
;;
@@ -270,27 +275,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"
@@ -382,7 +392,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 dd134a99f..820b59eea 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 fcffb0f30..9413e2953 100644
--- a/exec.c
+++ b/exec.c
@@ -475,7 +475,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 b4b678406..cb0e97be2 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -10,7 +10,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 0893ce36f..35670c80d 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 9ea66e36f..7c44c1ad5 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 0f8ad4ad7..815997dc7 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 5a81e8f5f..e202585fd 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 8a63921e0..fc6dc7471 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 82f9a3816..97e106f47 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 4a372777c..1e7e01608 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 4f1de5193..ab47b1a3a 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 52d687d33..be75af5e6 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 e9d92249e..9d62b64b5 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 000000000..8fcb5c99c
--- /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 000000000..46760a50e
--- /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 6e8c5266e..a66364f0d 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 f30cc2378..247ccf422 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>
@@ -583,7 +581,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) {
@@ -596,7 +594,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);