diff options
-rw-r--r-- | block/raw-posix.c | 16 | ||||
-rwxr-xr-x | configure | 13 | ||||
-rw-r--r-- | exec-all.h | 6 | ||||
-rw-r--r-- | exec.c | 2 | ||||
-rw-r--r-- | fpu/softfloat-native.c | 2 | ||||
-rw-r--r-- | fpu/softfloat-native.h | 6 | ||||
-rw-r--r-- | net.c | 5 | ||||
-rw-r--r-- | net/tap-bsd.c | 7 | ||||
-rw-r--r-- | qemu-char.c | 18 | ||||
-rw-r--r-- | savevm.c | 5 | ||||
-rw-r--r-- | target-mips/cpu.h | 2 | ||||
-rw-r--r-- | target-mips/helper.c | 122 | ||||
-rw-r--r-- | target-mips/helper.h | 9 | ||||
-rw-r--r-- | target-mips/op_helper.c | 291 | ||||
-rw-r--r-- | target-mips/translate.c | 41 | ||||
-rw-r--r-- | tcg/mips/tcg-target.c | 1342 | ||||
-rw-r--r-- | tcg/mips/tcg-target.h | 104 | ||||
-rw-r--r-- | usb-bsd.c | 4 | ||||
-rw-r--r-- | vl.c | 8 |
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 } @@ -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) @@ -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 @@ -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 }; @@ -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); +} @@ -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]); @@ -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); |