From 9f6f7ca1490563d98003149e6de32caf25c670da Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 19 Jun 2015 11:08:40 +0100 Subject: include/softmmu-semi.h: Make semihosting support 64-bit clean Correct addresses passed around in semihosting to use a data type suitable for both 32-bit and 64-bit targets. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- include/exec/softmmu-semi.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h index 8401f7d..1819cc2 100644 --- a/include/exec/softmmu-semi.h +++ b/include/exec/softmmu-semi.h @@ -9,14 +9,14 @@ #ifndef SOFTMMU_SEMI_H #define SOFTMMU_SEMI_H 1 -static inline uint32_t softmmu_tget32(CPUArchState *env, uint32_t addr) +static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr) { uint32_t val; cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 0); return tswap32(val); } -static inline uint32_t softmmu_tget8(CPUArchState *env, uint32_t addr) +static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr) { uint8_t val; @@ -28,7 +28,8 @@ static inline uint32_t softmmu_tget8(CPUArchState *env, uint32_t addr) #define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; }) #define get_user_ual(arg, p) get_user_u32(arg, p) -static inline void softmmu_tput32(CPUArchState *env, uint32_t addr, uint32_t val) +static inline void softmmu_tput32(CPUArchState *env, + target_ulong addr, uint32_t val) { val = tswap32(val); cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 1); @@ -36,8 +37,8 @@ static inline void softmmu_tput32(CPUArchState *env, uint32_t addr, uint32_t val #define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; }) #define put_user_ual(arg, p) put_user_u32(arg, p) -static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len, - int copy) +static void *softmmu_lock_user(CPUArchState *env, + target_ulong addr, target_ulong len, int copy) { uint8_t *p; /* TODO: Make this something that isn't fixed size. */ @@ -48,7 +49,7 @@ static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len, return p; } #define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy) -static char *softmmu_lock_user_string(CPUArchState *env, uint32_t addr) +static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr) { char *p; char *s; -- cgit v1.1 From d6ca4277eee98b3c561e21ac105199891d346d79 Mon Sep 17 00:00:00 2001 From: Matthew Fortune Date: Fri, 19 Jun 2015 11:08:41 +0100 Subject: hw/mips: Do not clear BEV for MIPS malta kernel load The BEV flag controls whether the boot exception vector is still in place when starting a kernel. When cleared the exception vector at EBASE (or hard coded address of 0x80000000) is used instead. The early stages of the linux kernel would benefit from BEV still being set to ensure any faults get handled by the boot rom exception handlers. This is a moot point for system qemu as there aren't really any BEV handlers, but there are other good reasons to change this... The UHI (semi-hosting interface) defines special behaviours depending on whether an application starts in an environment with BEV set or cleared. When BEV is set then UHI assumes that a bootloader is relatively dumb and has no advanced exception handling logic. However, when BEV is cleared then UHI assumes that the bootloader has the ability to handle UHI exceptions with its exception handlers and will unwind and forward UHI SYSCALL exceptions to the exception vector that was installed prior to running the application. Signed-off-by: Matthew Fortune Signed-off-by: Leon Alrae --- hw/mips/mips_malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 786a8f0..a5d64d5 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -887,7 +887,7 @@ static void main_cpu_reset(void *opaque) read only location. The kernel location and the arguments table location does not change. */ if (loaderparams.kernel_filename) { - env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); + env->CP0_Status &= ~(1 << CP0St_ERL); } malta_mips_config(cpu); -- cgit v1.1 From ff334767728011218c62f7476232d260cb5b28e6 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 19 Jun 2015 11:08:42 +0100 Subject: target-mips: remove identical code in different branch Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/translate.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index a2dbad5..7d9f2da 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -11852,11 +11852,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) * when in debug mode... */ check_insn(ctx, ISA_MIPS32); - if (!(ctx->hflags & MIPS_HFLAG_DM)) { - generate_exception(ctx, EXCP_DBp); - } else { - generate_exception(ctx, EXCP_DBp); - } + generate_exception(ctx, EXCP_DBp); break; case RR_SLT: gen_slt(ctx, OPC_SLT, 24, rx, ry); @@ -12707,11 +12703,7 @@ static void gen_pool16c_insn(DisasContext *ctx) * when in debug mode... */ check_insn(ctx, ISA_MIPS32); - if (!(ctx->hflags & MIPS_HFLAG_DM)) { - generate_exception(ctx, EXCP_DBp); - } else { - generate_exception(ctx, EXCP_DBp); - } + generate_exception(ctx, EXCP_DBp); break; case JRADDIUSP + 0: case JRADDIUSP + 1: @@ -13076,11 +13068,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) break; case SDBBP: check_insn(ctx, ISA_MIPS32); - if (!(ctx->hflags & MIPS_HFLAG_DM)) { - generate_exception(ctx, EXCP_DBp); - } else { - generate_exception(ctx, EXCP_DBp); - } + generate_exception(ctx, EXCP_DBp); break; default: goto pool32axf_invalid; @@ -16849,12 +16837,7 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) * when in debug mode... */ check_insn(ctx, ISA_MIPS32); - if (!(ctx->hflags & MIPS_HFLAG_DM)) { - generate_exception(ctx, EXCP_DBp); - } else { - generate_exception(ctx, EXCP_DBp); - } - /* Treat as NOP. */ + generate_exception(ctx, EXCP_DBp); break; #if defined(TARGET_MIPS64) case OPC_DCLO: -- cgit v1.1 From 3b3c1694cfd394b73de426edebdbf90c28f664fd Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 19 Jun 2015 11:08:43 +0100 Subject: target-mips: add Unified Hosting Interface (UHI) support Add UHI semihosting support for MIPS. QEMU run with "-semihosting" option will alter the behaviour of SDBBP 1 instruction -- UHI operation will be called instead of generating a debug exception. Also tweak Malta's pseudo-bootloader. On CPU reset the $4 register is set to -1 if semihosting arguments are passed to indicate that the UHI operations should be used to obtain input arguments. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- hw/mips/mips_malta.c | 9 +- qemu-options.hx | 10 +- target-mips/Makefile.objs | 2 +- target-mips/helper.h | 2 + target-mips/mips-semi.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 75 ++++++++--- 6 files changed, 408 insertions(+), 26 deletions(-) create mode 100644 target-mips/mips-semi.c diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index a5d64d5..3082e75 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -53,6 +53,7 @@ #include "qemu/error-report.h" #include "hw/empty_slot.h" #include "sysemu/kvm.h" +#include "exec/semihost.h" //#define DEBUG_BOARD_INIT @@ -634,7 +635,13 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, /* Second part of the bootloader */ p = (uint32_t *) (base + 0x580); - stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */ + + if (semihosting_get_argc()) { + /* Preserve a0 content as arguments have been passed */ + stl_p(p++, 0x00000000); /* nop */ + } else { + stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */ + } stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */ stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ diff --git a/qemu-options.hx b/qemu-options.hx index 987dbf0..e6e3895 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3345,20 +3345,22 @@ Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only). ETEXI DEF("semihosting", 0, QEMU_OPTION_semihosting, "-semihosting semihosting mode\n", - QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) + QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | + QEMU_ARCH_MIPS) STEXI @item -semihosting @findex -semihosting -Enable semihosting mode (ARM, M68K, Xtensa only). +Enable semihosting mode (ARM, M68K, Xtensa, MIPS only). ETEXI DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, "-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \ " semihosting configuration\n", -QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) +QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | +QEMU_ARCH_MIPS) STEXI @item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]] @findex -semihosting-config -Enable and configure semihosting (ARM, M68K, Xtensa only). +Enable and configure semihosting (ARM, M68K, Xtensa, MIPS only). @table @option @item target=@code{native|gdb|auto} Defines where the semihosting calls will be addressed, to QEMU (@code{native}) diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs index 108fd9b..bc5ed85 100644 --- a/target-mips/Makefile.objs +++ b/target-mips/Makefile.objs @@ -1,4 +1,4 @@ obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o -obj-y += gdbstub.o msa_helper.o +obj-y += gdbstub.o msa_helper.o mips-semi.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target-mips/helper.h b/target-mips/helper.h index 8df98c7..2b28e87 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -1,6 +1,8 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) +DEF_HELPER_1(do_semihosting, void, env) + #ifdef TARGET_MIPS64 DEF_HELPER_4(sdl, void, env, tl, tl, int) DEF_HELPER_4(sdr, void, env, tl, tl, int) diff --git a/target-mips/mips-semi.c b/target-mips/mips-semi.c new file mode 100644 index 0000000..6944e98 --- /dev/null +++ b/target-mips/mips-semi.c @@ -0,0 +1,336 @@ +/* + * Unified Hosting Interface syscalls. + * + * Copyright (c) 2015 Imagination Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/softmmu-semi.h" +#include "exec/semihost.h" + +typedef enum UHIOp { + UHI_exit = 1, + UHI_open = 2, + UHI_close = 3, + UHI_read = 4, + UHI_write = 5, + UHI_lseek = 6, + UHI_unlink = 7, + UHI_fstat = 8, + UHI_argc = 9, + UHI_argnlen = 10, + UHI_argn = 11, + UHI_plog = 13, + UHI_assert = 14, + UHI_pread = 19, + UHI_pwrite = 20, + UHI_link = 22 +} UHIOp; + +typedef struct UHIStat { + int16_t uhi_st_dev; + uint16_t uhi_st_ino; + uint32_t uhi_st_mode; + uint16_t uhi_st_nlink; + uint16_t uhi_st_uid; + uint16_t uhi_st_gid; + int16_t uhi_st_rdev; + uint64_t uhi_st_size; + uint64_t uhi_st_atime; + uint64_t uhi_st_spare1; + uint64_t uhi_st_mtime; + uint64_t uhi_st_spare2; + uint64_t uhi_st_ctime; + uint64_t uhi_st_spare3; + uint64_t uhi_st_blksize; + uint64_t uhi_st_blocks; + uint64_t uhi_st_spare4[2]; +} UHIStat; + +enum UHIOpenFlags { + UHIOpen_RDONLY = 0x0, + UHIOpen_WRONLY = 0x1, + UHIOpen_RDWR = 0x2, + UHIOpen_APPEND = 0x8, + UHIOpen_CREAT = 0x200, + UHIOpen_TRUNC = 0x400, + UHIOpen_EXCL = 0x800 +}; + +static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src, + target_ulong vaddr) +{ + hwaddr len = sizeof(struct UHIStat); + UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); + if (!dst) { + errno = EFAULT; + return -1; + } + + dst->uhi_st_dev = tswap16(src->st_dev); + dst->uhi_st_ino = tswap16(src->st_ino); + dst->uhi_st_mode = tswap32(src->st_mode); + dst->uhi_st_nlink = tswap16(src->st_nlink); + dst->uhi_st_uid = tswap16(src->st_uid); + dst->uhi_st_gid = tswap16(src->st_gid); + dst->uhi_st_rdev = tswap16(src->st_rdev); + dst->uhi_st_size = tswap64(src->st_size); + dst->uhi_st_atime = tswap64(src->st_atime); + dst->uhi_st_mtime = tswap64(src->st_mtime); + dst->uhi_st_ctime = tswap64(src->st_ctime); +#ifdef _WIN32 + dst->uhi_st_blksize = 0; + dst->uhi_st_blocks = 0; +#else + dst->uhi_st_blksize = tswap64(src->st_blksize); + dst->uhi_st_blocks = tswap64(src->st_blocks); +#endif + unlock_user(dst, vaddr, len); + return 0; +} + +static int get_open_flags(target_ulong target_flags) +{ + int open_flags = 0; + + if (target_flags & UHIOpen_RDWR) { + open_flags |= O_RDWR; + } else if (target_flags & UHIOpen_WRONLY) { + open_flags |= O_WRONLY; + } else { + open_flags |= O_RDONLY; + } + + open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0; + open_flags |= (target_flags & UHIOpen_CREAT) ? O_CREAT : 0; + open_flags |= (target_flags & UHIOpen_TRUNC) ? O_TRUNC : 0; + open_flags |= (target_flags & UHIOpen_EXCL) ? O_EXCL : 0; + + return open_flags; +} + +static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr, + target_ulong len, target_ulong offset) +{ + int num_of_bytes; + void *dst = lock_user(VERIFY_READ, vaddr, len, 1); + if (!dst) { + errno = EFAULT; + return -1; + } + + if (offset) { +#ifdef _WIN32 + num_of_bytes = 0; +#else + num_of_bytes = pwrite(fd, dst, len, offset); +#endif + } else { + num_of_bytes = write(fd, dst, len); + } + + unlock_user(dst, vaddr, 0); + return num_of_bytes; +} + +static int read_from_file(CPUMIPSState *env, target_ulong fd, + target_ulong vaddr, target_ulong len, + target_ulong offset) +{ + int num_of_bytes; + void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); + if (!dst) { + errno = EFAULT; + return -1; + } + + if (offset) { +#ifdef _WIN32 + num_of_bytes = 0; +#else + num_of_bytes = pread(fd, dst, len, offset); +#endif + } else { + num_of_bytes = read(fd, dst, len); + } + + unlock_user(dst, vaddr, len); + return num_of_bytes; +} + +static int copy_argn_to_target(CPUMIPSState *env, int arg_num, + target_ulong vaddr) +{ + int strsize = strlen(semihosting_get_arg(arg_num)) + 1; + char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0); + if (!dst) { + return -1; + } + + strcpy(dst, semihosting_get_arg(arg_num)); + + unlock_user(dst, vaddr, strsize); + return 0; +} + +#define GET_TARGET_STRING(p, addr) \ + do { \ + p = lock_user_string(addr); \ + if (!p) { \ + gpr[2] = -1; \ + gpr[3] = EFAULT; \ + goto uhi_done; \ + } \ + } while (0) + +#define FREE_TARGET_STRING(p, gpr) \ + do { \ + unlock_user(p, gpr, 0); \ + } while (0) + +void helper_do_semihosting(CPUMIPSState *env) +{ + target_ulong *gpr = env->active_tc.gpr; + const UHIOp op = gpr[25]; + char *p, *p2; + + switch (op) { + case UHI_exit: + qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]); + exit(gpr[4]); + case UHI_open: + GET_TARGET_STRING(p, gpr[4]); + if (!strcmp("/dev/stdin", p)) { + gpr[2] = 0; + } else if (!strcmp("/dev/stdout", p)) { + gpr[2] = 1; + } else if (!strcmp("/dev/stderr", p)) { + gpr[2] = 2; + } else { + gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]); + gpr[3] = errno; + } + FREE_TARGET_STRING(p, gpr[4]); + break; + case UHI_close: + if (gpr[4] < 3) { + /* ignore closing stdin/stdout/stderr */ + gpr[2] = 0; + goto uhi_done; + } + gpr[2] = close(gpr[4]); + gpr[3] = errno; + break; + case UHI_read: + gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0); + gpr[3] = errno; + break; + case UHI_write: + gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0); + gpr[3] = errno; + break; + case UHI_lseek: + gpr[2] = lseek(gpr[4], gpr[5], gpr[6]); + gpr[3] = errno; + break; + case UHI_unlink: + GET_TARGET_STRING(p, gpr[4]); + gpr[2] = remove(p); + gpr[3] = errno; + FREE_TARGET_STRING(p, gpr[4]); + break; + case UHI_fstat: + { + struct stat sbuf; + memset(&sbuf, 0, sizeof(sbuf)); + gpr[2] = fstat(gpr[4], &sbuf); + gpr[3] = errno; + if (gpr[2]) { + goto uhi_done; + } + gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]); + gpr[3] = errno; + } + break; + case UHI_argc: + gpr[2] = semihosting_get_argc(); + break; + case UHI_argnlen: + if (gpr[4] >= semihosting_get_argc()) { + gpr[2] = -1; + goto uhi_done; + } + gpr[2] = strlen(semihosting_get_arg(gpr[4])); + break; + case UHI_argn: + if (gpr[4] >= semihosting_get_argc()) { + gpr[2] = -1; + goto uhi_done; + } + gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]); + break; + case UHI_plog: + GET_TARGET_STRING(p, gpr[4]); + p2 = strstr(p, "%d"); + if (p2) { + int char_num = p2 - p; + char *buf = g_malloc(char_num + 1); + strncpy(buf, p, char_num); + buf[char_num] = '\0'; + gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2); + g_free(buf); + } else { + gpr[2] = printf("%s", p); + } + FREE_TARGET_STRING(p, gpr[4]); + break; + case UHI_assert: + GET_TARGET_STRING(p, gpr[4]); + GET_TARGET_STRING(p2, gpr[5]); + printf("assertion '"); + printf("\"%s\"", p); + printf("': file \"%s\", line %d\n", p2, (int)gpr[6]); + FREE_TARGET_STRING(p2, gpr[5]); + FREE_TARGET_STRING(p, gpr[4]); + abort(); + break; + case UHI_pread: + gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); + gpr[3] = errno; + break; + case UHI_pwrite: + gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); + gpr[3] = errno; + break; +#ifndef _WIN32 + case UHI_link: + GET_TARGET_STRING(p, gpr[4]); + GET_TARGET_STRING(p2, gpr[5]); + gpr[2] = link(p, p2); + gpr[3] = errno; + FREE_TARGET_STRING(p2, gpr[5]); + FREE_TARGET_STRING(p, gpr[4]); + break; +#endif + default: + fprintf(stderr, "Unknown UHI operation %d\n", op); + abort(); + } +uhi_done: + return; +} diff --git a/target-mips/translate.c b/target-mips/translate.c index 7d9f2da..8547e2d 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -29,6 +29,7 @@ #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "sysemu/kvm.h" +#include "exec/semihost.h" #include "trace-tcg.h" @@ -11549,6 +11550,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) return 4; } +static inline bool is_uhi(int sdbbp_code) +{ +#ifdef CONFIG_USER_ONLY + return false; +#else + return semihosting_enabled() && sdbbp_code == 1; +#endif +} + static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) { int rx, ry; @@ -11848,11 +11858,15 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) } break; case RR_SDBBP: - /* XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS32); - generate_exception(ctx, EXCP_DBp); + if (is_uhi(extract32(ctx->opcode, 5, 6))) { + gen_helper_do_semihosting(cpu_env); + } else { + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS32); + generate_exception(ctx, EXCP_DBp); + } break; case RR_SLT: gen_slt(ctx, OPC_SLT, 24, rx, ry); @@ -12699,11 +12713,15 @@ static void gen_pool16c_insn(DisasContext *ctx) generate_exception(ctx, EXCP_BREAK); break; case SDBBP16: - /* XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS32); - generate_exception(ctx, EXCP_DBp); + if (is_uhi(extract32(ctx->opcode, 0, 4))) { + gen_helper_do_semihosting(cpu_env); + } else { + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS32); + generate_exception(ctx, EXCP_DBp); + } break; case JRADDIUSP + 0: case JRADDIUSP + 1: @@ -13067,8 +13085,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) ctx->bstate = BS_STOP; break; case SDBBP: - check_insn(ctx, ISA_MIPS32); - generate_exception(ctx, EXCP_DBp); + if (is_uhi(extract32(ctx->opcode, 16, 10))) { + gen_helper_do_semihosting(cpu_env); + } else { + check_insn(ctx, ISA_MIPS32); + generate_exception(ctx, EXCP_DBp); + } break; default: goto pool32axf_invalid; @@ -16460,10 +16482,14 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) } break; case R6_OPC_SDBBP: - if (ctx->hflags & MIPS_HFLAG_SBRI) { - generate_exception(ctx, EXCP_RI); + if (is_uhi(extract32(ctx->opcode, 6, 20))) { + gen_helper_do_semihosting(cpu_env); } else { - generate_exception(ctx, EXCP_DBp); + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception(ctx, EXCP_RI); + } else { + generate_exception(ctx, EXCP_DBp); + } } break; #if defined(TARGET_MIPS64) @@ -16833,11 +16859,15 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) gen_cl(ctx, op1, rd, rs); break; case OPC_SDBBP: - /* XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS32); - generate_exception(ctx, EXCP_DBp); + if (is_uhi(extract32(ctx->opcode, 6, 20))) { + gen_helper_do_semihosting(cpu_env); + } else { + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS32); + generate_exception(ctx, EXCP_DBp); + } break; #if defined(TARGET_MIPS64) case OPC_DCLO: @@ -19910,6 +19940,11 @@ void cpu_state_reset(CPUMIPSState *env) restore_flush_mode(env); restore_pamask(env); cs->exception_index = EXCP_NONE; + + if (semihosting_get_argc()) { + /* UHI interface can be used to obtain argc and argv */ + env->active_tc.gpr[4] = -1; + } } void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos) -- cgit v1.1 From 2c44b19c199f4ce2f1721120744d3d6e5d01d274 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 19 Jun 2015 11:08:44 +0100 Subject: target-mips: convert host to MIPS errno values when required Convert only errno values which can be returned by system calls in mips-semi.c and are not generic to all archs. Signed-off-by: Leon Alrae Reviewed-by: Aurelien Jarno --- target-mips/mips-semi.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/target-mips/mips-semi.c b/target-mips/mips-semi.c index 6944e98..1162c76 100644 --- a/target-mips/mips-semi.c +++ b/target-mips/mips-semi.c @@ -72,6 +72,28 @@ enum UHIOpenFlags { UHIOpen_EXCL = 0x800 }; +/* Errno values taken from asm-mips/errno.h */ +static uint16_t host_to_mips_errno[] = { + [ENAMETOOLONG] = 78, +#ifdef EOVERFLOW + [EOVERFLOW] = 79, +#endif +#ifdef ELOOP + [ELOOP] = 90, +#endif +}; + +static int errno_mips(int err) +{ + if (err < 0 || err >= ARRAY_SIZE(host_to_mips_errno)) { + return EINVAL; + } else if (host_to_mips_errno[err]) { + return host_to_mips_errno[err]; + } else { + return err; + } +} + static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src, target_ulong vaddr) { @@ -223,7 +245,7 @@ void helper_do_semihosting(CPUMIPSState *env) gpr[2] = 2; } else { gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]); - gpr[3] = errno; + gpr[3] = errno_mips(errno); } FREE_TARGET_STRING(p, gpr[4]); break; @@ -234,24 +256,24 @@ void helper_do_semihosting(CPUMIPSState *env) goto uhi_done; } gpr[2] = close(gpr[4]); - gpr[3] = errno; + gpr[3] = errno_mips(errno); break; case UHI_read: gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0); - gpr[3] = errno; + gpr[3] = errno_mips(errno); break; case UHI_write: gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0); - gpr[3] = errno; + gpr[3] = errno_mips(errno); break; case UHI_lseek: gpr[2] = lseek(gpr[4], gpr[5], gpr[6]); - gpr[3] = errno; + gpr[3] = errno_mips(errno); break; case UHI_unlink: GET_TARGET_STRING(p, gpr[4]); gpr[2] = remove(p); - gpr[3] = errno; + gpr[3] = errno_mips(errno); FREE_TARGET_STRING(p, gpr[4]); break; case UHI_fstat: @@ -259,12 +281,12 @@ void helper_do_semihosting(CPUMIPSState *env) struct stat sbuf; memset(&sbuf, 0, sizeof(sbuf)); gpr[2] = fstat(gpr[4], &sbuf); - gpr[3] = errno; + gpr[3] = errno_mips(errno); if (gpr[2]) { goto uhi_done; } gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]); - gpr[3] = errno; + gpr[3] = errno_mips(errno); } break; case UHI_argc: @@ -311,18 +333,18 @@ void helper_do_semihosting(CPUMIPSState *env) break; case UHI_pread: gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); - gpr[3] = errno; + gpr[3] = errno_mips(errno); break; case UHI_pwrite: gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); - gpr[3] = errno; + gpr[3] = errno_mips(errno); break; #ifndef _WIN32 case UHI_link: GET_TARGET_STRING(p, gpr[4]); GET_TARGET_STRING(p2, gpr[5]); gpr[2] = link(p, p2); - gpr[3] = errno; + gpr[3] = errno_mips(errno); FREE_TARGET_STRING(p2, gpr[5]); FREE_TARGET_STRING(p, gpr[4]); break; -- cgit v1.1 From 1bf5902de03732d4067c4e90171a1741d6542c45 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:13 +0100 Subject: target-mips: fix {RD, WR}PGPR in microMIPS rt, rs were swapped Signed-off-by: Yongbok Kim Reviewed-by: Aurelien Jarno Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8547e2d..02c2523 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13001,12 +13001,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) case RDPGPR: check_cp0_enabled(ctx); check_insn(ctx, ISA_MIPS32R2); - gen_load_srsgpr(rt, rs); + gen_load_srsgpr(rs, rt); break; case WRPGPR: check_cp0_enabled(ctx); check_insn(ctx, ISA_MIPS32R2); - gen_store_srsgpr(rt, rs); + gen_store_srsgpr(rs, rt); break; default: goto pool32axf_invalid; -- cgit v1.1 From e60ec06357470db5a0f25901ca19b6237e6da927 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:14 +0100 Subject: target-mips: add microMIPS TLBINV, TLBINVF Add microMIPS TLBINV, TLBINVF Signed-off-by: Yongbok Kim Reviewed-by: Aurelien Jarno Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 02c2523..abff2ab 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12243,6 +12243,8 @@ enum { TLBR = 0x1, TLBWI = 0x2, TLBWR = 0x3, + TLBINV = 0x4, + TLBINVF = 0x5, WAIT = 0x9, IRET = 0xd, DERET = 0xe, @@ -13027,6 +13029,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) case TLBWR: mips32_op = OPC_TLBWR; goto do_cp0; + case TLBINV: + mips32_op = OPC_TLBINV; + goto do_cp0; + case TLBINVF: + mips32_op = OPC_TLBINVF; + goto do_cp0; case WAIT: mips32_op = OPC_WAIT; goto do_cp0; -- cgit v1.1 From f60eeb0c5ddd8ceb8ca6b3ba032159027afab67a Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:15 +0100 Subject: target-mips: remove an unused argument Remove an unused argument from decode_micromips32_opc() Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index abff2ab..146ab25 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13414,8 +13414,7 @@ static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) } } -static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, - uint16_t insn_hw1) +static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) { int32_t offset; uint16_t insn; @@ -14458,7 +14457,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); break; default: - decode_micromips32_opc (env, ctx, op); + decode_micromips32_opc(env, ctx); return 4; } -- cgit v1.1 From 1f1b4c008e250f870719ed38fbd0bcc14322fc01 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:16 +0100 Subject: target-mips: refactor {D}LSA, {D}ALIGN, {D}BITSWAP Refactor those instructions in order to reuse them for microMIPS32 Release 6. Rearrange gen_move_low32(). Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 166 +++++++++++++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 67 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 146ab25..cbe348b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1724,6 +1724,15 @@ static target_long addr_add(DisasContext *ctx, target_long base, return sum; } +static inline void gen_move_low32(TCGv ret, TCGv_i64 arg) +{ +#if defined(TARGET_MIPS64) + tcg_gen_ext32s_tl(ret, arg); +#else + tcg_gen_trunc_i64_tl(ret, arg); +#endif +} + static inline void check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) @@ -4846,17 +4855,94 @@ static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd) tcg_temp_free(t0); } -#ifndef CONFIG_USER_ONLY -/* CP0 (MMU and control) */ -static inline void gen_move_low32(TCGv ret, TCGv_i64 arg) +static void gen_lsa(DisasContext *ctx, int opc, int rd, int rs, int rt, + int imm2) +{ + TCGv t0; + TCGv t1; + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_shli_tl(t0, t0, imm2 + 1); + tcg_gen_add_tl(cpu_gpr[rd], t0, t1); + if (opc == OPC_LSA) { + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } + + tcg_temp_free(t1); + tcg_temp_free(t0); + + return; +} + +static void gen_align(DisasContext *ctx, int opc, int rd, int rs, int rt, + int bp) { + TCGv t0; + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + if (bp == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], t0); + } else { + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t1, rs); + switch (opc) { + case OPC_ALIGN: + { + TCGv_i64 t2 = tcg_temp_new_i64(); + tcg_gen_concat_tl_i64(t2, t1, t0); + tcg_gen_shri_i64(t2, t2, 8 * (4 - bp)); + gen_move_low32(cpu_gpr[rd], t2); + tcg_temp_free_i64(t2); + } + break; #if defined(TARGET_MIPS64) - tcg_gen_ext32s_tl(ret, arg); -#else - tcg_gen_trunc_i64_tl(ret, arg); + case OPC_DALIGN: + tcg_gen_shli_tl(t0, t0, 8 * bp); + tcg_gen_shri_tl(t1, t1, 8 * (8 - bp)); + tcg_gen_or_tl(cpu_gpr[rd], t1, t0); + break; #endif + } + tcg_temp_free(t1); + } + + tcg_temp_free(t0); +} + +static void gen_bitswap(DisasContext *ctx, int opc, int rd, int rt) +{ + TCGv t0; + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + switch (opc) { + case OPC_BITSWAP: + gen_helper_bitswap(cpu_gpr[rd], t0); + break; +#if defined(TARGET_MIPS64) + case OPC_DBITSWAP: + gen_helper_dbitswap(cpu_gpr[rd], t0); + break; +#endif + } + tcg_temp_free(t0); } +#ifndef CONFIG_USER_ONLY +/* CP0 (MMU and control) */ static inline void gen_mthc0_entrylo(TCGv arg, target_ulong off) { TCGv_i64 t0 = tcg_temp_new_i64(); @@ -16442,18 +16528,7 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { case OPC_LSA: - if (rd != 0) { - int imm2 = extract32(ctx->opcode, 6, 3); - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_shli_tl(t0, t0, imm2 + 1); - tcg_gen_add_tl(t0, t0, t1); - tcg_gen_ext32s_tl(cpu_gpr[rd], t0); - tcg_temp_free(t1); - tcg_temp_free(t0); - } + gen_lsa(ctx, op1, rd, rs, rt, extract32(ctx->opcode, 6, 2)); break; case OPC_MULT ... OPC_DIVU: op2 = MASK_R6_MULDIV(ctx->opcode); @@ -16502,17 +16577,7 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) #if defined(TARGET_MIPS64) case OPC_DLSA: check_mips_64(ctx); - if (rd != 0) { - int imm2 = extract32(ctx->opcode, 6, 3); - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_shli_tl(t0, t0, imm2 + 1); - tcg_gen_add_tl(cpu_gpr[rd], t0, t1); - tcg_temp_free(t1); - tcg_temp_free(t0); - } + gen_lsa(ctx, op1, rd, rs, rt, extract32(ctx->opcode, 6, 2)); break; case R6_OPC_DCLO: case R6_OPC_DCLZ: @@ -16936,35 +17001,15 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) /* Treat as NOP. */ break; } - TCGv t0 = tcg_temp_new(); - gen_load_gpr(t0, rt); - op2 = MASK_BSHFL(ctx->opcode); switch (op2) { case OPC_ALIGN ... OPC_ALIGN_END: - sa &= 3; - if (sa == 0) { - tcg_gen_mov_tl(cpu_gpr[rd], t0); - } else { - TCGv t1 = tcg_temp_new(); - TCGv_i64 t2 = tcg_temp_new_i64(); - gen_load_gpr(t1, rs); - tcg_gen_concat_tl_i64(t2, t1, t0); - tcg_gen_shri_i64(t2, t2, 8 * (4 - sa)); -#if defined(TARGET_MIPS64) - tcg_gen_ext32s_i64(cpu_gpr[rd], t2); -#else - tcg_gen_trunc_i64_i32(cpu_gpr[rd], t2); -#endif - tcg_temp_free_i64(t2); - tcg_temp_free(t1); - } + gen_align(ctx, OPC_ALIGN, rd, rs, rt, sa & 3); break; case OPC_BITSWAP: - gen_helper_bitswap(cpu_gpr[rd], t0); + gen_bitswap(ctx, op2, rd, rt); break; } - tcg_temp_free(t0); } break; #if defined(TARGET_MIPS64) @@ -16981,29 +17026,16 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) /* Treat as NOP. */ break; } - TCGv t0 = tcg_temp_new(); - gen_load_gpr(t0, rt); - op2 = MASK_DBSHFL(ctx->opcode); switch (op2) { case OPC_DALIGN ... OPC_DALIGN_END: - sa &= 7; - if (sa == 0) { - tcg_gen_mov_tl(cpu_gpr[rd], t0); - } else { - TCGv t1 = tcg_temp_new(); - gen_load_gpr(t1, rs); - tcg_gen_shli_tl(t0, t0, 8 * sa); - tcg_gen_shri_tl(t1, t1, 8 * (8 - sa)); - tcg_gen_or_tl(cpu_gpr[rd], t1, t0); - tcg_temp_free(t1); - } + gen_align(ctx, OPC_DALIGN, rd, rs, rt, sa & 7); break; case OPC_DBITSWAP: - gen_helper_dbitswap(cpu_gpr[rd], t0); + gen_bitswap(ctx, op2, rd, rt); break; } - tcg_temp_free(t0); + } break; #endif -- cgit v1.1 From 6893f07466b045c5faf314ab9e57ef3b4a6f9e49 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:17 +0100 Subject: target-mips: rearrange gen_compute_compact_branch The function will be also used for microMIPS Release 6. Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 472 ++++++++++++++++++++++++------------------------ 1 file changed, 236 insertions(+), 236 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index cbe348b..76f3c07 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -10971,6 +10971,242 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) } } +/* Compact Branches */ +static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, + int rs, int rt, int32_t offset) +{ + int bcond_compute = 0; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + if (ctx->hflags & MIPS_HFLAG_BMASK) { +#ifdef MIPS_DEBUG_DISAS + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx + "\n", ctx->pc); +#endif + generate_exception(ctx, EXCP_RI); + goto out; + } + + /* Load needed operands and calculate btarget */ + switch (opc) { + /* compact branch */ + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + if (rs <= rt && rs == 0) { + /* OPC_BEQZALC, OPC_BNEZALC */ + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + } + break; + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + break; + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ + if (rs == 0 || rs == rt) { + /* OPC_BLEZALC, OPC_BGEZALC */ + /* OPC_BGTZALC, OPC_BLTZALC */ + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + } + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + break; + case OPC_BC: + case OPC_BALC: + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + break; + case OPC_BEQZC: + case OPC_BNEZC: + if (rs != 0) { + /* OPC_BEQZC, OPC_BNEZC */ + gen_load_gpr(t0, rs); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); + } else { + /* OPC_JIC, OPC_JIALC */ + TCGv tbase = tcg_temp_new(); + TCGv toffset = tcg_temp_new(); + + gen_load_gpr(tbase, rt); + tcg_gen_movi_tl(toffset, offset); + gen_op_addr_add(ctx, btarget, tbase, toffset); + tcg_temp_free(tbase); + tcg_temp_free(toffset); + } + break; + default: + MIPS_INVAL("Compact branch/jump"); + generate_exception(ctx, EXCP_RI); + goto out; + } + + if (bcond_compute == 0) { + /* Uncoditional compact branch */ + switch (opc) { + case OPC_JIALC: + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + /* Fallthrough */ + case OPC_JIC: + ctx->hflags |= MIPS_HFLAG_BR; + break; + case OPC_BALC: + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + /* Fallthrough */ + case OPC_BC: + ctx->hflags |= MIPS_HFLAG_B; + break; + default: + MIPS_INVAL("Compact branch/jump"); + generate_exception(ctx, EXCP_RI); + goto out; + } + + /* Generating branch here as compact branches don't have delay slot */ + gen_branch(ctx, 4); + } else { + /* Conditional compact branch */ + TCGLabel *fs = gen_new_label(); + save_cpu_state(ctx, 0); + + switch (opc) { + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ + if (rs == 0 && rt != 0) { + /* OPC_BLEZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BGEZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); + } else { + /* OPC_BGEUC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GEU), t0, t1, fs); + } + break; + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ + if (rs == 0 && rt != 0) { + /* OPC_BGTZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BLTZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); + } else { + /* OPC_BLTUC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LTU), t0, t1, fs); + } + break; + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ + if (rs == 0 && rt != 0) { + /* OPC_BLEZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BGEZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); + } else { + /* OPC_BGEC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GE), t0, t1, fs); + } + break; + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ + if (rs == 0 && rt != 0) { + /* OPC_BGTZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BLTZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); + } else { + /* OPC_BLTC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); + } + break; + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ + if (rs >= rt) { + /* OPC_BOVC, OPC_BNVC */ + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + TCGv t4 = tcg_temp_new(); + TCGv input_overflow = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_ext32s_tl(t2, t0); + tcg_gen_setcond_tl(TCG_COND_NE, input_overflow, t2, t0); + tcg_gen_ext32s_tl(t3, t1); + tcg_gen_setcond_tl(TCG_COND_NE, t4, t3, t1); + tcg_gen_or_tl(input_overflow, input_overflow, t4); + + tcg_gen_add_tl(t4, t2, t3); + tcg_gen_ext32s_tl(t4, t4); + tcg_gen_xor_tl(t2, t2, t3); + tcg_gen_xor_tl(t3, t4, t3); + tcg_gen_andc_tl(t2, t3, t2); + tcg_gen_setcondi_tl(TCG_COND_LT, t4, t2, 0); + tcg_gen_or_tl(t4, t4, input_overflow); + if (opc == OPC_BOVC) { + /* OPC_BOVC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t4, 0, fs); + } else { + /* OPC_BNVC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t4, 0, fs); + } + tcg_temp_free(input_overflow); + tcg_temp_free(t4); + tcg_temp_free(t3); + tcg_temp_free(t2); + } else if (rs < rt && rs == 0) { + /* OPC_BEQZALC, OPC_BNEZALC */ + if (opc == OPC_BEQZALC) { + /* OPC_BEQZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t1, 0, fs); + } else { + /* OPC_BNEZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t1, 0, fs); + } + } else { + /* OPC_BEQC, OPC_BNEC */ + if (opc == OPC_BEQC) { + /* OPC_BEQC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_EQ), t0, t1, fs); + } else { + /* OPC_BNEC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_NE), t0, t1, fs); + } + } + break; + case OPC_BEQZC: + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t0, 0, fs); + break; + case OPC_BNEZC: + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t0, 0, fs); + break; + default: + MIPS_INVAL("Compact conditional branch/jump"); + generate_exception(ctx, EXCP_RI); + goto out; + } + + /* Generating branch here as compact branches don't have delay slot */ + gen_goto_tb(ctx, 1, ctx->btarget); + gen_set_label(fs); + + ctx->hflags |= MIPS_HFLAG_FBNSLOT; + MIPS_DEBUG("Compact conditional branch"); + } + +out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + /* ISA extensions (ASEs) */ /* MIPS16 extension to MIPS32 */ @@ -16279,242 +16515,6 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, /* End MIPSDSP functions. */ -/* Compact Branches */ -static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, - int rs, int rt, int32_t offset) -{ - int bcond_compute = 0; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - if (ctx->hflags & MIPS_HFLAG_BMASK) { -#ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx - "\n", ctx->pc); -#endif - generate_exception(ctx, EXCP_RI); - goto out; - } - - /* Load needed operands and calculate btarget */ - switch (opc) { - /* compact branch */ - case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ - case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); - if (rs <= rt && rs == 0) { - /* OPC_BEQZALC, OPC_BNEZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); - } - break; - case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ - case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); - break; - case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ - case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ - if (rs == 0 || rs == rt) { - /* OPC_BLEZALC, OPC_BGEZALC */ - /* OPC_BGTZALC, OPC_BLTZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); - } - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); - break; - case OPC_BC: - case OPC_BALC: - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); - break; - case OPC_BEQZC: - case OPC_BNEZC: - if (rs != 0) { - /* OPC_BEQZC, OPC_BNEZC */ - gen_load_gpr(t0, rs); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); - } else { - /* OPC_JIC, OPC_JIALC */ - TCGv tbase = tcg_temp_new(); - TCGv toffset = tcg_temp_new(); - - gen_load_gpr(tbase, rt); - tcg_gen_movi_tl(toffset, offset); - gen_op_addr_add(ctx, btarget, tbase, toffset); - tcg_temp_free(tbase); - tcg_temp_free(toffset); - } - break; - default: - MIPS_INVAL("Compact branch/jump"); - generate_exception(ctx, EXCP_RI); - goto out; - } - - if (bcond_compute == 0) { - /* Uncoditional compact branch */ - switch (opc) { - case OPC_JIALC: - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); - /* Fallthrough */ - case OPC_JIC: - ctx->hflags |= MIPS_HFLAG_BR; - break; - case OPC_BALC: - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); - /* Fallthrough */ - case OPC_BC: - ctx->hflags |= MIPS_HFLAG_B; - break; - default: - MIPS_INVAL("Compact branch/jump"); - generate_exception(ctx, EXCP_RI); - goto out; - } - - /* Generating branch here as compact branches don't have delay slot */ - gen_branch(ctx, 4); - } else { - /* Conditional compact branch */ - TCGLabel *fs = gen_new_label(); - save_cpu_state(ctx, 0); - - switch (opc) { - case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ - if (rs == 0 && rt != 0) { - /* OPC_BLEZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BGEZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); - } else { - /* OPC_BGEUC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GEU), t0, t1, fs); - } - break; - case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ - if (rs == 0 && rt != 0) { - /* OPC_BGTZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BLTZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); - } else { - /* OPC_BLTUC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LTU), t0, t1, fs); - } - break; - case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ - if (rs == 0 && rt != 0) { - /* OPC_BLEZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BGEZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); - } else { - /* OPC_BGEC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GE), t0, t1, fs); - } - break; - case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ - if (rs == 0 && rt != 0) { - /* OPC_BGTZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BLTZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); - } else { - /* OPC_BLTC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); - } - break; - case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ - case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */ - if (rs >= rt) { - /* OPC_BOVC, OPC_BNVC */ - TCGv t2 = tcg_temp_new(); - TCGv t3 = tcg_temp_new(); - TCGv t4 = tcg_temp_new(); - TCGv input_overflow = tcg_temp_new(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_ext32s_tl(t2, t0); - tcg_gen_setcond_tl(TCG_COND_NE, input_overflow, t2, t0); - tcg_gen_ext32s_tl(t3, t1); - tcg_gen_setcond_tl(TCG_COND_NE, t4, t3, t1); - tcg_gen_or_tl(input_overflow, input_overflow, t4); - - tcg_gen_add_tl(t4, t2, t3); - tcg_gen_ext32s_tl(t4, t4); - tcg_gen_xor_tl(t2, t2, t3); - tcg_gen_xor_tl(t3, t4, t3); - tcg_gen_andc_tl(t2, t3, t2); - tcg_gen_setcondi_tl(TCG_COND_LT, t4, t2, 0); - tcg_gen_or_tl(t4, t4, input_overflow); - if (opc == OPC_BOVC) { - /* OPC_BOVC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t4, 0, fs); - } else { - /* OPC_BNVC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t4, 0, fs); - } - tcg_temp_free(input_overflow); - tcg_temp_free(t4); - tcg_temp_free(t3); - tcg_temp_free(t2); - } else if (rs < rt && rs == 0) { - /* OPC_BEQZALC, OPC_BNEZALC */ - if (opc == OPC_BEQZALC) { - /* OPC_BEQZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t1, 0, fs); - } else { - /* OPC_BNEZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t1, 0, fs); - } - } else { - /* OPC_BEQC, OPC_BNEC */ - if (opc == OPC_BEQC) { - /* OPC_BEQC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_EQ), t0, t1, fs); - } else { - /* OPC_BNEC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_NE), t0, t1, fs); - } - } - break; - case OPC_BEQZC: - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t0, 0, fs); - break; - case OPC_BNEZC: - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t0, 0, fs); - break; - default: - MIPS_INVAL("Compact conditional branch/jump"); - generate_exception(ctx, EXCP_RI); - goto out; - } - - /* Generating branch here as compact branches don't have delay slot */ - gen_goto_tb(ctx, 1, ctx->btarget); - gen_set_label(fs); - - ctx->hflags |= MIPS_HFLAG_FBNSLOT; - MIPS_DEBUG("Compact conditional branch"); - } - -out: - tcg_temp_free(t0); - tcg_temp_free(t1); -} - static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; -- cgit v1.1 From e29c962804c4dd3fabd44e703aa87eec555ed910 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:18 +0100 Subject: target-mips: raise RI exceptions when FIR.PS = 0 64-bit paired-single (PS) floating point data type is optional in the pre-Release 6. It has to raise RI exception when PS type is not implemented. (FIR.PS = 0) (The PS data type is removed in the Release 6.) Loongson-2E and Loongson-2F don't have any implementation field in FCSR0(FIR) but do support PS data format, therefore for these cores RI will not be signalled regardless of PS bit. Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 78 ++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 76f3c07..12b291a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1430,6 +1430,7 @@ typedef struct DisasContext { uint64_t PAMask; bool mvh; int CP0_LLAddr_shift; + bool ps; } DisasContext; enum { @@ -1826,6 +1827,16 @@ static inline void check_insn_opc_removed(DisasContext *ctx, int flags) } } +/* This code generates a "reserved instruction" exception if the + CPU does not support 64-bit paired-single (PS) floating point data type */ +static inline void check_ps(DisasContext *ctx) +{ + if (unlikely(!ctx->ps)) { + generate_exception(ctx, EXCP_RI); + } + check_cp1_64bitmode(ctx); +} + #ifdef TARGET_MIPS64 /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ @@ -1859,7 +1870,7 @@ static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \ TCGv_i##bits fp1 = tcg_temp_new_i##bits (); \ switch (ifmt) { \ case FMT_PS: \ - check_cp1_64bitmode(ctx); \ + check_ps(ctx); \ break; \ case FMT_D: \ if (abs) { \ @@ -8999,7 +9010,6 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, }; enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP; uint32_t func = ctx->opcode & 0x3f; - switch (op1) { case OPC_ADD_S: { @@ -9492,8 +9502,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.l.s"; break; case OPC_CVT_PS_S: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp64 = tcg_temp_new_i64(); TCGv_i32 fp32_0 = tcg_temp_new_i32(); @@ -10110,8 +10119,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.d.l"; break; case OPC_CVT_PS_PW: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10123,7 +10131,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.ps.pw"; break; case OPC_ADD_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10138,7 +10146,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "add.ps"; break; case OPC_SUB_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10153,7 +10161,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "sub.ps"; break; case OPC_MUL_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10168,7 +10176,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "mul.ps"; break; case OPC_ABS_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10180,7 +10188,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "abs.ps"; break; case OPC_MOV_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10191,7 +10199,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "mov.ps"; break; case OPC_NEG_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10203,12 +10211,12 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "neg.ps"; break; case OPC_MOVCF_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); gen_movcf_ps(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.ps"; break; case OPC_MOVZ_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGLabel *l1 = gen_new_label(); TCGv_i64 fp0; @@ -10224,7 +10232,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "movz.ps"; break; case OPC_MOVN_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGLabel *l1 = gen_new_label(); TCGv_i64 fp0; @@ -10241,7 +10249,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "movn.ps"; break; case OPC_ADDR_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10256,7 +10264,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "addr.ps"; break; case OPC_MULR_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10271,7 +10279,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "mulr.ps"; break; case OPC_RECIP2_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10286,7 +10294,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "recip2.ps"; break; case OPC_RECIP1_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10298,7 +10306,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "recip1.ps"; break; case OPC_RSQRT1_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10310,7 +10318,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "rsqrt1.ps"; break; case OPC_RSQRT2_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10337,7 +10345,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.s.pu"; break; case OPC_CVT_PW_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); @@ -10361,7 +10369,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "cvt.s.pl"; break; case OPC_PLL_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); @@ -10376,7 +10384,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "pll.ps"; break; case OPC_PLU_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); @@ -10391,7 +10399,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "plu.ps"; break; case OPC_PUL_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); @@ -10406,7 +10414,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, opn = "pul.ps"; break; case OPC_PUU_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); @@ -10565,7 +10573,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, switch (opc) { case OPC_ALNV_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv t0 = tcg_temp_local_new(); TCGv_i32 fp = tcg_temp_new_i32(); @@ -10640,7 +10648,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, opn = "madd.d"; break; case OPC_MADD_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10695,7 +10703,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, opn = "msub.d"; break; case OPC_MSUB_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10750,7 +10758,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, opn = "nmadd.d"; break; case OPC_NMADD_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -10805,7 +10813,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, opn = "nmsub.d"; break; case OPC_NMSUB_PS: - check_cp1_64bitmode(ctx); + check_ps(ctx); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); @@ -14118,6 +14126,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_movcf_d(ctx, rs, rt, cc, 0); break; case FMT_SDPS_PS: + check_ps(ctx); gen_movcf_ps(ctx, rs, rt, cc, 0); break; default: @@ -14133,6 +14142,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_movcf_d(ctx, rs, rt, cc, 1); break; case FMT_SDPS_PS: + check_ps(ctx); gen_movcf_ps(ctx, rs, rt, cc, 1); break; default: @@ -14154,6 +14164,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) mips32_op = OPC_##prfx##_D; \ goto do_fpop; \ case FMT_SDPS_PS: \ + check_ps(ctx); \ mips32_op = OPC_##prfx##_PS; \ goto do_fpop; \ default: \ @@ -19162,8 +19173,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) (rt >> 2) & 0x7, imm << 2); break; case OPC_PS_FMT: - check_cp1_enabled(ctx); - check_insn_opc_removed(ctx, ISA_MIPS32R6); + check_ps(ctx); /* fall through */ case OPC_S_FMT: case OPC_D_FMT: @@ -19472,6 +19482,8 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; + ctx.ps = ((env->active_fpu.fcr0 >> FCR0_PS) & 1) || + (env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)); restore_cpu_state(env, &ctx); #ifdef CONFIG_USER_ONLY ctx.mem_idx = MIPS_HFLAG_UM; -- cgit v1.1 From 9e8f441a7e094c0dc33a1c8f521d9e5bcfc1b4da Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:19 +0100 Subject: target-mips: signal RI for removed instructions in microMIPS R6 Signal a Reserved Instruction exception for removed instruction encoding in microMIPS Release 6. Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 12b291a..ba76880 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13264,15 +13264,19 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) gen_bshfl(ctx, OPC_WSBH, rs, rt); break; case MULT: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MULT; goto do_mul; case MULTU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MULTU; goto do_mul; case DIV: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_DIV; goto do_div; case DIVU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_DIVU; goto do_div; do_div: @@ -13280,15 +13284,19 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) gen_muldiv(ctx, mips32_op, 0, rs, rt); break; case MADD: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MADD; goto do_mul; case MADDU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MADDU; goto do_mul; case MSUB: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MSUB; goto do_mul; case MSUBU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MSUBU; do_mul: check_insn(ctx, ISA_MIPS32); @@ -13321,6 +13329,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) break; case JALRS: case JALRS_HB: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; @@ -13453,6 +13462,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) } break; case 0x35: + check_insn_opc_removed(ctx, ISA_MIPS32R6); switch (minor) { case MFHI32: gen_HILO(ctx, OPC_MFHI, 0, rs); @@ -13725,6 +13735,7 @@ static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) case COND_FLOAT_MOV(MOVT, 5): case COND_FLOAT_MOV(MOVT, 6): case COND_FLOAT_MOV(MOVT, 7): + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1); break; case COND_FLOAT_MOV(MOVF, 0): @@ -13735,6 +13746,7 @@ static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) case COND_FLOAT_MOV(MOVF, 5): case COND_FLOAT_MOV(MOVF, 6): case COND_FLOAT_MOV(MOVF, 7): + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0); break; default: @@ -13805,6 +13817,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) mips32_op = OPC_SUBU; goto do_arith; case MUL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MUL; do_arith: gen_arith(ctx, mips32_op, rd, rs, rt); @@ -13936,47 +13949,61 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) check_cp1_enabled(ctx); switch (minor) { case ALNV_PS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_ALNV_PS; goto do_madd; case MADD_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MADD_S; goto do_madd; case MADD_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MADD_D; goto do_madd; case MADD_PS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MADD_PS; goto do_madd; case MSUB_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MSUB_S; goto do_madd; case MSUB_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MSUB_D; goto do_madd; case MSUB_PS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_MSUB_PS; goto do_madd; case NMADD_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_NMADD_S; goto do_madd; case NMADD_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_NMADD_D; goto do_madd; case NMADD_PS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_NMADD_PS; goto do_madd; case NMSUB_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_NMSUB_S; goto do_madd; case NMSUB_D: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_NMSUB_D; goto do_madd; case NMSUB_PS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_NMSUB_PS; do_madd: gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt); break; case CABS_COND_FMT: + check_insn_opc_removed(ctx, ISA_MIPS32R6); cond = (ctx->opcode >> 6) & 0xf; cc = (ctx->opcode >> 13) & 0x7; fmt = (ctx->opcode >> 10) & 0x3; @@ -13995,6 +14022,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) } break; case C_COND_FMT: + check_insn_opc_removed(ctx, ISA_MIPS32R6); cond = (ctx->opcode >> 6) & 0xf; cc = (ctx->opcode >> 13) & 0x7; fmt = (ctx->opcode >> 10) & 0x3; @@ -14031,6 +14059,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) mips32_op = OPC_PUU_PS; goto do_ps; case CVT_PS_S: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_CVT_PS_S; do_ps: gen_farith(ctx, mips32_op, rt, rs, rd, 0); @@ -14043,21 +14072,27 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) /* [LS][WDU]XC1 */ switch ((ctx->opcode >> 6) & 0x7) { case LWXC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LWXC1; goto do_ldst_cp1; case SWXC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SWXC1; goto do_ldst_cp1; case LDXC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LDXC1; goto do_ldst_cp1; case SDXC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SDXC1; goto do_ldst_cp1; case LUXC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LUXC1; goto do_ldst_cp1; case SUXC1: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SUXC1; do_ldst_cp1: gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs); @@ -14068,6 +14103,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) break; case 0x18: /* 3D insns */ + check_insn_opc_removed(ctx, ISA_MIPS32R6); fmt = (ctx->opcode >> 9) & 0x3; switch ((ctx->opcode >> 6) & 0x7) { case RSQRT2_FMT: @@ -14150,6 +14186,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) } break; case PREFX: + check_insn_opc_removed(ctx, ISA_MIPS32R6); break; default: goto pool32f_invalid; @@ -14226,31 +14263,39 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) minor = (ctx->opcode >> 21) & 0x1f; switch (minor) { case BLTZ: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); break; case BLTZAL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case BLTZALS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case BGEZ: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); break; case BGEZAL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case BGEZALS: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case BLEZ: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); break; case BGTZ: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); break; @@ -14262,15 +14307,18 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) mips32_op = OPC_TGEI; goto do_trapi; case TLTIU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_TLTIU; goto do_trapi; case TGEIU: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_TGEIU; goto do_trapi; case TNEI: mips32_op = OPC_TNEI; goto do_trapi; case TEQI: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_TEQI; do_trapi: gen_trap(ctx, mips32_op, rs, -1, imm); @@ -14278,6 +14326,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) case BNEZC: case BEQZC: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, 4, rs, 0, imm << 1, 0); /* Compact branches don't have a delay slot, so just let @@ -14285,28 +14334,35 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) target. */ break; case LUI: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_logic_imm(ctx, OPC_LUI, rs, 0, imm); break; case SYNCI: + check_insn_opc_removed(ctx, ISA_MIPS32R6); /* Break the TB to be able to sync copied instructions immediately */ ctx->bstate = BS_STOP; break; case BC2F: case BC2T: + check_insn_opc_removed(ctx, ISA_MIPS32R6); /* COP2: Not implemented. */ generate_exception_err(ctx, EXCP_CpU, 2); break; case BC1F: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F; goto do_cp1branch; case BC1T: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T; goto do_cp1branch; case BC1ANY4F: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_BC1FANY4; goto do_cp1mips3d; case BC1ANY4T: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_BC1TANY4; do_cp1mips3d: check_cop1x(ctx); @@ -14335,36 +14391,44 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) minor = (ctx->opcode >> 12) & 0xf; switch (minor) { case LWL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LWL; goto do_ld_lr; case SWL: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SWL; goto do_st_lr; case LWR: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LWR; goto do_ld_lr; case SWR: + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SWR; goto do_st_lr; #if defined(TARGET_MIPS64) case LDL: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LDL; goto do_ld_lr; case SDL: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SDL; goto do_st_lr; case LDR: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_LDR; goto do_ld_lr; case SDR: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_SDR; goto do_st_lr; case LWU: @@ -14438,6 +14502,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_slt_imm(ctx, mips32_op, rt, rs, imm); break; case JALX32: + check_insn_opc_removed(ctx, ISA_MIPS32R6); offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; @@ -14454,10 +14519,12 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); break; case J32: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_J, 4, rt, rs, (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); break; case JAL32: + check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; @@ -14636,6 +14703,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) } break; case POOL16F: + check_insn_opc_removed(ctx, ISA_MIPS32R6); if (ctx->opcode & 1) { generate_exception(ctx, EXCP_RI); } else { -- cgit v1.1 From 3a1f426828cd8ffeec1a4fa8ca6ca3ed4f800edb Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:20 +0100 Subject: target-mips: add microMIPS32 R6 opcode enum Add microMIPS32 Release 6 opcode enum. Remove RI checking for pre-R6 reserved opcode. Signed-off-by: Yongbok Kim Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 119 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 16 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index ba76880..70cc99c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12378,6 +12378,8 @@ enum { LBU16 = 0x02, MOVE16 = 0x03, ADDI32 = 0x04, + R6_LUI = 0x04, + AUI = 0x04, LBU32 = 0x05, SB32 = 0x06, LB32 = 0x07, @@ -12400,56 +12402,88 @@ enum { POOL32S = 0x16, /* MIPS64 */ DADDIU32 = 0x17, /* MIPS64 */ - /* 0x1f is reserved */ POOL32C = 0x18, LWGP16 = 0x19, LW16 = 0x1a, POOL16E = 0x1b, XORI32 = 0x1c, JALS32 = 0x1d, + BOVC = 0x1d, + BEQC = 0x1d, + BEQZALC = 0x1d, ADDIUPC = 0x1e, + PCREL = 0x1e, + BNVC = 0x1f, + BNEC = 0x1f, + BNEZALC = 0x1f, - /* 0x20 is reserved */ - RES_20 = 0x20, + R6_BEQZC = 0x20, + JIC = 0x20, POOL16F = 0x21, SB16 = 0x22, BEQZ16 = 0x23, + BEQZC16 = 0x23, SLTI32 = 0x24, BEQ32 = 0x25, + BC = 0x25, SWC132 = 0x26, LWC132 = 0x27, - /* 0x28 and 0x29 are reserved */ - RES_28 = 0x28, + /* 0x29 is reserved */ RES_29 = 0x29, + R6_BNEZC = 0x28, + JIALC = 0x28, SH16 = 0x2a, BNEZ16 = 0x2b, + BNEZC16 = 0x2b, SLTIU32 = 0x2c, BNE32 = 0x2d, + BALC = 0x2d, SDC132 = 0x2e, LDC132 = 0x2f, - /* 0x30 and 0x31 are reserved */ - RES_30 = 0x30, + /* 0x31 is reserved */ RES_31 = 0x31, + BLEZALC = 0x30, + BGEZALC = 0x30, + BGEUC = 0x30, SWSP16 = 0x32, B16 = 0x33, + BC16 = 0x33, ANDI32 = 0x34, J32 = 0x35, + BGTZC = 0x35, + BLTZC = 0x35, + BLTC = 0x35, SD32 = 0x36, /* MIPS64 */ LD32 = 0x37, /* MIPS64 */ - /* 0x38 and 0x39 are reserved */ - RES_38 = 0x38, + /* 0x39 is reserved */ RES_39 = 0x39, + BGTZALC = 0x38, + BLTZALC = 0x38, + BLTUC = 0x38, SW16 = 0x3a, LI16 = 0x3b, JALX32 = 0x3c, JAL32 = 0x3d, + BLEZC = 0x3d, + BGEZC = 0x3d, + BGEC = 0x3d, SW32 = 0x3e, LW32 = 0x3f }; +/* PCREL Instructions perform PC-Relative address calculation. bits 20..16 */ +enum { + ADDIUPC_00 = 0x00, + ADDIUPC_07 = 0x07, + AUIPC = 0x1e, + ALUIPC = 0x1f, + LWPC_08 = 0x08, + LWPC_0F = 0x0F, +}; + /* POOL32A encoding of minor opcode field */ enum { @@ -12459,6 +12493,8 @@ enum { SRL32 = 0x1, SRA = 0x2, ROTR = 0x3, + SELEQZ = 0x5, + SELNEZ = 0x6, SLLV = 0x0, SRLV = 0x1, @@ -12477,11 +12513,21 @@ enum { SLTU = 0xe, MOVN = 0x0, + R6_MUL = 0x0, MOVZ = 0x1, + MUH = 0x1, + MULU = 0x2, + MUHU = 0x3, LWXS = 0x4, + R6_DIV = 0x4, + MOD = 0x5, + R6_DIVU = 0x6, + MODU = 0x7, /* The following can be distinguished by their lower 6 bits. */ INS = 0x0c, + LSA = 0x0f, + ALIGN = 0x1f, EXT = 0x2c, POOL32AXF = 0x3c }; @@ -12534,6 +12580,7 @@ enum { /* end of microMIPS32 DSP */ /* bits 15..12 for 0x2c */ + BITSWAP = 0x0, SEB = 0x2, SEH = 0x3, CLO = 0x4, @@ -12560,7 +12607,10 @@ enum { /* bits 15..12 for 0x3c */ JALR = 0x0, JR = 0x0, /* alias */ + JALRC = 0x0, + JRC = 0x0, JALR_HB = 0x1, + JALRC_HB = 0x1, JALRS = 0x4, JALRS_HB = 0x5, @@ -12644,32 +12694,39 @@ enum { enum { /* These are the bit 7..6 values */ ADD_FMT = 0x0, - MOVN_FMT = 0x0, SUB_FMT = 0x1, - MOVZ_FMT = 0x1, MUL_FMT = 0x2, DIV_FMT = 0x3, /* These are the bit 8..6 values */ + MOVN_FMT = 0x0, RSQRT2_FMT = 0x0, MOVF_FMT = 0x0, + RINT_FMT = 0x0, + SELNEZ_FMT = 0x0, + MOVZ_FMT = 0x1, LWXC1 = 0x1, MOVT_FMT = 0x1, + CLASS_FMT = 0x1, + SELEQZ_FMT = 0x1, PLL_PS = 0x2, SWXC1 = 0x2, + SEL_FMT = 0x2, PLU_PS = 0x3, LDXC1 = 0x3, + MOVN_FMT_04 = 0x4, PUL_PS = 0x4, SDXC1 = 0x4, RECIP2_FMT = 0x4, + MOVZ_FMT_05 = 0x05, PUU_PS = 0x5, LUXC1 = 0x5, @@ -12677,8 +12734,10 @@ enum { SUXC1 = 0x6, ADDR_PS = 0x6, PREFX = 0x6, + MADDF_FMT = 0x6, MULR_PS = 0x7, + MSUBF_FMT = 0x7, MADD_S = 0x01, MADD_D = 0x09, @@ -12695,10 +12754,17 @@ enum { NMSUB_D = 0x2a, NMSUB_PS = 0x32, + MIN_FMT = 0x3, + MAX_FMT = 0xb, + MINA_FMT = 0x23, + MAXA_FMT = 0x2b, POOL32FXF = 0x3b, CABS_COND_FMT = 0x1c, /* MIPS3D */ - C_COND_FMT = 0x3c + C_COND_FMT = 0x3c, + + CMP_CONDN_S = 0x5, + CMP_CONDN_D = 0x15 }; /* POOL32Fxf encoding of minor opcode extension field */ @@ -12751,10 +12817,15 @@ enum { BGTZ = 0x06, BEQZC = 0x07, TLTI = 0x08, + BC1EQZC = 0x08, TGEI = 0x09, + BC1NEZC = 0x09, TLTIU = 0x0a, + BC2EQZC = 0x0a, TGEIU = 0x0b, + BC2NEZC = 0x0a, TNEI = 0x0c, + R6_SYNCI = 0x0c, LUI = 0x0d, TEQI = 0x0e, SYNCI = 0x10, @@ -12807,6 +12878,26 @@ enum { JRADDIUSP = 0x30 }; +/* R6 POOL16C encoding of minor opcode field (bits 0..5) */ + +enum { + R6_NOT16 = 0x00, + R6_AND16 = 0x01, + R6_LWM16 = 0x02, + R6_JRC16 = 0x03, + MOVEP = 0x04, + MOVEP_07 = 0x07, + R6_XOR16 = 0x08, + R6_OR16 = 0x09, + R6_SWM16 = 0x0a, + JALRC16 = 0x0b, + MOVEP_0C = 0x0c, + MOVEP_0F = 0x0f, + JRCADDIUSP = 0x13, + R6_BREAK16 = 0x1b, + R6_SDBBP16 = 0x3b +}; + /* POOL16D encoding of minor opcode field */ enum { @@ -14848,12 +14939,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) tcg_gen_movi_tl(cpu_gpr[reg], imm); } break; - case RES_20: - case RES_28: case RES_29: - case RES_30: case RES_31: - case RES_38: case RES_39: generate_exception(ctx, EXCP_RI); break; -- cgit v1.1 From 65935f070aa710cf340e96ae7ee36d2c1d5c8d15 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:21 +0100 Subject: target-mips: microMIPS32 R6 branches and jumps Add new microMIPS32 Release 6 branch and jump instructions. Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 242 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 202 insertions(+), 40 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 70cc99c..d0c5317 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -8442,7 +8442,8 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, /* R6 CP1 Branches */ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, - int32_t ft, int32_t offset) + int32_t ft, int32_t offset, + int delayslot_size) { target_ulong btarget; const char *opn = "cp1 cond branch"; @@ -8485,7 +8486,15 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, ctx->hflags, btarget); ctx->btarget = btarget; - ctx->hflags |= MIPS_HFLAG_BDS32; + + switch (delayslot_size) { + case 2: + ctx->hflags |= MIPS_HFLAG_BDS16; + break; + case 4: + ctx->hflags |= MIPS_HFLAG_BDS32; + break; + } out: tcg_temp_free_i64(t0); @@ -10986,6 +10995,7 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, int bcond_compute = 0; TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); + int m16_lowbit = (ctx->hflags & MIPS_HFLAG_M16) != 0; if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS @@ -11007,7 +11017,7 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, ctx->btarget = addr_add(ctx, ctx->pc + 4, offset); if (rs <= rt && rs == 0) { /* OPC_BEQZALC, OPC_BNEZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); } break; case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ @@ -11022,7 +11032,7 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, if (rs == 0 || rs == rt) { /* OPC_BLEZALC, OPC_BGEZALC */ /* OPC_BGTZALC, OPC_BLTZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); } gen_load_gpr(t0, rs); gen_load_gpr(t1, rt); @@ -11062,13 +11072,13 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, /* Uncoditional compact branch */ switch (opc) { case OPC_JIALC: - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); /* Fallthrough */ case OPC_JIC: ctx->hflags |= MIPS_HFLAG_BR; break; case OPC_BALC: - tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4); + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 4 + m16_lowbit); /* Fallthrough */ case OPC_BC: ctx->hflags |= MIPS_HFLAG_B; @@ -13413,10 +13423,16 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) break; case 0x3c: switch (minor) { - case JALR: - case JALR_HB: - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + case JALR: /* JALRC */ + case JALR_HB: /* JALRC_HB */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* JALRC, JALRC_HB */ + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 0); + } else { + /* JALR, JALR_HB */ + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } break; case JALRS: case JALRS_HB: @@ -14391,12 +14407,28 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) break; /* Traps */ - case TLTI: - mips32_op = OPC_TLTI; - goto do_trapi; - case TGEI: - mips32_op = OPC_TGEI; - goto do_trapi; + case TLTI: /* BC1EQZC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* BC1EQZC */ + check_cp1_enabled(ctx); + gen_compute_branch1_r6(ctx, OPC_BC1EQZ, rs, imm << 1, 0); + } else { + /* TLTI */ + mips32_op = OPC_TLTI; + goto do_trapi; + } + break; + case TGEI: /* BC1NEZC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* BC1NEZC */ + check_cp1_enabled(ctx); + gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rs, imm << 1, 0); + } else { + /* TGEI */ + mips32_op = OPC_TGEI; + goto do_trapi; + } + break; case TLTIU: check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_TLTIU; @@ -14598,27 +14630,84 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; - case JALS32: - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; - gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + case JALS32: /* BOVC, BEQC, BEQZALC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rs >= rt) { + /* BOVC */ + mips32_op = OPC_BOVC; + } else if (rs < rt && rs == 0) { + /* BEQZALC */ + mips32_op = OPC_BEQZALC; + } else { + /* BEQC */ + mips32_op = OPC_BEQC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* JALS32 */ + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } break; - case BEQ32: - gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); + case BEQ32: /* BC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* BC */ + gen_compute_compact_branch(ctx, OPC_BC, 0, 0, + sextract32(ctx->opcode << 1, 0, 27)); + } else { + /* BEQ32 */ + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); + } break; - case BNE32: - gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); + case BNE32: /* BALC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* BALC */ + gen_compute_compact_branch(ctx, OPC_BALC, 0, 0, + sextract32(ctx->opcode << 1, 0, 27)); + } else { + /* BNE32 */ + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); + } break; - case J32: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_compute_branch(ctx, OPC_J, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + case J32: /* BGTZC, BLTZC, BLTC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rs == 0 && rt != 0) { + /* BGTZC */ + mips32_op = OPC_BGTZC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BLTZC */ + mips32_op = OPC_BLTZC; + } else { + /* BLTC */ + mips32_op = OPC_BLTC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* J32 */ + gen_compute_branch(ctx, OPC_J, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + } break; - case JAL32: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + case JAL32: /* BLEZC, BGEZC, BGEC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + if (rs == 0 && rt != 0) { + /* BLEZC */ + mips32_op = OPC_BLEZC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BGEZC */ + mips32_op = OPC_BGEZC; + } else { + /* BGEC */ + mips32_op = OPC_BGEC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* JAL32 */ + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } break; /* Floating point (COP1) */ case LWC132: @@ -14643,6 +14732,70 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_addiupc(ctx, reg, offset, 0, 0); } break; + case BNVC: /* BNEC, BNEZALC */ + check_insn(ctx, ISA_MIPS32R6); + if (rs >= rt) { + /* BNVC */ + mips32_op = OPC_BNVC; + } else if (rs < rt && rs == 0) { + /* BNEZALC */ + mips32_op = OPC_BNEZALC; + } else { + /* BNEC */ + mips32_op = OPC_BNEC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + case R6_BNEZC: /* JIALC */ + check_insn(ctx, ISA_MIPS32R6); + if (rt != 0) { + /* BNEZC */ + gen_compute_compact_branch(ctx, OPC_BNEZC, rt, 0, + sextract32(ctx->opcode << 1, 0, 22)); + } else { + /* JIALC */ + gen_compute_compact_branch(ctx, OPC_JIALC, 0, rs, imm); + } + break; + case R6_BEQZC: /* JIC */ + check_insn(ctx, ISA_MIPS32R6); + if (rt != 0) { + /* BEQZC */ + gen_compute_compact_branch(ctx, OPC_BEQZC, rt, 0, + sextract32(ctx->opcode << 1, 0, 22)); + } else { + /* JIC */ + gen_compute_compact_branch(ctx, OPC_JIC, 0, rs, imm); + } + break; + case BLEZALC: /* BGEZALC, BGEUC */ + check_insn(ctx, ISA_MIPS32R6); + if (rs == 0 && rt != 0) { + /* BLEZALC */ + mips32_op = OPC_BLEZALC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BGEZALC */ + mips32_op = OPC_BGEZALC; + } else { + /* BGEUC */ + mips32_op = OPC_BGEUC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + case BGTZALC: /* BLTZALC, BLTUC */ + check_insn(ctx, ISA_MIPS32R6); + if (rs == 0 && rt != 0) { + /* BGTZALC */ + mips32_op = OPC_BGTZALC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BLTZALC */ + mips32_op = OPC_BLTZALC; + } else { + /* BLTUC */ + mips32_op = OPC_BLTUC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; /* Loads and stores */ case LB32: mips32_op = OPC_LB; @@ -14920,15 +15073,18 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) break; } break; - case B16: + case B16: /* BC16 */ gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, - SIMM(ctx->opcode, 0, 10) << 1, 4); + sextract32(ctx->opcode, 0, 10) << 1, + (ctx->insn_flags & ISA_MIPS32R6) ? 0 : 4); break; - case BNEZ16: - case BEQZ16: + case BNEZ16: /* BNEZC16 */ + case BEQZ16: /* BEQZC16 */ gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, mmreg(uMIPS_RD(ctx->opcode)), - 0, SIMM(ctx->opcode, 0, 7) << 1, 4); + 0, sextract32(ctx->opcode, 0, 7) << 1, + (ctx->insn_flags & ISA_MIPS32R6) ? 0 : 4); + break; case LI16: { @@ -19300,7 +19456,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) if (ctx->insn_flags & ISA_MIPS32R6) { /* OPC_BC1EQZ */ gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), - rt, imm << 2); + rt, imm << 2, 4); } else { /* OPC_BC1ANY2 */ check_cop1x(ctx); @@ -19313,7 +19469,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) check_cp1_enabled(ctx); check_insn(ctx, ISA_MIPS32R6); gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), - rt, imm << 2); + rt, imm << 2, 4); break; case OPC_BC1ANY4: check_cp1_enabled(ctx); @@ -19708,6 +19864,12 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, forbidden slot */ is_slot = 1; } + if ((ctx.hflags & MIPS_HFLAG_M16) && + (ctx.hflags & MIPS_HFLAG_FBNSLOT)) { + /* Force to generate branch as microMIPS R6 doesn't restrict + branches in the forbidden slot. */ + is_slot = 1; + } } if (is_slot) { gen_branch(&ctx, insn_bytes); -- cgit v1.1 From e03320958305a68f2bc6a32c87d7ed48303438f9 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:22 +0100 Subject: target-mips: microMIPS32 R6 POOL32A{XF} instructions Add new microMIPS32 Release 6 pool32a/pool32axf instructions. Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 82 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index d0c5317..cfcc154 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13343,6 +13343,10 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) break; case 0x2c: switch (minor) { + case BITSWAP: + check_insn(ctx, ISA_MIPS32R6); + gen_bitswap(ctx, OPC_BITSWAP, rs, rt); + break; case SEB: gen_bshfl(ctx, OPC_SEB, rs, rt); break; @@ -13543,7 +13547,11 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) gen_helper_do_semihosting(cpu_env); } else { check_insn(ctx, ISA_MIPS32); - generate_exception(ctx, EXCP_DBp); + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception(ctx, EXCP_RI); + } else { + generate_exception(ctx, EXCP_DBp); + } } break; default: @@ -13903,6 +13911,14 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) do_shifti: gen_shift_imm(ctx, mips32_op, rt, rs, rd); break; + case SELEQZ: + check_insn(ctx, ISA_MIPS32R6); + gen_cond_move(ctx, OPC_SELEQZ, rd, rs, rt); + break; + case SELNEZ: + check_insn(ctx, ISA_MIPS32R6); + gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt); + break; default: goto pool32a_invalid; } @@ -13976,16 +13992,52 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) minor = (ctx->opcode >> 6) & 0xf; switch (minor) { /* Conditional moves */ - case MOVN: - mips32_op = OPC_MOVN; - goto do_cmov; - case MOVZ: - mips32_op = OPC_MOVZ; - do_cmov: - gen_cond_move(ctx, mips32_op, rd, rs, rt); + case MOVN: /* MUL */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* MUL */ + gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); + } else { + /* MOVN */ + gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); + } + break; + case MOVZ: /* MUH */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* MUH */ + gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); + } else { + /* MOVZ */ + gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); + } + break; + case MULU: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); + break; + case MUHU: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); + break; + case LWXS: /* DIV */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* DIV */ + gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); + } else { + /* LWXS */ + gen_ldxs(ctx, rs, rt, rd); + } break; - case LWXS: - gen_ldxs(ctx, rs, rt, rd); + case MOD: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); + break; + case R6_DIVU: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); + break; + case MODU: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); break; default: goto pool32a_invalid; @@ -13994,6 +14046,16 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) case INS: gen_bitops(ctx, OPC_INS, rt, rs, rr, rd); return; + case LSA: + check_insn(ctx, ISA_MIPS32R6); + gen_lsa(ctx, OPC_LSA, rd, rs, rt, + extract32(ctx->opcode, 9, 2)); + break; + case ALIGN: + check_insn(ctx, ISA_MIPS32R6); + gen_align(ctx, OPC_ALIGN, rd, rs, rt, + extract32(ctx->opcode, 9, 2)); + break; case EXT: gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); return; -- cgit v1.1 From 2a24a7badeb6ad3ba72e7984f299623035d564d6 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:23 +0100 Subject: target-mips: microMIPS32 R6 POOL32F instructions Add new microMIPS32 Release 6 POOL32F instructions Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 231 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 199 insertions(+), 32 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index cfcc154..1c9bfdb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -14209,6 +14209,14 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) goto pool32f_invalid; } break; + case CMP_CONDN_S: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_cmp_s(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); + break; + case CMP_CONDN_D: + check_insn(ctx, ISA_MIPS32R6); + gen_r6_cmp_d(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); + break; case POOL32FXF: gen_pool32fxf(ctx, rt, rs); break; @@ -14237,6 +14245,19 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) goto pool32f_invalid; } break; + case MIN_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; case 0x08: /* [LS][WDU]XC1 */ switch ((ctx->opcode >> 6) & 0x7) { @@ -14270,6 +14291,19 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) goto pool32f_invalid; } break; + case MAX_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; case 0x18: /* 3D insns */ check_insn_opc_removed(ctx, ISA_MIPS32R6); @@ -14318,40 +14352,70 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) } break; case 0x20: - /* MOV[FT].fmt and PREFX */ + /* MOV[FT].fmt, PREFX, RINT.fmt, CLASS.fmt*/ cc = (ctx->opcode >> 13) & 0x7; fmt = (ctx->opcode >> 9) & 0x3; switch ((ctx->opcode >> 6) & 0x7) { - case MOVF_FMT: - switch (fmt) { - case FMT_SDPS_S: - gen_movcf_s(ctx, rs, rt, cc, 0); - break; - case FMT_SDPS_D: - gen_movcf_d(ctx, rs, rt, cc, 0); - break; - case FMT_SDPS_PS: - check_ps(ctx); - gen_movcf_ps(ctx, rs, rt, cc, 0); - break; - default: - goto pool32f_invalid; + case MOVF_FMT: /* RINT_FMT */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* RINT_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVF_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_PS: + check_ps(ctx); + gen_movcf_ps(ctx, rs, rt, cc, 0); + break; + default: + goto pool32f_invalid; + } } break; - case MOVT_FMT: - switch (fmt) { - case FMT_SDPS_S: - gen_movcf_s(ctx, rs, rt, cc, 1); - break; - case FMT_SDPS_D: - gen_movcf_d(ctx, rs, rt, cc, 1); - break; - case FMT_SDPS_PS: - check_ps(ctx); - gen_movcf_ps(ctx, rs, rt, cc, 1); - break; - default: - goto pool32f_invalid; + case MOVT_FMT: /* CLASS_FMT */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* CLASS_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVT_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_PS: + check_ps(ctx); + gen_movcf_ps(ctx, rs, rt, cc, 1); + break; + default: + goto pool32f_invalid; + } } break; case PREFX: @@ -14376,6 +14440,32 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) default: \ goto pool32f_invalid; \ } + case MINA_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case MAXA_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; case 0x30: /* regular FP ops */ switch ((ctx->opcode >> 6) & 0x3) { @@ -14404,13 +14494,90 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) break; case 0x38: /* cmovs */ - switch ((ctx->opcode >> 6) & 0x3) { - case MOVN_FMT: + switch ((ctx->opcode >> 6) & 0x7) { + case MOVN_FMT: /* SELNEZ_FMT */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* SELNEZ_FMT */ + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVN_FMT */ + FINSN_3ARG_SDPS(MOVN); + } + break; + case MOVN_FMT_04: + check_insn_opc_removed(ctx, ISA_MIPS32R6); FINSN_3ARG_SDPS(MOVN); break; - case MOVZ_FMT: + case MOVZ_FMT: /* SELEQZ_FMT */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* SELEQZ_FMT */ + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVZ_FMT */ + FINSN_3ARG_SDPS(MOVZ); + } + break; + case MOVZ_FMT_05: + check_insn_opc_removed(ctx, ISA_MIPS32R6); FINSN_3ARG_SDPS(MOVZ); break; + case SEL_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + break; + case MADDF_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + mips32_op = OPC_MADDF_S; + goto do_fpop; + case FMT_SDPS_D: + mips32_op = OPC_MADDF_D; + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + case MSUBF_FMT: + check_insn(ctx, ISA_MIPS32R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + mips32_op = OPC_MSUBF_S; + goto do_fpop; + case FMT_SDPS_D: + mips32_op = OPC_MSUBF_D; + goto do_fpop; + default: + goto pool32f_invalid; + } + break; default: goto pool32f_invalid; } -- cgit v1.1 From 3b4a5489447e7ed17cc504572cf729833853e7ab Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:24 +0100 Subject: target-mips: microMIPS32 R6 POOL32{I, C} instructions Add new microMIPS32 Release 6 POOL32I/POOL32C type instructions Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 1c9bfdb..1e79c5a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -14666,9 +14666,18 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_TGEIU; goto do_trapi; - case TNEI: - mips32_op = OPC_TNEI; - goto do_trapi; + case TNEI: /* SYNCI */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* SYNCI */ + /* Break the TB to be able to sync copied instructions + immediately */ + ctx->bstate = BS_STOP; + } else { + /* TNEI */ + mips32_op = OPC_TNEI; + goto do_trapi; + } + break; case TEQI: check_insn_opc_removed(ctx, ISA_MIPS32R6); mips32_op = OPC_TEQI; @@ -14741,6 +14750,8 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) break; case POOL32C: minor = (ctx->opcode >> 12) & 0xf; + offset = sextract32(ctx->opcode, 0, + (ctx->insn_flags & ISA_MIPS32R6) ? 9 : 12); switch (minor) { case LWL: check_insn_opc_removed(ctx, ISA_MIPS32R6); @@ -14798,23 +14809,27 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) mips32_op = OPC_LL; goto do_ld_lr; do_ld_lr: - gen_ld(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); + gen_ld(ctx, mips32_op, rt, rs, offset); break; do_st_lr: gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); break; case SC: - gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12)); + gen_st_cond(ctx, OPC_SC, rt, rs, offset); break; #if defined(TARGET_MIPS64) case SCD: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12)); + gen_st_cond(ctx, OPC_SCD, rt, rs, offset); break; #endif case PREF: /* Treat as no-op */ + if ((ctx->insn_flags & ISA_MIPS32R6) && (rt >= 24)) { + /* hint codes 24-31 are reserved and signal RI */ + generate_exception(ctx, EXCP_RI); + } break; default: MIPS_INVAL("pool32c"); -- cgit v1.1 From ab39ee452d74855adec91056812b8e1e5166302c Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:25 +0100 Subject: target-mips: microMIPS32 R6 Major instructions Add new microMIPS32 Release 6 Major opcode instructions Signed-off-by: Yongbok Kim Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 62 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 1e79c5a..38dcf9e 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -3209,45 +3209,46 @@ static inline void gen_r6_ld(target_long addr, int reg, int memidx, tcg_temp_free(t0); } -static inline void gen_pcrel(DisasContext *ctx, int rs, int16_t imm) +static inline void gen_pcrel(DisasContext *ctx, int opc, target_ulong pc, + int rs) { target_long offset; target_long addr; - switch (MASK_OPC_PCREL_TOP2BITS(ctx->opcode)) { + switch (MASK_OPC_PCREL_TOP2BITS(opc)) { case OPC_ADDIUPC: if (rs != 0) { offset = sextract32(ctx->opcode << 2, 0, 21); - addr = addr_add(ctx, ctx->pc, offset); + addr = addr_add(ctx, pc, offset); tcg_gen_movi_tl(cpu_gpr[rs], addr); } break; case R6_OPC_LWPC: offset = sextract32(ctx->opcode << 2, 0, 21); - addr = addr_add(ctx, ctx->pc, offset); + addr = addr_add(ctx, pc, offset); gen_r6_ld(addr, rs, ctx->mem_idx, MO_TESL); break; #if defined(TARGET_MIPS64) case OPC_LWUPC: check_mips_64(ctx); offset = sextract32(ctx->opcode << 2, 0, 21); - addr = addr_add(ctx, ctx->pc, offset); + addr = addr_add(ctx, pc, offset); gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUL); break; #endif default: - switch (MASK_OPC_PCREL_TOP5BITS(ctx->opcode)) { + switch (MASK_OPC_PCREL_TOP5BITS(opc)) { case OPC_AUIPC: if (rs != 0) { - offset = imm << 16; - addr = addr_add(ctx, ctx->pc, offset); + offset = sextract32(ctx->opcode, 0, 16) << 16; + addr = addr_add(ctx, pc, offset); tcg_gen_movi_tl(cpu_gpr[rs], addr); } break; case OPC_ALUIPC: if (rs != 0) { - offset = imm << 16; - addr = ~0xFFFF & addr_add(ctx, ctx->pc, offset); + offset = sextract32(ctx->opcode, 0, 16) << 16; + addr = ~0xFFFF & addr_add(ctx, pc, offset); tcg_gen_movi_tl(cpu_gpr[rs], addr); } break; @@ -3258,7 +3259,7 @@ static inline void gen_pcrel(DisasContext *ctx, int rs, int16_t imm) case R6_OPC_LDPC + (3 << 16): check_mips_64(ctx); offset = sextract32(ctx->opcode << 3, 0, 21); - addr = addr_add(ctx, (ctx->pc & ~0x7), offset); + addr = addr_add(ctx, (pc & ~0x7), offset); gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEQ); break; #endif @@ -14837,9 +14838,16 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) break; } break; - case ADDI32: - mips32_op = OPC_ADDI; - goto do_addi; + case ADDI32: /* AUI, LUI */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* AUI, LUI */ + gen_logic_imm(ctx, OPC_LUI, rt, rs, imm); + } else { + /* ADDI32 */ + mips32_op = OPC_ADDI; + goto do_addi; + } + break; case ADDIU32: mips32_op = OPC_ADDIU; do_addi: @@ -14968,8 +14976,28 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) do_cop1: gen_cop1_ldst(ctx, mips32_op, rt, rs, imm); break; - case ADDIUPC: - { + case ADDIUPC: /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ + switch ((ctx->opcode >> 16) & 0x1f) { + case ADDIUPC_00 ... ADDIUPC_07: + gen_pcrel(ctx, OPC_ADDIUPC, ctx->pc & ~0x3, rt); + break; + case AUIPC: + gen_pcrel(ctx, OPC_AUIPC, ctx->pc, rt); + break; + case ALUIPC: + gen_pcrel(ctx, OPC_ALUIPC, ctx->pc, rt); + break; + case LWPC_08 ... LWPC_0F: + gen_pcrel(ctx, R6_OPC_LWPC, ctx->pc & ~0x3, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + } else { + /* ADDIUPC */ int reg = mmreg(ZIMM(ctx->opcode, 23, 3)); int offset = SIMM(ctx->opcode, 0, 23) << 2; @@ -19989,7 +20017,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) break; case OPC_PCREL: check_insn(ctx, ISA_MIPS32R6); - gen_pcrel(ctx, rs, imm); + gen_pcrel(ctx, ctx->opcode, ctx->pc, rs); break; default: /* Invalid */ MIPS_INVAL("major opcode"); -- cgit v1.1 From ed7ce6c0f9d4370826557ce33d652beb88ccb3e6 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:26 +0100 Subject: target-mips: microMIPS32 R6 POOL16{A, C} instructions microMIPS32 Release 6 POOL16A/ POOL16C instructions Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate.c | 133 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 15 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 38dcf9e..7302857 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13173,6 +13173,110 @@ static void gen_pool16c_insn(DisasContext *ctx) } } +static inline void gen_movep(DisasContext *ctx, int enc_dest, int enc_rt, + int enc_rs) +{ + int rd, rs, re, rt; + static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; + static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; + static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; + rd = rd_enc[enc_dest]; + re = re_enc[enc_dest]; + rs = rs_rt_enc[enc_rs]; + rt = rs_rt_enc[enc_rt]; + if (rs) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + if (rt) { + tcg_gen_mov_tl(cpu_gpr[re], cpu_gpr[rt]); + } else { + tcg_gen_movi_tl(cpu_gpr[re], 0); + } +} + +static void gen_pool16c_r6_insn(DisasContext *ctx) +{ + int rt = mmreg((ctx->opcode >> 7) & 0x7); + int rs = mmreg((ctx->opcode >> 4) & 0x7); + + switch (ctx->opcode & 0xf) { + case R6_NOT16: + gen_logic(ctx, OPC_NOR, rt, rs, 0); + break; + case R6_AND16: + gen_logic(ctx, OPC_AND, rt, rt, rs); + break; + case R6_LWM16: + { + int lwm_converted = 0x11 + extract32(ctx->opcode, 8, 2); + int offset = extract32(ctx->opcode, 4, 4); + gen_ldst_multiple(ctx, LWM32, lwm_converted, 29, offset << 2); + } + break; + case R6_JRC16: /* JRCADDIUSP */ + if ((ctx->opcode >> 4) & 1) { + /* JRCADDIUSP */ + int imm = extract32(ctx->opcode, 5, 5); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); + } else { + /* JRC16 */ + int rs = extract32(ctx->opcode, 5, 5); + gen_compute_branch(ctx, OPC_JR, 2, rs, 0, 0, 0); + } + break; + case MOVEP ... MOVEP_07: + case MOVEP_0C ... MOVEP_0F: + { + int enc_dest = uMIPS_RD(ctx->opcode); + int enc_rt = uMIPS_RS2(ctx->opcode); + int enc_rs = (ctx->opcode & 3) | ((ctx->opcode >> 1) & 4); + gen_movep(ctx, enc_dest, enc_rt, enc_rs); + } + break; + case R6_XOR16: + gen_logic(ctx, OPC_XOR, rt, rt, rs); + break; + case R6_OR16: + gen_logic(ctx, OPC_OR, rt, rt, rs); + break; + case R6_SWM16: + { + int swm_converted = 0x11 + extract32(ctx->opcode, 8, 2); + int offset = extract32(ctx->opcode, 4, 4); + gen_ldst_multiple(ctx, SWM32, swm_converted, 29, offset << 2); + } + break; + case JALRC16: /* BREAK16, SDBBP16 */ + switch (ctx->opcode & 0x3f) { + case JALRC16: + case JALRC16 + 0x20: + /* JALRC16 */ + gen_compute_branch(ctx, OPC_JALR, 2, (ctx->opcode >> 5) & 0x1f, + 31, 0, 0); + break; + case R6_BREAK16: + /* BREAK16 */ + generate_exception(ctx, EXCP_BREAK); + break; + case R6_SDBBP16: + /* SDBBP16 */ + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception(ctx, EXCP_RI); + } else { + generate_exception(ctx, EXCP_DBp); + } + break; + } + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } +} + static void gen_ldxs (DisasContext *ctx, int base, int index, int rd) { TCGv t0 = tcg_temp_new(); @@ -15182,8 +15286,14 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) opc = OPC_SUBU; break; } - - gen_arith(ctx, opc, rd, rs1, rs2); + if (ctx->insn_flags & ISA_MIPS32R6) { + /* In the Release 6 the register number location in + * the instruction encoding has changed. + */ + gen_arith(ctx, opc, rs1, rd, rs2); + } else { + gen_arith(ctx, opc, rd, rs1, rs2); + } } break; case POOL16B: @@ -15207,7 +15317,11 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) } break; case POOL16C: - gen_pool16c_insn(ctx); + if (ctx->insn_flags & ISA_MIPS32R6) { + gen_pool16c_r6_insn(ctx); + } else { + gen_pool16c_insn(ctx); + } break; case LWGP16: { @@ -15227,18 +15341,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) int enc_dest = uMIPS_RD(ctx->opcode); int enc_rt = uMIPS_RS2(ctx->opcode); int enc_rs = uMIPS_RS1(ctx->opcode); - int rd, rs, re, rt; - static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; - static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; - static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; - - rd = rd_enc[enc_dest]; - re = re_enc[enc_dest]; - rs = rs_rt_enc[enc_rs]; - rt = rs_rt_enc[enc_rt]; - - gen_arith(ctx, OPC_ADDU, rd, rs, 0); - gen_arith(ctx, OPC_ADDU, re, rt, 0); + gen_movep(ctx, enc_dest, enc_rt, enc_rs); } break; case LBU16: -- cgit v1.1 From 4b3bcd016d83cc75f6a495c1db54b6c77f037adc Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Thu, 25 Jun 2015 00:24:27 +0100 Subject: target-mips: add mips32r6-generic CPU definition Define a new CPU definition supporting MIPS32 Release 6 ISA and microMIPS32 Release 6 ISA. Signed-off-by: Yongbok Kim Reviewed-by: Aurelien Jarno Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 30605da..ddfaff8 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -424,6 +424,43 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA, .mmu_type = MMU_TYPE_R4000, }, + { + /* A generic CPU supporting MIPS32 Release 6 ISA. + FIXME: Support IEEE 754-2008 FP. + Eventually this should be replaced by a real CPU model. */ + .name = "mips32r6-generic", + .CP0_PRid = 0x00010000, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AR) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) | + (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | + (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | + (0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_BP) | (1 << CP0C3_BI) | + (2 << CP0C3_ISA) | (1 << CP0C3_ULRI) | + (1 << CP0C3_RXI) | (1U << CP0C3_M), + .CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) | + (3 << CP0C4_IE) | (1U << CP0C4_M), + .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_LLB), + .CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) | + (1 << CP0C5_UFE), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 0, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x3058FF1F, + .CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) | + (1U << CP0PG_RIE), + .CP0_PageGrain_rw_bitmask = 0, + .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) | + (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | + (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 32, + .PABITS = 32, + .insn_flags = CPU_MIPS32R6 | ASE_MICROMIPS, + .mmu_type = MMU_TYPE_R4000, + }, #if defined(TARGET_MIPS64) { .name = "R4000", -- cgit v1.1