From e98c0d179fe43adb99a39b7bf7c74820adc3c0ca Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:23:55 +0100 Subject: [PATCH 01/34] target-mips: add KScratch registers KScratch Registers (CP0 Register 31, Selects 2 to 7) The KScratch registers are read/write registers available for scratch pad storage by kernel mode software. They are 32-bits in width for 32-bit processors and 64-bits for 64-bit processors. CP0Config4.KScrExist[2:7] bits indicate presence of CP0_KScratch1-6 registers. For Release 6, all KScratch registers are required. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 3 +++ target-mips/translate.c | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 26e7894eaf..91e781e26a 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -136,6 +136,7 @@ typedef struct mips_def_t mips_def_t; #define MIPS_TC_MAX 5 #define MIPS_FPU_MAX 1 #define MIPS_DSP_ACC 4 +#define MIPS_KSCRATCH_NUM 6 typedef struct TCState TCState; struct TCState { @@ -229,6 +230,7 @@ struct CPUMIPSState { target_ulong CP0_EntryLo0; target_ulong CP0_EntryLo1; target_ulong CP0_Context; + target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM]; int32_t CP0_PageMask; int32_t CP0_PageGrain; int32_t CP0_Wired; @@ -375,6 +377,7 @@ struct CPUMIPSState { uint32_t CP0_Config4; uint32_t CP0_Config4_rw_bitmask; #define CP0C4_M 31 +#define CP0C4_KScrExist 16 uint32_t CP0_Config5; uint32_t CP0_Config5_rw_bitmask; #define CP0C5_M 31 diff --git a/target-mips/translate.c b/target-mips/translate.c index 446eb8a20f..167f9bc545 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1170,6 +1170,7 @@ typedef struct DisasContext { int bstate; target_ulong btarget; bool ulri; + int kscrexist; } DisasContext; enum { @@ -4567,6 +4568,15 @@ static inline void gen_mtc0_store64 (TCGv arg, target_ulong off) tcg_gen_st_tl(arg, cpu_env, off); } +static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg) +{ + if (ctx->insn_flags & ISA_MIPS32R6) { + tcg_gen_movi_tl(arg, 0); + } else { + tcg_gen_movi_tl(arg, ~0); + } +} + static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; @@ -5149,6 +5159,16 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); rn = "DESAVE"; break; + case 2 ... 7: + if (ctx->kscrexist & (1 << sel)) { + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + tcg_gen_ext32s_tl(arg, arg); + rn = "KScratch"; + } else { + gen_mfc0_unimplemented(ctx, arg); + } + break; default: goto die; } @@ -5757,6 +5777,13 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); rn = "DESAVE"; break; + case 2 ... 7: + if (ctx->kscrexist & (1 << sel)) { + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + rn = "KScratch"; + } + break; default: goto die; } @@ -6344,6 +6371,15 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); rn = "DESAVE"; break; + case 2 ... 7: + if (ctx->kscrexist & (1 << sel)) { + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + rn = "KScratch"; + } else { + gen_mfc0_unimplemented(ctx, arg); + } + break; default: goto die; } @@ -6943,6 +6979,13 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE)); rn = "DESAVE"; break; + case 2 ... 7: + if (ctx->kscrexist & (1 << sel)) { + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + rn = "KScratch"; + } + break; default: goto die; } @@ -17414,6 +17457,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.CP0_Config1 = env->CP0_Config1; ctx.tb = tb; ctx.bstate = BS_NONE; + ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff; /* 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 & (1 << CP0C3_ULRI); From 55e9409366c5b7954a5dfb3efec9b191c238dd12 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:23:56 +0100 Subject: [PATCH 02/34] softmmu: provide softmmu access type enum New MIPS features depend on the access type and enum is more convenient than using the numbers directly. Signed-off-by: Leon Alrae Reviewed-by: Thomas Huth --- include/exec/cpu-common.h | 6 ++++++ softmmu_template.h | 26 ++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index e3ec4c8e0c..427b8515a3 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -26,6 +26,12 @@ typedef struct CPUListState { FILE *file; } CPUListState; +typedef enum MMUAccessType { + MMU_DATA_LOAD = 0, + MMU_DATA_STORE = 1, + MMU_INST_FETCH = 2 +} MMUAccessType; + #if !defined(CONFIG_USER_ONLY) enum device_endian { diff --git a/softmmu_template.h b/softmmu_template.h index 88e33900b6..6b4e615dbf 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -67,10 +67,10 @@ #endif #ifdef SOFTMMU_CODE_ACCESS -#define READ_ACCESS_TYPE 2 +#define READ_ACCESS_TYPE MMU_INST_FETCH #define ADDR_READ addr_code #else -#define READ_ACCESS_TYPE 0 +#define READ_ACCESS_TYPE MMU_DATA_LOAD #define ADDR_READ addr_read #endif @@ -396,11 +396,12 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { - cpu_unaligned_access(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, + mmu_idx, retaddr); } #endif if (!VICTIM_TLB_HIT(addr_write)) { - tlb_fill(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); } tlb_addr = env->tlb_table[mmu_idx][index].addr_write; } @@ -427,7 +428,8 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, int i; do_unaligned_access: #ifdef ALIGNED_ONLY - cpu_unaligned_access(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, + mmu_idx, retaddr); #endif /* XXX: not efficient, but simple */ /* Note: relies on the fact that tlb_fill() does not remove the @@ -446,7 +448,8 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, /* Handle aligned access or unaligned access in the same page. */ #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { - cpu_unaligned_access(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, + mmu_idx, retaddr); } #endif @@ -474,11 +477,12 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { - cpu_unaligned_access(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, + mmu_idx, retaddr); } #endif if (!VICTIM_TLB_HIT(addr_write)) { - tlb_fill(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); } tlb_addr = env->tlb_table[mmu_idx][index].addr_write; } @@ -505,7 +509,8 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, int i; do_unaligned_access: #ifdef ALIGNED_ONLY - cpu_unaligned_access(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, + mmu_idx, retaddr); #endif /* XXX: not efficient, but simple */ /* Note: relies on the fact that tlb_fill() does not remove the @@ -524,7 +529,8 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, /* Handle aligned access or unaligned access in the same page. */ #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { - cpu_unaligned_access(ENV_GET_CPU(env), addr, 1, mmu_idx, retaddr); + cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, + mmu_idx, retaddr); } #endif From 9f6bcedba61927438000fb94b0706c22dfb87eaa Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:23:57 +0100 Subject: [PATCH 03/34] target-mips: distinguish between data load and instruction fetch Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/helper.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index fe16820885..1c9e69d8f4 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -87,7 +87,7 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, /* Check access rights */ if (!(n ? tlb->V1 : tlb->V0)) return TLBRET_INVALID; - if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { + if (rw != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & (mask >> 1)); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) @@ -237,25 +237,28 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, case TLBRET_BADADDR: /* Reference to kernel address from user mode or supervisor mode */ /* Reference to supervisor address from user mode */ - if (rw) + if (rw == MMU_DATA_STORE) { exception = EXCP_AdES; - else + } else { exception = EXCP_AdEL; + } break; case TLBRET_NOMATCH: /* No TLB match for a mapped address */ - if (rw) + if (rw == MMU_DATA_STORE) { exception = EXCP_TLBS; - else + } else { exception = EXCP_TLBL; + } error_code = 1; break; case TLBRET_INVALID: /* TLB match with no valid bit */ - if (rw) + if (rw == MMU_DATA_STORE) { exception = EXCP_TLBS; - else + } else { exception = EXCP_TLBL; + } break; case TLBRET_DIRTY: /* TLB match but 'D' bit is cleared */ @@ -312,8 +315,6 @@ int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, qemu_log("%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n", __func__, env->active_tc.PC, address, rw, mmu_idx); - rw &= 1; - /* data access */ #if !defined(CONFIG_USER_ONLY) /* XXX: put correct access by using cpu_restore_state() @@ -347,8 +348,6 @@ hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int r int access_type; int ret = 0; - rw &= 1; - /* data access */ access_type = ACCESS_INT; ret = get_physical_address(env, &physical, &prot, From 2fb58b73746e2f99ac85e82160277b18b18279be Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:23:58 +0100 Subject: [PATCH 04/34] target-mips: add RI and XI fields to TLB entry In Revision 3 of the architecture, the RI and XI bits were added to the TLB to enable more secure access of memory pages. These bits (along with the Dirty bit) allow the implementation of read-only, write-only, no-execute access policies for mapped pages. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 11 +++++++++++ target-mips/helper.c | 11 ++++++++++- target-mips/op_helper.c | 8 ++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 91e781e26a..13f3a48198 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -30,6 +30,10 @@ struct r4k_tlb_t { uint_fast16_t V1:1; uint_fast16_t D0:1; uint_fast16_t D1:1; + uint_fast16_t XI0:1; + uint_fast16_t XI1:1; + uint_fast16_t RI0:1; + uint_fast16_t RI1:1; target_ulong PFN[2]; }; @@ -229,6 +233,13 @@ struct CPUMIPSState { #define CP0VPEOpt_DWX0 0 target_ulong CP0_EntryLo0; target_ulong CP0_EntryLo1; +#if defined(TARGET_MIPS64) +# define CP0EnLo_RI 63 +# define CP0EnLo_XI 62 +#else +# define CP0EnLo_RI 31 +# define CP0EnLo_XI 30 +#endif target_ulong CP0_Context; target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM]; int32_t CP0_PageMask; diff --git a/target-mips/helper.c b/target-mips/helper.c index 1c9e69d8f4..49187a3d08 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -27,6 +27,8 @@ #include "sysemu/kvm.h" enum { + TLBRET_XI = -6, + TLBRET_RI = -5, TLBRET_DIRTY = -4, TLBRET_INVALID = -3, TLBRET_NOMATCH = -2, @@ -85,8 +87,15 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, /* TLB match */ int n = !!(address & mask & ~(mask >> 1)); /* Check access rights */ - if (!(n ? tlb->V1 : tlb->V0)) + if (!(n ? tlb->V1 : tlb->V0)) { return TLBRET_INVALID; + } + if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) { + return TLBRET_XI; + } + if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) { + return TLBRET_RI; + } if (rw != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & (mask >> 1)); *prot = PAGE_READ; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9ec548cc02..582c84e1a4 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1849,10 +1849,14 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx) tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; + tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1; + tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1; tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; + tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1; + tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1; tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; } @@ -1964,8 +1968,12 @@ void r4k_helper_tlbr(CPUMIPSState *env) env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_PageMask = tlb->PageMask; env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | + ((target_ulong)tlb->RI0 << CP0EnLo_RI) | + ((target_ulong)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | + ((target_ulong)tlb->RI1 << CP0EnLo_RI) | + ((target_ulong)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); } From 7207c7f9d74816c32783a394d8072d1f978157ac Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:23:59 +0100 Subject: [PATCH 05/34] target-mips: update PageGrain and m{t,f}c0 EntryLo{0,1} PageGrain needs rw bitmask which differs between MIPS architectures. In pre-R6 if RIXI is supported, PageGrain.XIE and PageGrain.RIE are writeable, whereas in R6 they are read-only 1. On MIPS64 mtc0 instruction left shifts bits 31:30 for MIPS32 backward compatiblity, therefore there are separate mtc0 and dmtc0 helpers. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 4 ++++ target-mips/helper.h | 5 +++++ target-mips/op_helper.c | 25 ++++++++++++++++++++++--- target-mips/translate.c | 26 ++++++++++++++++++++++++-- target-mips/translate_init.c | 2 ++ 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 13f3a48198..38f90f27f4 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -243,7 +243,10 @@ struct CPUMIPSState { target_ulong CP0_Context; target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM]; int32_t CP0_PageMask; + int32_t CP0_PageGrain_rw_bitmask; int32_t CP0_PageGrain; +#define CP0PG_RIE 31 +#define CP0PG_XIE 30 int32_t CP0_Wired; int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0; @@ -377,6 +380,7 @@ struct CPUMIPSState { #define CP0C3_M 31 #define CP0C3_ISA_ON_EXC 16 #define CP0C3_ULRI 13 +#define CP0C3_RXI 12 #define CP0C3_DSPP 10 #define CP0C3_LPA 7 #define CP0C3_VEIC 6 diff --git a/target-mips/helper.h b/target-mips/helper.h index a127db55c2..e7e0c8c4ca 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -152,6 +152,11 @@ DEF_HELPER_2(mtc0_datalo, void, env, tl) DEF_HELPER_2(mtc0_taghi, void, env, tl) DEF_HELPER_2(mtc0_datahi, void, env, tl) +#if defined(TARGET_MIPS64) +DEF_HELPER_2(dmtc0_entrylo0, void, env, i64) +DEF_HELPER_2(dmtc0_entrylo1, void, env, i64) +#endif + /* MIPS MT functions */ DEF_HELPER_2(mftgpr, tl, env, i32) DEF_HELPER_2(mftlo, tl, env, i32) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 582c84e1a4..024a6a2b31 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1099,9 +1099,18 @@ void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) { /* Large physaddr (PABITS) not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF; + target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); + env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); } +#if defined(TARGET_MIPS64) +void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1) +{ + uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); + env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi; +} +#endif + void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1) { uint32_t mask = env->CP0_TCStatus_rw_bitmask; @@ -1266,9 +1275,18 @@ void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) { /* Large physaddr (PABITS) not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF; + target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); + env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); } +#if defined(TARGET_MIPS64) +void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1) +{ + uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); + env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi; +} +#endif + void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) { env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF); @@ -1285,7 +1303,8 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) /* SmartMIPS not implemented */ /* Large physaddr (PABITS) not implemented */ /* 1k pages not implemented */ - env->CP0_PageGrain = 0; + env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) | + (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask); } void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) diff --git a/target-mips/translate.c b/target-mips/translate.c index 167f9bc545..e8933a9dd4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1171,6 +1171,7 @@ typedef struct DisasContext { target_ulong btarget; bool ulri; int kscrexist; + bool rxi; } DisasContext; enum { @@ -4659,6 +4660,15 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0)); +#if defined(TARGET_MIPS64) + if (ctx->rxi) { + TCGv tmp = tcg_temp_new(); + tcg_gen_andi_tl(tmp, arg, (3ull << 62)); + tcg_gen_shri_tl(tmp, tmp, 32); + tcg_gen_or_tl(arg, arg, tmp); + tcg_temp_free(tmp); + } +#endif tcg_gen_ext32s_tl(arg, arg); rn = "EntryLo0"; break; @@ -4705,6 +4715,15 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) switch (sel) { case 0: tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1)); +#if defined(TARGET_MIPS64) + if (ctx->rxi) { + TCGv tmp = tcg_temp_new(); + tcg_gen_andi_tl(tmp, arg, (3ull << 62)); + tcg_gen_shri_tl(tmp, tmp, 32); + tcg_gen_or_tl(arg, arg, tmp); + tcg_temp_free(tmp); + } +#endif tcg_gen_ext32s_tl(arg, arg); rn = "EntryLo1"; break; @@ -6480,7 +6499,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 2: switch (sel) { case 0: - gen_helper_mtc0_entrylo0(cpu_env, arg); + gen_helper_dmtc0_entrylo0(cpu_env, arg); rn = "EntryLo0"; break; case 1: @@ -6525,7 +6544,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 3: switch (sel) { case 0: - gen_helper_mtc0_entrylo1(cpu_env, arg); + gen_helper_dmtc0_entrylo1(cpu_env, arg); rn = "EntryLo1"; break; default: @@ -17458,6 +17477,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.tb = tb; ctx.bstate = BS_NONE; ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff; + ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1; /* 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 & (1 << CP0C3_ULRI); @@ -17840,6 +17860,8 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3; env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask; env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4; + env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask; + env->CP0_PageGrain = env->cpu_model->CP0_PageGrain; env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0; env->insn_flags = env->cpu_model->insn_flags; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 67b7837750..779afff2d4 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -96,6 +96,8 @@ struct mips_def_t { int32_t CP0_SRSConf3; int32_t CP0_SRSConf4_rw_bitmask; int32_t CP0_SRSConf4; + int32_t CP0_PageGrain_rw_bitmask; + int32_t CP0_PageGrain; int insn_flags; enum mips_mmu_types mmu_type; }; From 92ceb440d47b9ef3ba860cdc75a7e31563a7dc0c Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:23:59 +0100 Subject: [PATCH 06/34] target-mips: add new Read-Inhibit and Execute-Inhibit exceptions An Execute-Inhibit exception occurs when the virtual address of an instruction fetch matches a TLB entry whose XI bit is set. This exception type can only occur if the XI bit is implemented within the TLB and is enabled, this is denoted by the PageGrain XIE bit. An Read-Inhibit exception occurs when the virtual address of a memory load reference matches a TLB entry whose RI bit is set. This exception type can only occur if the RI bit is implemented within the TLB and is enabled, this is denoted by the PageGrain RIE bit. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 5 ++++- target-mips/helper.c | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 38f90f27f4..a9e1bc2eb4 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -247,6 +247,7 @@ struct CPUMIPSState { int32_t CP0_PageGrain; #define CP0PG_RIE 31 #define CP0PG_XIE 30 +#define CP0PG_IEC 27 int32_t CP0_Wired; int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0; @@ -646,8 +647,10 @@ enum { EXCP_C2E, EXCP_CACHE, /* 32 */ EXCP_DSPDIS, + EXCP_TLBXI, + EXCP_TLBRI, - EXCP_LAST = EXCP_DSPDIS, + EXCP_LAST = EXCP_TLBRI, }; /* Dummy exception for conditional stores. */ #define EXCP_SC 0x100 diff --git a/target-mips/helper.c b/target-mips/helper.c index 49187a3d08..37038ef799 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -273,7 +273,22 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, /* TLB match but 'D' bit is cleared */ exception = EXCP_LTLBL; break; - + case TLBRET_XI: + /* Execute-Inhibit Exception */ + if (env->CP0_PageGrain & (1 << CP0PG_IEC)) { + exception = EXCP_TLBXI; + } else { + exception = EXCP_TLBL; + } + break; + case TLBRET_RI: + /* Read-Inhibit Exception */ + if (env->CP0_PageGrain & (1 << CP0PG_IEC)) { + exception = EXCP_TLBRI; + } else { + exception = EXCP_TLBL; + } + break; } /* Raise exception */ env->CP0_BadVAddr = address; @@ -404,6 +419,8 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_MDMX] = "MDMX", [EXCP_C2E] = "precise coprocessor 2", [EXCP_CACHE] = "cache error", + [EXCP_TLBXI] = "TLB execute-inhibit", + [EXCP_TLBRI] = "TLB read-inhibit", }; target_ulong exception_resume_pc (CPUMIPSState *env) @@ -622,6 +639,12 @@ void mips_cpu_do_interrupt(CPUState *cs) case EXCP_C2E: cause = 18; goto set_EPC; + case EXCP_TLBRI: + cause = 19; + goto set_EPC; + case EXCP_TLBXI: + cause = 20; + goto set_EPC; case EXCP_MDMX: cause = 22; goto set_EPC; From 9456c2fbcd82dd82328ac6e7602a815582b1043e Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:24:00 +0100 Subject: [PATCH 07/34] target-mips: add TLBINV support For Standard TLB configuration (Config.MT=1): TLBINV invalidates a set of TLB entries based on ASID. The virtual address is ignored in the entry match. TLB entries which have their G bit set to 1 are not modified. TLBINVF causes all entries to be invalidated. Single TLB entry can be marked as invalid on TLB entry write by having EntryHi.EHINV set to 1. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- disas/mips.c | 2 ++ target-mips/cpu.h | 7 ++++ target-mips/helper.c | 2 +- target-mips/helper.h | 2 ++ target-mips/op_helper.c | 65 ++++++++++++++++++++++++++++++++---- target-mips/translate.c | 22 ++++++++++++ target-mips/translate_init.c | 2 ++ 7 files changed, 94 insertions(+), 8 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 7297825138..4974bc0da2 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -2410,6 +2410,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, {"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, {"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbinv", "", 0x42000003, 0xffffffff, INSN_TLB, 0, I32 }, +{"tlbinvf", "", 0x42000004, 0xffffffff, INSN_TLB, 0, I32 }, {"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, {"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, {"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, diff --git a/target-mips/cpu.h b/target-mips/cpu.h index a9e1bc2eb4..9c38b4ff74 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -34,6 +34,7 @@ struct r4k_tlb_t { uint_fast16_t XI1:1; uint_fast16_t RI0:1; uint_fast16_t RI1:1; + uint_fast16_t EHINV:1; target_ulong PFN[2]; }; @@ -47,6 +48,8 @@ struct CPUMIPSTLBContext { void (*helper_tlbwr)(struct CPUMIPSState *env); void (*helper_tlbp)(struct CPUMIPSState *env); void (*helper_tlbr)(struct CPUMIPSState *env); + void (*helper_tlbinv)(struct CPUMIPSState *env); + void (*helper_tlbinvf)(struct CPUMIPSState *env); union { struct { r4k_tlb_t tlb[MIPS_TLB_MAX]; @@ -282,6 +285,7 @@ struct CPUMIPSState { target_ulong CP0_BadVAddr; int32_t CP0_Count; target_ulong CP0_EntryHi; +#define CP0EnHi_EHINV 10 int32_t CP0_Compare; int32_t CP0_Status; #define CP0St_CU3 31 @@ -393,6 +397,7 @@ struct CPUMIPSState { uint32_t CP0_Config4; uint32_t CP0_Config4_rw_bitmask; #define CP0C4_M 31 +#define CP0C4_IE 29 #define CP0C4_KScrExist 16 uint32_t CP0_Config5; uint32_t CP0_Config5_rw_bitmask; @@ -529,6 +534,8 @@ void r4k_helper_tlbwi(CPUMIPSState *env); void r4k_helper_tlbwr(CPUMIPSState *env); void r4k_helper_tlbp(CPUMIPSState *env); void r4k_helper_tlbr(CPUMIPSState *env); +void r4k_helper_tlbinv(CPUMIPSState *env); +void r4k_helper_tlbinvf(CPUMIPSState *env); void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write, bool is_exec, int unused, diff --git a/target-mips/helper.c b/target-mips/helper.c index 37038ef799..05325d92e9 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -83,7 +83,7 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, #endif /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) { /* TLB match */ int n = !!(address & mask & ~(mask >> 1)); /* Check access rights */ diff --git a/target-mips/helper.h b/target-mips/helper.h index e7e0c8c4ca..aea12a90d6 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -342,6 +342,8 @@ DEF_HELPER_1(tlbwi, void, env) DEF_HELPER_1(tlbwr, void, env) DEF_HELPER_1(tlbp, void, env) DEF_HELPER_1(tlbr, void, env) +DEF_HELPER_1(tlbinv, void, env) +DEF_HELPER_1(tlbinvf, void, env) DEF_HELPER_1(di, tl, env) DEF_HELPER_1(ei, tl, env) DEF_HELPER_1(eret, void, env) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 024a6a2b31..c33f0eb91a 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1361,10 +1361,14 @@ void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) { - target_ulong old, val; + target_ulong old, val, mask; + mask = (TARGET_PAGE_MASK << 1) | 0xFF; + if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) { + mask |= 1 << CP0EnHi_EHINV; + } /* 1k pages not implemented */ - val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF); + val = arg1 & mask; #if defined(TARGET_MIPS64) val &= env->SEGMask; #endif @@ -1858,6 +1862,11 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb->mmu.r4k.tlb[idx]; + if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) { + tlb->EHINV = 1; + return; + } + tlb->EHINV = 0; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); #if defined(TARGET_MIPS64) tlb->VPN &= env->SEGMask; @@ -1879,6 +1888,31 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx) tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; } +void r4k_helper_tlbinv(CPUMIPSState *env) +{ + int idx; + r4k_tlb_t *tlb; + uint8_t ASID = env->CP0_EntryHi & 0xFF; + + for (idx = 0; idx < env->tlb->nb_tlb; idx++) { + tlb = &env->tlb->mmu.r4k.tlb[idx]; + if (!tlb->G && tlb->ASID == ASID) { + tlb->EHINV = 1; + } + } + cpu_mips_tlb_flush(env, 1); +} + +void r4k_helper_tlbinvf(CPUMIPSState *env) +{ + int idx; + + for (idx = 0; idx < env->tlb->nb_tlb; idx++) { + env->tlb->mmu.r4k.tlb[idx].EHINV = 1; + } + cpu_mips_tlb_flush(env, 1); +} + void r4k_helper_tlbwi(CPUMIPSState *env) { r4k_tlb_t *tlb; @@ -1940,7 +1974,7 @@ void r4k_helper_tlbp(CPUMIPSState *env) tag &= env->SEGMask; #endif /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) { /* TLB match */ env->CP0_Index = i; break; @@ -1984,16 +2018,23 @@ void r4k_helper_tlbr(CPUMIPSState *env) r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); - env->CP0_EntryHi = tlb->VPN | tlb->ASID; - env->CP0_PageMask = tlb->PageMask; - env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | + if (tlb->EHINV) { + env->CP0_EntryHi = 1 << CP0EnHi_EHINV; + env->CP0_PageMask = 0; + env->CP0_EntryLo0 = 0; + env->CP0_EntryLo1 = 0; + } else { + env->CP0_EntryHi = tlb->VPN | tlb->ASID; + env->CP0_PageMask = tlb->PageMask; + env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | ((target_ulong)tlb->RI0 << CP0EnLo_RI) | ((target_ulong)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); - env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | + env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | ((target_ulong)tlb->RI1 << CP0EnLo_RI) | ((target_ulong)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); + } } void helper_tlbwi(CPUMIPSState *env) @@ -2016,6 +2057,16 @@ void helper_tlbr(CPUMIPSState *env) env->tlb->helper_tlbr(env); } +void helper_tlbinv(CPUMIPSState *env) +{ + env->tlb->helper_tlbinv(env); +} + +void helper_tlbinvf(CPUMIPSState *env) +{ + env->tlb->helper_tlbinvf(env); +} + /* Specials */ target_ulong helper_di(CPUMIPSState *env) { diff --git a/target-mips/translate.c b/target-mips/translate.c index e8933a9dd4..fdb61be8d3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -896,6 +896,8 @@ enum { enum { OPC_TLBR = 0x01 | OPC_C0, OPC_TLBWI = 0x02 | OPC_C0, + OPC_TLBINV = 0x03 | OPC_C0, + OPC_TLBINVF = 0x04 | OPC_C0, OPC_TLBWR = 0x06 | OPC_C0, OPC_TLBP = 0x08 | OPC_C0, OPC_RFE = 0x10 | OPC_C0, @@ -1172,6 +1174,7 @@ typedef struct DisasContext { bool ulri; int kscrexist; bool rxi; + int ie; } DisasContext; enum { @@ -7516,6 +7519,24 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, goto die; gen_helper_tlbwi(cpu_env); break; + case OPC_TLBINV: + opn = "tlbinv"; + if (ctx->ie >= 2) { + if (!env->tlb->helper_tlbinv) { + goto die; + } + gen_helper_tlbinv(cpu_env); + } /* treat as nop if TLBINV not supported */ + break; + case OPC_TLBINVF: + opn = "tlbinvf"; + if (ctx->ie >= 2) { + if (!env->tlb->helper_tlbinvf) { + goto die; + } + gen_helper_tlbinvf(cpu_env); + } /* treat as nop if TLBINV not supported */ + break; case OPC_TLBWR: opn = "tlbwr"; if (!env->tlb->helper_tlbwr) @@ -17478,6 +17499,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.bstate = BS_NONE; ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff; ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1; + ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 3; /* 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 & (1 << CP0C3_ULRI); diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 779afff2d4..bcfc46a715 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -657,6 +657,8 @@ static void r4k_mmu_init (CPUMIPSState *env, const mips_def_t *def) env->tlb->helper_tlbwr = r4k_helper_tlbwr; env->tlb->helper_tlbp = r4k_helper_tlbp; env->tlb->helper_tlbr = r4k_helper_tlbr; + env->tlb->helper_tlbinv = r4k_helper_tlbinv; + env->tlb->helper_tlbinvf = r4k_helper_tlbinvf; } static void mmu_init (CPUMIPSState *env, const mips_def_t *def) From aea14095ea91f792ee43ee52fe6032cd8cdd7190 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:24:01 +0100 Subject: [PATCH 08/34] target-mips: add BadInstr and BadInstrP support BadInstr Register (CP0 Register 8, Select 1) The BadInstr register is a read-only register that capture the most recent instruction which caused an exception. BadInstrP Register (CP0 Register 8, Select 2) The BadInstrP register contains the prior branch instruction, when the faulting instruction is in a branch delay slot. Using error_code to indicate whether AdEL or TLBL was triggered during instruction fetch, in this case BadInstr is not updated as valid instruction word is not available. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 6 ++++ target-mips/helper.c | 45 ++++++++++++++++++++++-- target-mips/op_helper.c | 17 +++++++-- target-mips/translate.c | 76 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 133 insertions(+), 11 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 9c38b4ff74..4687f4f2cf 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -283,6 +283,8 @@ struct CPUMIPSState { #define CP0SRSC4_SRS13 0 int32_t CP0_HWREna; target_ulong CP0_BadVAddr; + uint32_t CP0_BadInstr; + uint32_t CP0_BadInstrP; int32_t CP0_Count; target_ulong CP0_EntryHi; #define CP0EnHi_EHINV 10 @@ -383,6 +385,8 @@ struct CPUMIPSState { #define CP0C2_SA 0 int32_t CP0_Config3; #define CP0C3_M 31 +#define CP0C3_BP 27 +#define CP0C3_BI 26 #define CP0C3_ISA_ON_EXC 16 #define CP0C3_ULRI 13 #define CP0C3_RXI 12 @@ -453,6 +457,8 @@ struct CPUMIPSState { CPUMIPSFPUContext fpus[MIPS_FPU_MAX]; /* QEMU */ int error_code; +#define EXCP_TLB_NOMATCH 0x1 +#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ #define MIPS_HFLAG_TMASK 0x1807FF diff --git a/target-mips/helper.c b/target-mips/helper.c index 05325d92e9..c92b25c2a0 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -25,6 +25,7 @@ #include "cpu.h" #include "sysemu/kvm.h" +#include "exec/cpu_ldst.h" enum { TLBRET_XI = -6, @@ -241,6 +242,10 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, CPUState *cs = CPU(mips_env_get_cpu(env)); int exception = 0, error_code = 0; + if (rw == MMU_INST_FETCH) { + error_code |= EXCP_INST_NOTAVAIL; + } + switch (tlb_error) { default: case TLBRET_BADADDR: @@ -259,7 +264,7 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, } else { exception = EXCP_TLBL; } - error_code = 1; + error_code |= EXCP_TLB_NOMATCH; break; case TLBRET_INVALID: /* TLB match with no valid bit */ @@ -451,6 +456,21 @@ static void set_hflags_for_handler (CPUMIPSState *env) << MIPS_HFLAG_M16_SHIFT); } } + +static inline void set_badinstr_registers(CPUMIPSState *env) +{ + if (env->hflags & MIPS_HFLAG_M16) { + /* TODO: add BadInstr support for microMIPS */ + return; + } + if (env->CP0_Config3 & (1 << CP0C3_BI)) { + env->CP0_BadInstr = cpu_ldl_code(env, env->active_tc.PC); + } + if ((env->CP0_Config3 & (1 << CP0C3_BP)) && + (env->hflags & MIPS_HFLAG_BMASK)) { + env->CP0_BadInstrP = cpu_ldl_code(env, env->active_tc.PC - 4); + } +} #endif void mips_cpu_do_interrupt(CPUState *cs) @@ -458,6 +478,7 @@ void mips_cpu_do_interrupt(CPUState *cs) #if !defined(CONFIG_USER_ONLY) MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; + bool update_badinstr = 0; target_ulong offset; int cause = -1; const char *name; @@ -566,10 +587,13 @@ void mips_cpu_do_interrupt(CPUState *cs) goto set_EPC; case EXCP_LTLBL: cause = 1; + update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); goto set_EPC; case EXCP_TLBL: cause = 2; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { + update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); + if ((env->error_code & EXCP_TLB_NOMATCH) && + !(env->CP0_Status & (1 << CP0St_EXL))) { #if defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; @@ -586,7 +610,9 @@ void mips_cpu_do_interrupt(CPUState *cs) goto set_EPC; case EXCP_TLBS: cause = 3; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { + update_badinstr = 1; + if ((env->error_code & EXCP_TLB_NOMATCH) && + !(env->CP0_Status & (1 << CP0St_EXL))) { #if defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; @@ -603,9 +629,11 @@ void mips_cpu_do_interrupt(CPUState *cs) goto set_EPC; case EXCP_AdEL: cause = 4; + update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL); goto set_EPC; case EXCP_AdES: cause = 5; + update_badinstr = 1; goto set_EPC; case EXCP_IBE: cause = 6; @@ -615,32 +643,40 @@ void mips_cpu_do_interrupt(CPUState *cs) goto set_EPC; case EXCP_SYSCALL: cause = 8; + update_badinstr = 1; goto set_EPC; case EXCP_BREAK: cause = 9; + update_badinstr = 1; goto set_EPC; case EXCP_RI: cause = 10; + update_badinstr = 1; goto set_EPC; case EXCP_CpU: cause = 11; + update_badinstr = 1; env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | (env->error_code << CP0Ca_CE); goto set_EPC; case EXCP_OVERFLOW: cause = 12; + update_badinstr = 1; goto set_EPC; case EXCP_TRAP: cause = 13; + update_badinstr = 1; goto set_EPC; case EXCP_FPE: cause = 15; + update_badinstr = 1; goto set_EPC; case EXCP_C2E: cause = 18; goto set_EPC; case EXCP_TLBRI: cause = 19; + update_badinstr = 1; goto set_EPC; case EXCP_TLBXI: cause = 20; @@ -671,6 +707,9 @@ void mips_cpu_do_interrupt(CPUState *cs) set_EPC: if (!(env->CP0_Status & (1 << CP0St_EXL))) { env->CP0_EPC = exception_resume_pc(env); + if (update_badinstr) { + set_badinstr_registers(env); + } if (env->hflags & MIPS_HFLAG_BMASK) { env->CP0_Cause |= (1U << CP0Ca_BD); } else { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c33f0eb91a..875aa2c587 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2238,13 +2238,26 @@ void helper_wait(CPUMIPSState *env) #if !defined(CONFIG_USER_ONLY) void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - int is_write, int is_user, uintptr_t retaddr) + int access_type, int is_user, + uintptr_t retaddr) { MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; + int error_code = 0; + int excp; env->CP0_BadVAddr = addr; - do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr); + + if (access_type == MMU_DATA_STORE) { + excp = EXCP_AdES; + } else { + excp = EXCP_AdEL; + if (access_type == MMU_INST_FETCH) { + error_code |= EXCP_INST_NOTAVAIL; + } + } + + do_raise_exception_err(env, excp, error_code, retaddr); } void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, diff --git a/target-mips/translate.c b/target-mips/translate.c index fdb61be8d3..3e6e99026a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1175,6 +1175,8 @@ typedef struct DisasContext { int kscrexist; bool rxi; int ie; + bool bi; + bool bp; } DisasContext; enum { @@ -4828,9 +4830,25 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) tcg_gen_ext32s_tl(arg, arg); rn = "BadVAddr"; break; + case 1: + if (ctx->bi) { + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); + rn = "BadInstr"; + } else { + gen_mfc0_unimplemented(ctx, arg); + } + break; + case 2: + if (ctx->bp) { + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); + rn = "BadInstrP"; + } else { + gen_mfc0_unimplemented(ctx, arg); + } + break; default: goto die; - } + } break; case 9: switch (sel) { @@ -5428,8 +5446,22 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) } break; case 8: - /* ignored */ - rn = "BadVAddr"; + switch (sel) { + case 0: + /* ignored */ + rn = "BadVAddr"; + break; + case 1: + /* ignored */ + rn = "BadInstr"; + break; + case 2: + /* ignored */ + rn = "BadInstrP"; + break; + default: + goto die; + } break; case 9: switch (sel) { @@ -6054,6 +6086,22 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); rn = "BadVAddr"; break; + case 1: + if (ctx->bi) { + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); + rn = "BadInstr"; + } else { + gen_mfc0_unimplemented(ctx, arg); + } + break; + case 2: + if (ctx->bp) { + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); + rn = "BadInstrP"; + } else { + gen_mfc0_unimplemented(ctx, arg); + } + break; default: goto die; } @@ -6639,8 +6687,22 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) } break; case 8: - /* ignored */ - rn = "BadVAddr"; + switch (sel) { + case 0: + /* ignored */ + rn = "BadVAddr"; + break; + case 1: + /* ignored */ + rn = "BadInstr"; + break; + case 2: + /* ignored */ + rn = "BadInstrP"; + break; + default: + goto die; + } break; case 9: switch (sel) { @@ -16862,7 +16924,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) /* make sure instructions are on a word boundary */ if (ctx->pc & 0x3) { env->CP0_BadVAddr = ctx->pc; - generate_exception(ctx, EXCP_AdEL); + generate_exception_err(ctx, EXCP_AdEL, EXCP_INST_NOTAVAIL); return; } @@ -17500,6 +17562,8 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff; ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1; ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 3; + ctx.bi = (env->CP0_Config3 >> CP0C3_BI) & 1; + ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1; /* 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 & (1 << CP0C3_ULRI); From 460c81f14a74f671d14bad3a3fb4502292d7a355 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 7 Jul 2014 11:24:02 +0100 Subject: [PATCH 09/34] target-mips: update cpu_save/cpu_load to support new registers Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 2 +- target-mips/machine.c | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 4687f4f2cf..c66a725f70 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -558,7 +558,7 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env); extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env); -#define CPU_SAVE_VERSION 4 +#define CPU_SAVE_VERSION 5 /* MMU modes definitions. We carefully match the indices with our hflags layout. */ diff --git a/target-mips/machine.c b/target-mips/machine.c index 0496faa910..0ba7d736db 100644 --- a/target-mips/machine.c +++ b/target-mips/machine.c @@ -61,7 +61,12 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &env->tlb->nb_tlb); qemu_put_be32s(f, &env->tlb->tlb_in_use); for(i = 0; i < MIPS_TLB_MAX; i++) { - uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].G << 10) | + uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].EHINV << 15) | + (env->tlb->mmu.r4k.tlb[i].RI1 << 14) | + (env->tlb->mmu.r4k.tlb[i].RI0 << 13) | + (env->tlb->mmu.r4k.tlb[i].XI1 << 12) | + (env->tlb->mmu.r4k.tlb[i].XI0 << 11) | + (env->tlb->mmu.r4k.tlb[i].G << 10) | (env->tlb->mmu.r4k.tlb[i].C0 << 7) | (env->tlb->mmu.r4k.tlb[i].C1 << 4) | (env->tlb->mmu.r4k.tlb[i].V0 << 3) | @@ -111,6 +116,8 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_sbe32s(f, &env->CP0_SRSConf4); qemu_put_sbe32s(f, &env->CP0_HWREna); qemu_put_betls(f, &env->CP0_BadVAddr); + qemu_put_be32s(f, &env->CP0_BadInstr); + qemu_put_be32s(f, &env->CP0_BadInstrP); qemu_put_sbe32s(f, &env->CP0_Count); qemu_put_betls(f, &env->CP0_EntryHi); qemu_put_sbe32s(f, &env->CP0_Compare); @@ -144,6 +151,9 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_sbe32s(f, &env->CP0_DataHi); qemu_put_betls(f, &env->CP0_ErrorEPC); qemu_put_sbe32s(f, &env->CP0_DESAVE); + for (i = 0; i < MIPS_KSCRATCH_NUM; i++) { + qemu_put_betls(f, &env->CP0_KScratch[i]); + } /* Save inactive TC state */ for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) @@ -232,6 +242,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->tlb->mmu.r4k.tlb[i].V1 = (flags >> 2) & 1; env->tlb->mmu.r4k.tlb[i].D0 = (flags >> 1) & 1; env->tlb->mmu.r4k.tlb[i].D1 = (flags >> 0) & 1; + if (version_id >= 5) { + env->tlb->mmu.r4k.tlb[i].EHINV = (flags >> 15) & 1; + env->tlb->mmu.r4k.tlb[i].RI1 = (flags >> 14) & 1; + env->tlb->mmu.r4k.tlb[i].RI0 = (flags >> 13) & 1; + env->tlb->mmu.r4k.tlb[i].XI1 = (flags >> 12) & 1; + env->tlb->mmu.r4k.tlb[i].XI0 = (flags >> 11) & 1; + } qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]); qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]); } @@ -301,6 +318,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->CP0_DataHi); qemu_get_betls(f, &env->CP0_ErrorEPC); qemu_get_sbe32s(f, &env->CP0_DESAVE); + if (version_id >= 5) { + qemu_get_be32s(f, &env->CP0_BadInstr); + qemu_get_be32s(f, &env->CP0_BadInstrP); + for (i = 0; i < MIPS_KSCRATCH_NUM; i++) { + qemu_get_betls(f, &env->CP0_KScratch[i]); + } + } /* Load inactive TC state */ for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) { From faf1f68ba11c919191dd7a5f32cfd0b6401c4827 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 11 Jul 2014 16:11:33 +0100 Subject: [PATCH 10/34] target-mips: add Config5.SBRI SDBBP instruction Reserved Instruction control. The purpose of this field is to restrict availability of SDBBP to kernel mode operation. If the bit is set then SDBBP instruction can only be executed in kernel mode. User execution of SDBBP will cause a Reserved Instruction exception. Additionally add missing Config4 and Config5 cases for dm{f,t}c0. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 11 +++++++++-- target-mips/translate.c | 24 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c66a725f70..ce9a7a28f0 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -410,6 +410,7 @@ struct CPUMIPSState { #define CP0C5_CV 29 #define CP0C5_EVA 28 #define CP0C5_MSAEn 27 +#define CP0C5_SBRI 6 #define CP0C5_UFR 2 #define CP0C5_NFExists 0 int32_t CP0_Config6; @@ -461,7 +462,7 @@ struct CPUMIPSState { #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x1807FF +#define MIPS_HFLAG_TMASK 0x5807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -505,6 +506,7 @@ struct CPUMIPSState { #define MIPS_HFLAG_DSPR2 0x100000 /* Enable access to MIPS DSPR2 resources. */ /* Extra flag about HWREna register. */ #define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ +#define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ @@ -760,7 +762,8 @@ static inline void compute_hflags(CPUMIPSState *env) { env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | - MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2); + MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 | + MIPS_HFLAG_SBRI); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -796,6 +799,10 @@ static inline void compute_hflags(CPUMIPSState *env) if (env->CP0_Status & (1 << CP0St_FR)) { env->hflags |= MIPS_HFLAG_F64; } + if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) && + (env->CP0_Config5 & (1 << CP0C5_SBRI))) { + env->hflags |= MIPS_HFLAG_SBRI; + } if (env->insn_flags & ASE_DSPR2) { /* Enables access MIPS DSP resources, now our cpu is DSP ASER2, so enable to access DSPR2 resources. */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 3e6e99026a..c7a8bbc0d3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6225,6 +6225,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3)); rn = "Config3"; break; + case 4: + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4)); + rn = "Config4"; + break; + case 5: + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5)); + rn = "Config5"; + break; /* 6,7 are implementation dependent */ case 6: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6)); @@ -6843,6 +6851,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* ignored */ rn = "Config3"; break; + case 4: + /* currently ignored */ + rn = "Config4"; + break; + case 5: + gen_helper_mtc0_config5(cpu_env, arg); + rn = "Config5"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; /* 6,7 are implementation dependent */ default: rn = "Invalid config selector"; @@ -15801,7 +15819,11 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) } break; case R6_OPC_SDBBP: - 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) case OPC_DLSA: From 339cd2a82aca031370cd71b1118a5565dc2af0a9 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 11 Jul 2014 16:11:33 +0100 Subject: [PATCH 11/34] target-mips: implement forbidden slot When conditional compact branch is encountered decode one more instruction in current translation block - that will be forbidden slot. Instruction in forbidden slot will be executed only if conditional compact branch is not taken. Any control transfer instruction (CTI) which are branches, jumps, ERET, DERET, WAIT and PAUSE will generate RI exception if executed in forbidden or delay slot. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 3 +- target-mips/translate.c | 109 +++++++++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 36 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index ce9a7a28f0..6367d8c52d 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -488,7 +488,7 @@ struct CPUMIPSState { * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce * this from three bits to two. */ -#define MIPS_HFLAG_BMASK_BASE 0x03800 +#define MIPS_HFLAG_BMASK_BASE 0x803800 #define MIPS_HFLAG_B 0x00800 /* Unconditional branch */ #define MIPS_HFLAG_BC 0x01000 /* Conditional branch */ #define MIPS_HFLAG_BL 0x01800 /* Likely branch */ @@ -507,6 +507,7 @@ struct CPUMIPSState { /* Extra flag about HWREna register. */ #define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ #define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ +#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ diff --git a/target-mips/translate.c b/target-mips/translate.c index c7a8bbc0d3..a383a5ce4a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4136,7 +4136,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" + TARGET_FMT_lx "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); goto out; @@ -7638,12 +7639,22 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, case OPC_ERET: opn = "eret"; check_insn(ctx, ISA_MIPS2); + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + goto die; + } gen_helper_eret(cpu_env); ctx->bstate = BS_EXCP; break; case OPC_DERET: opn = "deret"; check_insn(ctx, ISA_MIPS32); + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + goto die; + } if (!(ctx->hflags & MIPS_HFLAG_DM)) { MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); @@ -7655,6 +7666,11 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, case OPC_WAIT: opn = "wait"; check_insn(ctx, ISA_MIPS3 | ISA_MIPS32); + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + goto die; + } /* If we get an exception, we want to restart at next instruction */ ctx->pc += 4; save_cpu_state(ctx, 1); @@ -7681,6 +7697,12 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, const char *opn = "cp1 cond branch"; TCGv_i32 t0 = tcg_temp_new_i32(); + if ((ctx->insn_flags & ISA_MIPS32R6) && (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + generate_exception(ctx, EXCP_RI); + goto out; + } + if (cc != 0) check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); @@ -7797,7 +7819,8 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx + "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); goto out; @@ -10251,6 +10274,10 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) save_cpu_state(ctx, 0); /* FIXME: Need to clear can_do_io. */ switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) { + case MIPS_HFLAG_FBNSLOT: + MIPS_DEBUG("forbidden slot"); + gen_goto_tb(ctx, 0, ctx->pc + insn_bytes); + break; case MIPS_HFLAG_B: /* unconditional branch */ MIPS_DEBUG("unconditional branch"); @@ -15533,7 +15560,8 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx + "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); goto out; @@ -15626,56 +15654,56 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, gen_branch(ctx, 4); } else { /* Conditional compact branch */ - int l1 = gen_new_label(); + int 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_COND_LE, t1, 0, l1); + 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_COND_GE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); } else { /* OPC_BGEUC */ - tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); + 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_COND_GT, t1, 0, l1); + 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_COND_LT, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); } else { /* OPC_BLTUC */ - tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1); + 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_COND_LE, t1, 0, l1); + 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_COND_GE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); } else { /* OPC_BGEC */ - tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1); + 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_COND_GT, t1, 0, l1); + 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_COND_LT, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); } else { /* OPC_BLTC */ - tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); } break; case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ @@ -15704,10 +15732,10 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, tcg_gen_or_tl(t4, t4, input_overflow); if (opc == OPC_BOVC) { /* OPC_BOVC */ - tcg_gen_brcondi_tl(TCG_COND_NE, t4, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t4, 0, fs); } else { /* OPC_BNVC */ - tcg_gen_brcondi_tl(TCG_COND_EQ, t4, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t4, 0, fs); } tcg_temp_free(input_overflow); tcg_temp_free(t4); @@ -15717,27 +15745,27 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, /* OPC_BEQZALC, OPC_BNEZALC */ if (opc == OPC_BEQZALC) { /* OPC_BEQZALC */ - tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t1, 0, fs); } else { /* OPC_BNEZALC */ - tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + 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_COND_EQ, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_EQ), t0, t1, fs); } else { /* OPC_BNEC */ - tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_NE), t0, t1, fs); } } break; case OPC_BEQZC: - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t0, 0, fs); break; case OPC_BNEZC: - tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t0, 0, fs); break; default: MIPS_INVAL("Compact conditional branch/jump"); @@ -15746,12 +15774,11 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, } /* Generating branch here as compact branches don't have delay slot */ - /* TODO: implement forbidden slot */ - gen_goto_tb(ctx, 1, ctx->pc + 4); - gen_set_label(l1); - gen_goto_tb(ctx, 0, ctx->btarget); + gen_goto_tb(ctx, 1, ctx->btarget); + gen_set_label(fs); + + ctx->hflags |= MIPS_HFLAG_FBNSLOT; MIPS_DEBUG("Compact conditional branch"); - ctx->bstate = BS_BRANCH; } out: @@ -15969,6 +15996,16 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { case OPC_SLL: /* Shift with immediate */ + if (sa == 5 && rd == 0 && + rs == 0 && rt == 0) { /* PAUSE */ + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + generate_exception(ctx, EXCP_RI); + break; + } + } + /* Fallthrough */ case OPC_SRA: gen_shift_imm(ctx, op1, rd, rt, sa); break; @@ -17567,7 +17604,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, int num_insns; int max_insns; int insn_bytes; - int is_delay; + int is_slot; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -17632,7 +17669,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); - is_delay = ctx.hflags & MIPS_HFLAG_BMASK; + is_slot = ctx.hflags & MIPS_HFLAG_BMASK; if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; @@ -17650,12 +17687,14 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, } if (ctx.hflags & MIPS_HFLAG_BMASK) { - if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32))) { - is_delay = 1; - /* force to generate branch as no delay slot is required */ + if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 | + MIPS_HFLAG_FBNSLOT))) { + /* force to generate branch as there is neither delay nor + forbidden slot */ + is_slot = 1; } } - if (is_delay) { + if (is_slot) { gen_branch(&ctx, insn_bytes); } ctx.pc += insn_bytes; From a63eb0ce0f5c43cf022022c5f4860aaf4f292a06 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 11 Jul 2014 16:11:34 +0100 Subject: [PATCH 12/34] target-mips: CP0_Status.CU0 no longer allows the user to access CP0 Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/cpu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 6367d8c52d..3b975ebe78 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -790,7 +790,8 @@ static inline void compute_hflags(CPUMIPSState *env) } } #endif - if ((env->CP0_Status & (1 << CP0St_CU0)) || + if (((env->CP0_Status & (1 << CP0St_CU0)) && + !(env->insn_flags & ISA_MIPS32R6)) || !(env->hflags & MIPS_HFLAG_KSU)) { env->hflags |= MIPS_HFLAG_CP0; } From ba801af429aaa68f6cc03842c8b6be81a6ede65a Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 11 Jul 2014 16:11:34 +0100 Subject: [PATCH 13/34] target-mips: add restrictions for possible values in registers In Release 6 not all the values are allowed to be written to a register. If the value is not valid or unsupported then it should stay unchanged. For pre-R6 the existing behaviour has been changed only for CP0_Index register as the current implementation does not seem to be correct - it looks like it tries to limit the input value but the limit is higher than the actual number of tlb entries. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/op_helper.c | 70 +++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 875aa2c587..99bdbcf5d0 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -959,14 +959,14 @@ target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1) { - int num = 1; - unsigned int tmp = env->tlb->nb_tlb; - - do { - tmp >>= 1; - num <<= 1; - } while (tmp); - env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1)); + uint32_t index_p = env->CP0_Index & 0x80000000; + uint32_t tlb_index = arg1 & 0x7fffffff; + if (tlb_index < env->tlb->nb_tlb) { + if (env->insn_flags & ISA_MIPS32R6) { + index_p |= arg1 & 0x80000000; + } + env->CP0_Index = index_p | tlb_index; + } } void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1) @@ -1294,8 +1294,13 @@ void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) { - /* 1k pages not implemented */ - env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); + uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1); + if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) || + (mask == 0x0000 || mask == 0x0003 || mask == 0x000F || + mask == 0x003F || mask == 0x00FF || mask == 0x03FF || + mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) { + env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); + } } void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) @@ -1309,7 +1314,13 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) { - env->CP0_Wired = arg1 % env->tlb->nb_tlb; + if (env->insn_flags & ISA_MIPS32R6) { + if (arg1 < env->tlb->nb_tlb) { + env->CP0_Wired = arg1; + } + } else { + env->CP0_Wired = arg1 % env->tlb->nb_tlb; + } } void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1) @@ -1368,11 +1379,21 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) } /* 1k pages not implemented */ - val = arg1 & mask; #if defined(TARGET_MIPS64) - val &= env->SEGMask; + if (env->insn_flags & ISA_MIPS32R6) { + int entryhi_r = extract64(arg1, 62, 2); + int config0_at = extract32(env->CP0_Config0, 13, 2); + bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0; + if ((entryhi_r == 2) || + (entryhi_r == 1 && (no_supervisor || config0_at == 1))) { + /* skip EntryHi.R field if new value is reserved */ + mask &= ~(0x3ull << 62); + } + } + mask &= env->SEGMask; #endif old = env->CP0_EntryHi; + val = (arg1 & mask) | (old & ~mask); env->CP0_EntryHi = val; if (env->CP0_Config3 & (1 << CP0C3_MT)) { sync_c0_entryhi(env, env->current_tc); @@ -1402,6 +1423,13 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) uint32_t val, old; uint32_t mask = env->CP0_Status_rw_bitmask; + if (env->insn_flags & ISA_MIPS32R6) { + if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) { + mask &= ~(3 << CP0St_KSU); + } + mask &= ~(0x00180000 & arg1); + } + val = arg1 & mask; old = env->CP0_Status; env->CP0_Status = (env->CP0_Status & ~mask) | val; @@ -1457,6 +1485,9 @@ static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1) if (cpu->insn_flags & ISA_MIPS32R2) { mask |= 1 << CP0Ca_DC; } + if (cpu->insn_flags & ISA_MIPS32R6) { + mask &= ~((1 << CP0Ca_WP) & arg1); + } cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask); @@ -2391,8 +2422,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) } break; case 25: - if (arg1 & 0xffffff00) + if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) { return; + } env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) | ((arg1 & 0x1) << 23); break; @@ -2408,9 +2440,13 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) ((arg1 & 0x4) << 22); break; case 31: - if (arg1 & 0x007c0000) - return; - env->active_fpu.fcr31 = arg1; + if (env->insn_flags & ISA_MIPS32R6) { + uint32_t mask = 0xfefc0000; + env->active_fpu.fcr31 = (arg1 & ~mask) | + (env->active_fpu.fcr31 & mask); + } else if (!(arg1 & 0x007c0000)) { + env->active_fpu.fcr31 = arg1; + } break; default: return; From f31b035a9f10dc9b57f01c426110af845d453ce2 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 11 Jul 2014 16:11:35 +0100 Subject: [PATCH 14/34] target-mips: correctly handle access to unimplemented CP0 register Release 6 limits the number of cases where software can cause UNDEFINED or UNPREDICTABLE behaviour. In this case, when accessing reserved / unimplemented CP0 register, writes are ignored and reads return 0. In pre-R6 the behaviour is not specified, but generating RI exception is not what the real HW does. Additionally, remove CP0 Random register as it became reserved in Release 6. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/translate.c | 538 +++++++++++++++++++--------------------- 1 file changed, 260 insertions(+), 278 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index a383a5ce4a..9a8f5c93f4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4584,6 +4584,13 @@ static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg) } } +#define CP0_CHECK(c) \ + do { \ + if (!(c)) { \ + goto cp0_unimplemented; \ + } \ + } while (0) + static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; @@ -4599,67 +4606,68 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Index"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpcontrol(arg, cpu_env); rn = "MVPControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf0(arg, cpu_env); rn = "MVPConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf1(arg, cpu_env); rn = "MVPConf1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 1: switch (sel) { case 0: + CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); gen_helper_mfc0_random(arg, cpu_env); rn = "Random"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask)); rn = "YQMask"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt)); rn = "VPEOpt"; break; default: - goto die; + goto cp0_unimplemented; } break; case 2: @@ -4679,42 +4687,42 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcstatus(arg, cpu_env); rn = "TCStatus"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcbind(arg, cpu_env); rn = "TCBind"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcrestart(arg, cpu_env); rn = "TCRestart"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tchalt(arg, cpu_env); rn = "TCHalt"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tccontext(arg, cpu_env); rn = "TCContext"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcschedule(arg, cpu_env); rn = "TCSchedule"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcschefback(arg, cpu_env); rn = "TCScheFBack"; break; default: - goto die; + goto cp0_unimplemented; } break; case 3: @@ -4734,7 +4742,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 4: @@ -4747,20 +4755,16 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; - goto die; + goto cp0_unimplemented; // break; case 2: - if (ctx->ulri) { - tcg_gen_ld32s_tl(arg, cpu_env, - offsetof(CPUMIPSState, - active_tc.CP0_UserLocal)); - rn = "UserLocal"; - } else { - tcg_gen_movi_tl(arg, 0); - } + CP0_CHECK(ctx->ulri); + tcg_gen_ld32s_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; break; default: - goto die; + goto cp0_unimplemented; } break; case 5: @@ -4775,7 +4779,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "PageGrain"; break; default: - goto die; + goto cp0_unimplemented; } break; case 6: @@ -4810,7 +4814,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSConf4"; break; default: - goto die; + goto cp0_unimplemented; } break; case 7: @@ -4821,7 +4825,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "HWREna"; break; default: - goto die; + goto cp0_unimplemented; } break; case 8: @@ -4832,23 +4836,17 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "BadVAddr"; break; case 1: - if (ctx->bi) { - gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); - rn = "BadInstr"; - } else { - gen_mfc0_unimplemented(ctx, arg); - } + CP0_CHECK(ctx->bi); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); + rn = "BadInstr"; break; case 2: - if (ctx->bp) { - gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); - rn = "BadInstrP"; - } else { - gen_mfc0_unimplemented(ctx, arg); - } + CP0_CHECK(ctx->bp); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); + rn = "BadInstrP"; break; default: - goto die; + goto cp0_unimplemented; } break; case 9: @@ -4868,7 +4866,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } break; case 10: @@ -4879,7 +4877,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 11: @@ -4890,7 +4888,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } break; case 12: @@ -4915,7 +4913,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSMap"; break; default: - goto die; + goto cp0_unimplemented; } break; case 13: @@ -4925,7 +4923,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Cause"; break; default: - goto die; + goto cp0_unimplemented; } break; case 14: @@ -4936,7 +4934,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 15: @@ -4951,7 +4949,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EBase"; break; default: - goto die; + goto cp0_unimplemented; } break; case 16: @@ -4990,7 +4988,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Config7"; break; default: - goto die; + goto cp0_unimplemented; } break; case 17: @@ -5000,7 +4998,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "LLAddr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 18: @@ -5010,7 +5008,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 19: @@ -5020,7 +5018,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 20: @@ -5034,18 +5032,19 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; #endif default: - goto die; + goto cp0_unimplemented; } break; case 21: /* Officially reserved, but sel 0 is used for R1x000 framemask */ + CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); switch (sel) { case 0: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Framemask)); rn = "Framemask"; break; default: - goto die; + goto cp0_unimplemented; } break; case 22: @@ -5075,7 +5074,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "TraceBPC"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 24: @@ -5087,7 +5086,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 25: @@ -5125,7 +5124,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Performance7"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 26: @@ -5139,7 +5138,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "CacheErr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 28: @@ -5159,7 +5158,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DataLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 29: @@ -5179,7 +5178,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DataHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 30: @@ -5190,7 +5189,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "ErrorEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 31: @@ -5201,29 +5200,26 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DESAVE"; break; case 2 ... 7: - if (ctx->kscrexist & (1 << sel)) { - tcg_gen_ld_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); - tcg_gen_ext32s_tl(arg, arg); - rn = "KScratch"; - } else { - gen_mfc0_unimplemented(ctx, arg); - } + CP0_CHECK(ctx->kscrexist & (1 << sel)); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + tcg_gen_ext32s_tl(arg, arg); + rn = "KScratch"; break; default: - goto die; + goto cp0_unimplemented; } break; default: - goto die; + goto cp0_unimplemented; } (void)rn; /* avoid a compiler warning */ LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel); return; -die: +cp0_unimplemented: LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel); - generate_exception(ctx, EXCP_RI); + gen_mfc0_unimplemented(ctx, arg); } static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) @@ -5244,22 +5240,22 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Index"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_mvpcontrol(cpu_env, arg); rn = "MVPControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ rn = "MVPConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ rn = "MVPConf1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 1: @@ -5269,42 +5265,42 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Random"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpecontrol(cpu_env, arg); rn = "VPEControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf0(cpu_env, arg); rn = "VPEConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf1(cpu_env, arg); rn = "VPEConf1"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_yqmask(cpu_env, arg); rn = "YQMask"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeopt(cpu_env, arg); rn = "VPEOpt"; break; default: - goto die; + goto cp0_unimplemented; } break; case 2: @@ -5314,42 +5310,42 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcstatus(cpu_env, arg); rn = "TCStatus"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcbind(cpu_env, arg); rn = "TCBind"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcrestart(cpu_env, arg); rn = "TCRestart"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tchalt(cpu_env, arg); rn = "TCHalt"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tccontext(cpu_env, arg); rn = "TCContext"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschedule(cpu_env, arg); rn = "TCSchedule"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschefback(cpu_env, arg); rn = "TCScheFBack"; break; default: - goto die; + goto cp0_unimplemented; } break; case 3: @@ -5359,7 +5355,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 4: @@ -5371,17 +5367,16 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ rn = "ContextConfig"; - goto die; + goto cp0_unimplemented; // break; case 2: - if (ctx->ulri) { - tcg_gen_st_tl(arg, cpu_env, - offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); - rn = "UserLocal"; - } + CP0_CHECK(ctx->ulri); + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; break; default: - goto die; + goto cp0_unimplemented; } break; case 5: @@ -5396,7 +5391,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "PageGrain"; break; default: - goto die; + goto cp0_unimplemented; } break; case 6: @@ -5431,7 +5426,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSConf4"; break; default: - goto die; + goto cp0_unimplemented; } break; case 7: @@ -5443,7 +5438,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "HWREna"; break; default: - goto die; + goto cp0_unimplemented; } break; case 8: @@ -5461,7 +5456,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "BadInstrP"; break; default: - goto die; + goto cp0_unimplemented; } break; case 9: @@ -5472,7 +5467,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } break; case 10: @@ -5482,7 +5477,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 11: @@ -5493,7 +5488,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } break; case 12: @@ -5528,7 +5523,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSMap"; break; default: - goto die; + goto cp0_unimplemented; } break; case 13: @@ -5539,7 +5534,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Cause"; break; default: - goto die; + goto cp0_unimplemented; } break; case 14: @@ -5549,7 +5544,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 15: @@ -5564,7 +5559,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EBase"; break; default: - goto die; + goto cp0_unimplemented; } break; case 16: @@ -5611,7 +5606,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; default: rn = "Invalid config selector"; - goto die; + goto cp0_unimplemented; } break; case 17: @@ -5621,7 +5616,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "LLAddr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 18: @@ -5631,7 +5626,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 19: @@ -5641,7 +5636,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 20: @@ -5654,18 +5649,19 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; #endif default: - goto die; + goto cp0_unimplemented; } break; case 21: /* Officially reserved, but sel 0 is used for R1x000 framemask */ + CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); switch (sel) { case 0: gen_helper_mtc0_framemask(cpu_env, arg); rn = "Framemask"; break; default: - goto die; + goto cp0_unimplemented; } break; case 22: @@ -5708,7 +5704,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "TraceBPC"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 24: @@ -5719,7 +5715,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 25: @@ -5757,7 +5753,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Performance7"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 26: @@ -5771,7 +5767,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "CacheErr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 28: @@ -5791,7 +5787,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DataLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 29: @@ -5812,7 +5808,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; default: rn = "invalid sel"; - goto die; + goto cp0_unimplemented; } break; case 30: @@ -5822,7 +5818,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "ErrorEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 31: @@ -5833,20 +5829,19 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DESAVE"; break; case 2 ... 7: - if (ctx->kscrexist & (1 << sel)) { - tcg_gen_st_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); - rn = "KScratch"; - } + CP0_CHECK(ctx->kscrexist & (1 << sel)); + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + rn = "KScratch"; break; default: - goto die; + goto cp0_unimplemented; } /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; break; default: - goto die; + goto cp0_unimplemented; } (void)rn; /* avoid a compiler warning */ LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel); @@ -5857,9 +5852,8 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) } return; -die: +cp0_unimplemented: LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel); - generate_exception(ctx, EXCP_RI); } #if defined(TARGET_MIPS64) @@ -5878,67 +5872,68 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Index"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpcontrol(arg, cpu_env); rn = "MVPControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf0(arg, cpu_env); rn = "MVPConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_mvpconf1(arg, cpu_env); rn = "MVPConf1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 1: switch (sel) { case 0: + CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); gen_helper_mfc0_random(arg, cpu_env); rn = "Random"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask)); rn = "YQMask"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt)); rn = "VPEOpt"; break; default: - goto die; + goto cp0_unimplemented; } break; case 2: @@ -5948,42 +5943,42 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcstatus(arg, cpu_env); rn = "TCStatus"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mfc0_tcbind(arg, cpu_env); rn = "TCBind"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tcrestart(arg, cpu_env); rn = "TCRestart"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tchalt(arg, cpu_env); rn = "TCHalt"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tccontext(arg, cpu_env); rn = "TCContext"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tcschedule(arg, cpu_env); rn = "TCSchedule"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_dmfc0_tcschefback(arg, cpu_env); rn = "TCScheFBack"; break; default: - goto die; + goto cp0_unimplemented; } break; case 3: @@ -5993,7 +5988,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 4: @@ -6005,19 +6000,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; - goto die; + goto cp0_unimplemented; // break; case 2: - if (ctx->ulri) { - tcg_gen_ld_tl(arg, cpu_env, - offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); - rn = "UserLocal"; - } else { - tcg_gen_movi_tl(arg, 0); - } + CP0_CHECK(ctx->ulri); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; break; default: - goto die; + goto cp0_unimplemented; } break; case 5: @@ -6032,7 +6024,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "PageGrain"; break; default: - goto die; + goto cp0_unimplemented; } break; case 6: @@ -6067,7 +6059,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSConf4"; break; default: - goto die; + goto cp0_unimplemented; } break; case 7: @@ -6078,7 +6070,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "HWREna"; break; default: - goto die; + goto cp0_unimplemented; } break; case 8: @@ -6088,23 +6080,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "BadVAddr"; break; case 1: - if (ctx->bi) { - gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); - rn = "BadInstr"; - } else { - gen_mfc0_unimplemented(ctx, arg); - } + CP0_CHECK(ctx->bi); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr)); + rn = "BadInstr"; break; case 2: - if (ctx->bp) { - gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); - rn = "BadInstrP"; - } else { - gen_mfc0_unimplemented(ctx, arg); - } + CP0_CHECK(ctx->bp); + gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP)); + rn = "BadInstrP"; break; default: - goto die; + goto cp0_unimplemented; } break; case 9: @@ -6124,7 +6110,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } break; case 10: @@ -6134,7 +6120,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 11: @@ -6145,7 +6131,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } break; case 12: @@ -6170,7 +6156,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSMap"; break; default: - goto die; + goto cp0_unimplemented; } break; case 13: @@ -6180,7 +6166,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Cause"; break; default: - goto die; + goto cp0_unimplemented; } break; case 14: @@ -6190,7 +6176,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 15: @@ -6205,7 +6191,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EBase"; break; default: - goto die; + goto cp0_unimplemented; } break; case 16: @@ -6244,7 +6230,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Config7"; break; default: - goto die; + goto cp0_unimplemented; } break; case 17: @@ -6254,7 +6240,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "LLAddr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 18: @@ -6264,7 +6250,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 19: @@ -6274,7 +6260,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 20: @@ -6285,18 +6271,19 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "XContext"; break; default: - goto die; + goto cp0_unimplemented; } break; case 21: /* Officially reserved, but sel 0 is used for R1x000 framemask */ + CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); switch (sel) { case 0: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Framemask)); rn = "Framemask"; break; default: - goto die; + goto cp0_unimplemented; } break; case 22: @@ -6326,7 +6313,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "TraceBPC"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 24: @@ -6337,7 +6324,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 25: @@ -6375,7 +6362,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Performance7"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 26: @@ -6390,7 +6377,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "CacheErr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 28: @@ -6410,7 +6397,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DataLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 29: @@ -6430,7 +6417,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DataHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 30: @@ -6440,7 +6427,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "ErrorEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 31: @@ -6451,28 +6438,25 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DESAVE"; break; case 2 ... 7: - if (ctx->kscrexist & (1 << sel)) { - tcg_gen_ld_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); - rn = "KScratch"; - } else { - gen_mfc0_unimplemented(ctx, arg); - } + CP0_CHECK(ctx->kscrexist & (1 << sel)); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + rn = "KScratch"; break; default: - goto die; + goto cp0_unimplemented; } break; default: - goto die; + goto cp0_unimplemented; } (void)rn; /* avoid a compiler warning */ LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel); return; -die: +cp0_unimplemented: LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel); - generate_exception(ctx, EXCP_RI); + gen_mfc0_unimplemented(ctx, arg); } static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) @@ -6493,22 +6477,22 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Index"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_mvpcontrol(cpu_env, arg); rn = "MVPControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ rn = "MVPConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); /* ignored */ rn = "MVPConf1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 1: @@ -6518,42 +6502,42 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Random"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpecontrol(cpu_env, arg); rn = "VPEControl"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf0(cpu_env, arg); rn = "VPEConf0"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeconf1(cpu_env, arg); rn = "VPEConf1"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_yqmask(cpu_env, arg); rn = "YQMask"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_vpeopt(cpu_env, arg); rn = "VPEOpt"; break; default: - goto die; + goto cp0_unimplemented; } break; case 2: @@ -6563,42 +6547,42 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcstatus(cpu_env, arg); rn = "TCStatus"; break; case 2: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcbind(cpu_env, arg); rn = "TCBind"; break; case 3: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcrestart(cpu_env, arg); rn = "TCRestart"; break; case 4: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tchalt(cpu_env, arg); rn = "TCHalt"; break; case 5: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tccontext(cpu_env, arg); rn = "TCContext"; break; case 6: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschedule(cpu_env, arg); rn = "TCSchedule"; break; case 7: - check_insn(ctx, ASE_MT); + CP0_CHECK(ctx->insn_flags & ASE_MT); gen_helper_mtc0_tcschefback(cpu_env, arg); rn = "TCScheFBack"; break; default: - goto die; + goto cp0_unimplemented; } break; case 3: @@ -6608,7 +6592,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryLo1"; break; default: - goto die; + goto cp0_unimplemented; } break; case 4: @@ -6620,17 +6604,16 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ rn = "ContextConfig"; - goto die; + goto cp0_unimplemented; // break; case 2: - if (ctx->ulri) { - tcg_gen_st_tl(arg, cpu_env, - offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); - rn = "UserLocal"; - } + CP0_CHECK(ctx->ulri); + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; break; default: - goto die; + goto cp0_unimplemented; } break; case 5: @@ -6645,7 +6628,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "PageGrain"; break; default: - goto die; + goto cp0_unimplemented; } break; case 6: @@ -6680,7 +6663,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSConf4"; break; default: - goto die; + goto cp0_unimplemented; } break; case 7: @@ -6692,7 +6675,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "HWREna"; break; default: - goto die; + goto cp0_unimplemented; } break; case 8: @@ -6710,7 +6693,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "BadInstrP"; break; default: - goto die; + goto cp0_unimplemented; } break; case 9: @@ -6721,7 +6704,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -6733,7 +6716,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EntryHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 11: @@ -6744,7 +6727,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; /* 6,7 are implementation dependent */ default: - goto die; + goto cp0_unimplemented; } /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -6781,7 +6764,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "SRSMap"; break; default: - goto die; + goto cp0_unimplemented; } break; case 13: @@ -6802,7 +6785,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Cause"; break; default: - goto die; + goto cp0_unimplemented; } break; case 14: @@ -6812,7 +6795,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 15: @@ -6827,7 +6810,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "EBase"; break; default: - goto die; + goto cp0_unimplemented; } break; case 16: @@ -6865,7 +6848,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* 6,7 are implementation dependent */ default: rn = "Invalid config selector"; - goto die; + goto cp0_unimplemented; } break; case 17: @@ -6875,7 +6858,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "LLAddr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 18: @@ -6885,7 +6868,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 19: @@ -6895,7 +6878,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "WatchHi"; break; default: - goto die; + goto cp0_unimplemented; } break; case 20: @@ -6906,18 +6889,19 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "XContext"; break; default: - goto die; + goto cp0_unimplemented; } break; case 21: /* Officially reserved, but sel 0 is used for R1x000 framemask */ + CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); switch (sel) { case 0: gen_helper_mtc0_framemask(cpu_env, arg); rn = "Framemask"; break; default: - goto die; + goto cp0_unimplemented; } break; case 22: @@ -6958,7 +6942,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "TraceBPC"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 24: @@ -6969,7 +6953,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 25: @@ -7007,7 +6991,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "Performance7"; // break; default: - goto die; + goto cp0_unimplemented; } break; case 26: @@ -7021,7 +7005,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "CacheErr"; break; default: - goto die; + goto cp0_unimplemented; } break; case 28: @@ -7041,7 +7025,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DataLo"; break; default: - goto die; + goto cp0_unimplemented; } break; case 29: @@ -7062,7 +7046,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; default: rn = "invalid sel"; - goto die; + goto cp0_unimplemented; } break; case 30: @@ -7072,7 +7056,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "ErrorEPC"; break; default: - goto die; + goto cp0_unimplemented; } break; case 31: @@ -7083,20 +7067,19 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) rn = "DESAVE"; break; case 2 ... 7: - if (ctx->kscrexist & (1 << sel)) { - tcg_gen_st_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); - rn = "KScratch"; - } + CP0_CHECK(ctx->kscrexist & (1 << sel)); + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + rn = "KScratch"; break; default: - goto die; + goto cp0_unimplemented; } /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; break; default: - goto die; + goto cp0_unimplemented; } (void)rn; /* avoid a compiler warning */ LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel); @@ -7107,9 +7090,8 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) } return; -die: +cp0_unimplemented: LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel); - generate_exception(ctx, EXCP_RI); } #endif /* TARGET_MIPS64 */ From 2d9e48bc041d9281f305ee82ae97776eb5ef0aab Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 11 Jul 2014 16:11:35 +0100 Subject: [PATCH 15/34] target-mips: enable features in MIPS64R6-generic CPU Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- target-mips/translate_init.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index bcfc46a715..0b70d05449 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -519,7 +519,7 @@ static const mips_def_t mips_defs[] = }, { /* A generic CPU supporting MIPS64 Release 6 ISA. - FIXME: It does not support all the MIPS64R6 features yet. + FIXME: Support IEEE 754-2008 FP and misaligned memory accesses. Eventually this should be replaced by a real CPU model. */ .name = "MIPS64R6-generic", .CP0_PRid = 0x00010000, @@ -530,12 +530,19 @@ static const mips_def_t mips_defs[] = (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, + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_RXI) | (1 << CP0C3_BP) | + (1 << CP0C3_BI) | (1 << CP0C3_ULRI) | (1U << CP0C3_M), + .CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) | + (3 << CP0C4_IE) | (1 << CP0C4_M), + .CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI), .CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x30D8FFFF, + .CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) | + (1U << CP0PG_RIE), + .CP0_PageGrain_rw_bitmask = 0, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), From e97a391d201c0a7ae4dfd3bb90890191f0e24780 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:35 +0000 Subject: [PATCH 16/34] target-mips: add MSA defines and data structure add defines and data structure for MIPS SIMD Architecture Reviewed-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/cpu.h | 52 +++++++++++++++++++++++++++++++++++++++-- target-mips/mips-defs.h | 1 + target-mips/op_helper.c | 1 + 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3b975ebe78..d08bbe7d9f 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -58,12 +58,32 @@ struct CPUMIPSTLBContext { }; #endif +/* MSA Context */ +#define MSA_WRLEN (128) + +enum CPUMIPSMSADataFormat { + DF_BYTE = 0, + DF_HALF, + DF_WORD, + DF_DOUBLE +}; + +typedef union wr_t wr_t; +union wr_t { + int8_t b[MSA_WRLEN/8]; + int16_t h[MSA_WRLEN/16]; + int32_t w[MSA_WRLEN/32]; + int64_t d[MSA_WRLEN/64]; +}; + typedef union fpr_t fpr_t; union fpr_t { float64 fd; /* ieee double precision */ float32 fs[2];/* ieee single precision */ uint64_t d; /* binary double fixed-point */ uint32_t w[2]; /* binary single fixed-point */ +/* FPU/MSA register mapping is not tested on big-endian hosts. */ + wr_t wr; /* vector data */ }; /* define FP_ENDIAN_IDX to access the same location * in the fpr_t union regardless of the host endianness @@ -177,6 +197,21 @@ struct TCState { target_ulong CP0_TCScheFBack; int32_t CP0_Debug_tcstatus; target_ulong CP0_UserLocal; + + int32_t msacsr; + +#define MSACSR_FS 24 +#define MSACSR_FS_MASK (1 << MSACSR_FS) +#define MSACSR_NX 18 +#define MSACSR_NX_MASK (1 << MSACSR_NX) +#define MSACSR_CEF 2 +#define MSACSR_CEF_MASK (0xffff << MSACSR_CEF) +#define MSACSR_RM 0 +#define MSACSR_RM_MASK (0x3 << MSACSR_RM) +#define MSACSR_MASK (MSACSR_RM_MASK | MSACSR_CEF_MASK | MSACSR_NX_MASK | \ + MSACSR_FS_MASK) + + float_status msa_fp_status; }; typedef struct CPUMIPSState CPUMIPSState; @@ -192,6 +227,10 @@ struct CPUMIPSState { target_ulong SEGMask; target_ulong PAMask; + int32_t msair; +#define MSAIR_ProcID 8 +#define MSAIR_Rev 0 + int32_t CP0_Index; /* CP0_MVP* are per MVP registers. */ int32_t CP0_Random; @@ -385,6 +424,7 @@ struct CPUMIPSState { #define CP0C2_SA 0 int32_t CP0_Config3; #define CP0C3_M 31 +#define CP0C3_MSAP 28 #define CP0C3_BP 27 #define CP0C3_BI 26 #define CP0C3_ISA_ON_EXC 16 @@ -462,7 +502,7 @@ struct CPUMIPSState { #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x5807FF +#define MIPS_HFLAG_TMASK 0x15807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -508,6 +548,7 @@ struct CPUMIPSState { #define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ #define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ #define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ +#define MIPS_HFLAG_MSA 0x1000000 target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ @@ -663,6 +704,8 @@ enum { EXCP_C2E, EXCP_CACHE, /* 32 */ EXCP_DSPDIS, + EXCP_MSADIS, + EXCP_MSAFPE, EXCP_TLBXI, EXCP_TLBRI, @@ -764,7 +807,7 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 | - MIPS_HFLAG_SBRI); + MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -837,6 +880,11 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= MIPS_HFLAG_COP1X; } } + if (env->insn_flags & ASE_MSA) { + if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) { + env->hflags |= MIPS_HFLAG_MSA; + } + } } #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 6cb62b2df0..1784227494 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -45,6 +45,7 @@ #define ASE_MT 0x00200000 #define ASE_SMARTMIPS 0x00400000 #define ASE_MICROMIPS 0x00800000 +#define ASE_MSA 0x01000000 /* Chip specific instructions. */ #define INSN_LOONGSON2E 0x20000000 diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 99bdbcf5d0..1b1c3048a4 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1589,6 +1589,7 @@ void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1) { env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) | (arg1 & env->CP0_Config5_rw_bitmask); + compute_hflags(env); } void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1) From b10ac20446019c7df77e51a30ed902b87fad8ec3 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:36 +0000 Subject: [PATCH 17/34] target-mips: add MSA exceptions add MSA exceptions Reviewed-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target-mips/helper.c b/target-mips/helper.c index c92b25c2a0..3a93c206e4 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -426,6 +426,8 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_CACHE] = "cache error", [EXCP_TLBXI] = "TLB execute-inhibit", [EXCP_TLBRI] = "TLB read-inhibit", + [EXCP_MSADIS] = "MSA disabled", + [EXCP_MSAFPE] = "MSA floating point", }; target_ulong exception_resume_pc (CPUMIPSState *env) @@ -667,6 +669,10 @@ void mips_cpu_do_interrupt(CPUState *cs) cause = 13; update_badinstr = 1; goto set_EPC; + case EXCP_MSAFPE: + cause = 14; + update_badinstr = 1; + goto set_EPC; case EXCP_FPE: cause = 15; update_badinstr = 1; @@ -681,6 +687,10 @@ void mips_cpu_do_interrupt(CPUState *cs) case EXCP_TLBXI: cause = 20; goto set_EPC; + case EXCP_MSADIS: + cause = 21; + update_badinstr = 1; + goto set_EPC; case EXCP_MDMX: cause = 22; goto set_EPC; From b7651e95218d92f84b9602940c6412911372cd3b Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:37 +0000 Subject: [PATCH 18/34] target-mips: remove duplicated mips/ieee mapping function Remove the duplicated ieee_rm in gdbstub.c. Make the other ieee_rm and ieee_ex_to_mips available to other files. Reviewed-by: James Hogan Reviewed-by: Leon Alrae Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/cpu.h | 4 ++++ target-mips/gdbstub.c | 7 ------- target-mips/op_helper.c | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index d08bbe7d9f..d21da8eb8c 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -760,6 +760,10 @@ hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address, #endif target_ulong exception_resume_pc (CPUMIPSState *env); +/* op_helper.c */ +extern unsigned int ieee_rm[]; +int ieee_ex_to_mips(int xcpt); + static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c index 5b72d58a44..f65fec23cc 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -73,13 +73,6 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return 0; } -/* convert MIPS rounding mode in FCR31 to IEEE library */ -static unsigned int ieee_rm[] = { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down -}; #define RESTORE_ROUNDING_MODE \ set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \ &env->active_fpu.fp_status) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1b1c3048a4..2a977210de 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2340,7 +2340,7 @@ void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr, #define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL /* convert MIPS rounding mode in FCR31 to IEEE library */ -static unsigned int ieee_rm[] = { +unsigned int ieee_rm[] = { float_round_nearest_even, float_round_to_zero, float_round_up, @@ -2461,7 +2461,7 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) do_raise_exception(env, EXCP_FPE, GETPC()); } -static inline int ieee_ex_to_mips(int xcpt) +int ieee_ex_to_mips(int xcpt) { int ret = 0; if (xcpt) { From 4cf8a45f56b71d474c33c5d8c2f9e39c4476a3d3 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:38 +0000 Subject: [PATCH 19/34] target-mips: stop translation after ctc1 stop translation as ctc1 instruction can change hflags Reviewed-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 9a8f5c93f4..b388ba5fef 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -7490,12 +7490,15 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, break; case 3: /* XXX: For now we support only a single FPU context. */ + save_cpu_state(ctx, 1); { TCGv_i32 fs_tmp = tcg_const_i32(rd); gen_helper_0e2i(ctc1, t0, fs_tmp, rt); tcg_temp_free_i32(fs_tmp); } + /* Stop translation as we may have changed hflags */ + ctx->bstate = BS_STOP; break; /* COP2: Not implemented. */ case 4: @@ -8089,12 +8092,15 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) break; case OPC_CTC1: gen_load_gpr(t0, rt); + save_cpu_state(ctx, 1); { TCGv_i32 fs_tmp = tcg_const_i32(fs); gen_helper_0e2i(ctc1, t0, fs_tmp, rt); tcg_temp_free_i32(fs_tmp); } + /* Stop translation as we may have changed hflags */ + ctx->bstate = BS_STOP; opn = "ctc1"; break; #if defined(TARGET_MIPS64) From 239dfebe124f160ae4c3e4d6aa54dc13cc1f2c08 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:39 +0000 Subject: [PATCH 20/34] target-mips: add MSA opcode enum add MSA opcode enum Reviewed-by: James Hogan Reviewed-by: Leon Alrae Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/translate.c | 245 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index b388ba5fef..555f89b843 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -137,6 +137,8 @@ enum { OPC_JIALC = (0x3E << 26), /* MDMX ASE specific */ OPC_MDMX = (0x1E << 26), + /* MSA ASE, same as MDMX */ + OPC_MSA = OPC_MDMX, /* Cache and prefetch */ OPC_CACHE = (0x2F << 26), OPC_PREF = (0x33 << 26), @@ -934,6 +936,8 @@ enum { OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, + OPC_BZ_V = (0x0B << 21) | OPC_CP1, + OPC_BNZ_V = (0x0F << 21) | OPC_CP1, OPC_S_FMT = (FMT_S << 21) | OPC_CP1, OPC_D_FMT = (FMT_D << 21) | OPC_CP1, OPC_E_FMT = (FMT_E << 21) | OPC_CP1, @@ -943,6 +947,14 @@ enum { OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1, OPC_BC1EQZ = (0x09 << 21) | OPC_CP1, OPC_BC1NEZ = (0x0D << 21) | OPC_CP1, + OPC_BZ_B = (0x18 << 21) | OPC_CP1, + OPC_BZ_H = (0x19 << 21) | OPC_CP1, + OPC_BZ_W = (0x1A << 21) | OPC_CP1, + OPC_BZ_D = (0x1B << 21) | OPC_CP1, + OPC_BNZ_B = (0x1C << 21) | OPC_CP1, + OPC_BNZ_H = (0x1D << 21) | OPC_CP1, + OPC_BNZ_W = (0x1E << 21) | OPC_CP1, + OPC_BNZ_D = (0x1F << 21) | OPC_CP1, }; #define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) @@ -1103,6 +1115,239 @@ enum { OPC_NMSUB_PS= 0x3E | OPC_CP3, }; +/* MSA Opcodes */ +#define MASK_MSA_MINOR(op) (MASK_OP_MAJOR(op) | (op & 0x3F)) +enum { + OPC_MSA_I8_00 = 0x00 | OPC_MSA, + OPC_MSA_I8_01 = 0x01 | OPC_MSA, + OPC_MSA_I8_02 = 0x02 | OPC_MSA, + OPC_MSA_I5_06 = 0x06 | OPC_MSA, + OPC_MSA_I5_07 = 0x07 | OPC_MSA, + OPC_MSA_BIT_09 = 0x09 | OPC_MSA, + OPC_MSA_BIT_0A = 0x0A | OPC_MSA, + OPC_MSA_3R_0D = 0x0D | OPC_MSA, + OPC_MSA_3R_0E = 0x0E | OPC_MSA, + OPC_MSA_3R_0F = 0x0F | OPC_MSA, + OPC_MSA_3R_10 = 0x10 | OPC_MSA, + OPC_MSA_3R_11 = 0x11 | OPC_MSA, + OPC_MSA_3R_12 = 0x12 | OPC_MSA, + OPC_MSA_3R_13 = 0x13 | OPC_MSA, + OPC_MSA_3R_14 = 0x14 | OPC_MSA, + OPC_MSA_3R_15 = 0x15 | OPC_MSA, + OPC_MSA_ELM = 0x19 | OPC_MSA, + OPC_MSA_3RF_1A = 0x1A | OPC_MSA, + OPC_MSA_3RF_1B = 0x1B | OPC_MSA, + OPC_MSA_3RF_1C = 0x1C | OPC_MSA, + OPC_MSA_VEC = 0x1E | OPC_MSA, + + /* MI10 instruction */ + OPC_LD_B = (0x20) | OPC_MSA, + OPC_LD_H = (0x21) | OPC_MSA, + OPC_LD_W = (0x22) | OPC_MSA, + OPC_LD_D = (0x23) | OPC_MSA, + OPC_ST_B = (0x24) | OPC_MSA, + OPC_ST_H = (0x25) | OPC_MSA, + OPC_ST_W = (0x26) | OPC_MSA, + OPC_ST_D = (0x27) | OPC_MSA, +}; + +enum { + /* I5 instruction df(bits 22..21) = _b, _h, _w, _d */ + OPC_ADDVI_df = (0x0 << 23) | OPC_MSA_I5_06, + OPC_CEQI_df = (0x0 << 23) | OPC_MSA_I5_07, + OPC_SUBVI_df = (0x1 << 23) | OPC_MSA_I5_06, + OPC_MAXI_S_df = (0x2 << 23) | OPC_MSA_I5_06, + OPC_CLTI_S_df = (0x2 << 23) | OPC_MSA_I5_07, + OPC_MAXI_U_df = (0x3 << 23) | OPC_MSA_I5_06, + OPC_CLTI_U_df = (0x3 << 23) | OPC_MSA_I5_07, + OPC_MINI_S_df = (0x4 << 23) | OPC_MSA_I5_06, + OPC_CLEI_S_df = (0x4 << 23) | OPC_MSA_I5_07, + OPC_MINI_U_df = (0x5 << 23) | OPC_MSA_I5_06, + OPC_CLEI_U_df = (0x5 << 23) | OPC_MSA_I5_07, + OPC_LDI_df = (0x6 << 23) | OPC_MSA_I5_07, + + /* I8 instruction */ + OPC_ANDI_B = (0x0 << 24) | OPC_MSA_I8_00, + OPC_BMNZI_B = (0x0 << 24) | OPC_MSA_I8_01, + OPC_SHF_B = (0x0 << 24) | OPC_MSA_I8_02, + OPC_ORI_B = (0x1 << 24) | OPC_MSA_I8_00, + OPC_BMZI_B = (0x1 << 24) | OPC_MSA_I8_01, + OPC_SHF_H = (0x1 << 24) | OPC_MSA_I8_02, + OPC_NORI_B = (0x2 << 24) | OPC_MSA_I8_00, + OPC_BSELI_B = (0x2 << 24) | OPC_MSA_I8_01, + OPC_SHF_W = (0x2 << 24) | OPC_MSA_I8_02, + OPC_XORI_B = (0x3 << 24) | OPC_MSA_I8_00, + + /* VEC/2R/2RF instruction */ + OPC_AND_V = (0x00 << 21) | OPC_MSA_VEC, + OPC_OR_V = (0x01 << 21) | OPC_MSA_VEC, + OPC_NOR_V = (0x02 << 21) | OPC_MSA_VEC, + OPC_XOR_V = (0x03 << 21) | OPC_MSA_VEC, + OPC_BMNZ_V = (0x04 << 21) | OPC_MSA_VEC, + OPC_BMZ_V = (0x05 << 21) | OPC_MSA_VEC, + OPC_BSEL_V = (0x06 << 21) | OPC_MSA_VEC, + + OPC_MSA_2R = (0x18 << 21) | OPC_MSA_VEC, + OPC_MSA_2RF = (0x19 << 21) | OPC_MSA_VEC, + + /* 2R instruction df(bits 17..16) = _b, _h, _w, _d */ + OPC_FILL_df = (0x00 << 18) | OPC_MSA_2R, + OPC_PCNT_df = (0x01 << 18) | OPC_MSA_2R, + OPC_NLOC_df = (0x02 << 18) | OPC_MSA_2R, + OPC_NLZC_df = (0x03 << 18) | OPC_MSA_2R, + + /* 2RF instruction df(bit 16) = _w, _d */ + OPC_FCLASS_df = (0x00 << 17) | OPC_MSA_2RF, + OPC_FTRUNC_S_df = (0x01 << 17) | OPC_MSA_2RF, + OPC_FTRUNC_U_df = (0x02 << 17) | OPC_MSA_2RF, + OPC_FSQRT_df = (0x03 << 17) | OPC_MSA_2RF, + OPC_FRSQRT_df = (0x04 << 17) | OPC_MSA_2RF, + OPC_FRCP_df = (0x05 << 17) | OPC_MSA_2RF, + OPC_FRINT_df = (0x06 << 17) | OPC_MSA_2RF, + OPC_FLOG2_df = (0x07 << 17) | OPC_MSA_2RF, + OPC_FEXUPL_df = (0x08 << 17) | OPC_MSA_2RF, + OPC_FEXUPR_df = (0x09 << 17) | OPC_MSA_2RF, + OPC_FFQL_df = (0x0A << 17) | OPC_MSA_2RF, + OPC_FFQR_df = (0x0B << 17) | OPC_MSA_2RF, + OPC_FTINT_S_df = (0x0C << 17) | OPC_MSA_2RF, + OPC_FTINT_U_df = (0x0D << 17) | OPC_MSA_2RF, + OPC_FFINT_S_df = (0x0E << 17) | OPC_MSA_2RF, + OPC_FFINT_U_df = (0x0F << 17) | OPC_MSA_2RF, + + /* 3R instruction df(bits 22..21) = _b, _h, _w, d */ + OPC_SLL_df = (0x0 << 23) | OPC_MSA_3R_0D, + OPC_ADDV_df = (0x0 << 23) | OPC_MSA_3R_0E, + OPC_CEQ_df = (0x0 << 23) | OPC_MSA_3R_0F, + OPC_ADD_A_df = (0x0 << 23) | OPC_MSA_3R_10, + OPC_SUBS_S_df = (0x0 << 23) | OPC_MSA_3R_11, + OPC_MULV_df = (0x0 << 23) | OPC_MSA_3R_12, + OPC_DOTP_S_df = (0x0 << 23) | OPC_MSA_3R_13, + OPC_SLD_df = (0x0 << 23) | OPC_MSA_3R_14, + OPC_VSHF_df = (0x0 << 23) | OPC_MSA_3R_15, + OPC_SRA_df = (0x1 << 23) | OPC_MSA_3R_0D, + OPC_SUBV_df = (0x1 << 23) | OPC_MSA_3R_0E, + OPC_ADDS_A_df = (0x1 << 23) | OPC_MSA_3R_10, + OPC_SUBS_U_df = (0x1 << 23) | OPC_MSA_3R_11, + OPC_MADDV_df = (0x1 << 23) | OPC_MSA_3R_12, + OPC_DOTP_U_df = (0x1 << 23) | OPC_MSA_3R_13, + OPC_SPLAT_df = (0x1 << 23) | OPC_MSA_3R_14, + OPC_SRAR_df = (0x1 << 23) | OPC_MSA_3R_15, + OPC_SRL_df = (0x2 << 23) | OPC_MSA_3R_0D, + OPC_MAX_S_df = (0x2 << 23) | OPC_MSA_3R_0E, + OPC_CLT_S_df = (0x2 << 23) | OPC_MSA_3R_0F, + OPC_ADDS_S_df = (0x2 << 23) | OPC_MSA_3R_10, + OPC_SUBSUS_U_df = (0x2 << 23) | OPC_MSA_3R_11, + OPC_MSUBV_df = (0x2 << 23) | OPC_MSA_3R_12, + OPC_DPADD_S_df = (0x2 << 23) | OPC_MSA_3R_13, + OPC_PCKEV_df = (0x2 << 23) | OPC_MSA_3R_14, + OPC_SRLR_df = (0x2 << 23) | OPC_MSA_3R_15, + OPC_BCLR_df = (0x3 << 23) | OPC_MSA_3R_0D, + OPC_MAX_U_df = (0x3 << 23) | OPC_MSA_3R_0E, + OPC_CLT_U_df = (0x3 << 23) | OPC_MSA_3R_0F, + OPC_ADDS_U_df = (0x3 << 23) | OPC_MSA_3R_10, + OPC_SUBSUU_S_df = (0x3 << 23) | OPC_MSA_3R_11, + OPC_DPADD_U_df = (0x3 << 23) | OPC_MSA_3R_13, + OPC_PCKOD_df = (0x3 << 23) | OPC_MSA_3R_14, + OPC_BSET_df = (0x4 << 23) | OPC_MSA_3R_0D, + OPC_MIN_S_df = (0x4 << 23) | OPC_MSA_3R_0E, + OPC_CLE_S_df = (0x4 << 23) | OPC_MSA_3R_0F, + OPC_AVE_S_df = (0x4 << 23) | OPC_MSA_3R_10, + OPC_ASUB_S_df = (0x4 << 23) | OPC_MSA_3R_11, + OPC_DIV_S_df = (0x4 << 23) | OPC_MSA_3R_12, + OPC_DPSUB_S_df = (0x4 << 23) | OPC_MSA_3R_13, + OPC_ILVL_df = (0x4 << 23) | OPC_MSA_3R_14, + OPC_HADD_S_df = (0x4 << 23) | OPC_MSA_3R_15, + OPC_BNEG_df = (0x5 << 23) | OPC_MSA_3R_0D, + OPC_MIN_U_df = (0x5 << 23) | OPC_MSA_3R_0E, + OPC_CLE_U_df = (0x5 << 23) | OPC_MSA_3R_0F, + OPC_AVE_U_df = (0x5 << 23) | OPC_MSA_3R_10, + OPC_ASUB_U_df = (0x5 << 23) | OPC_MSA_3R_11, + OPC_DIV_U_df = (0x5 << 23) | OPC_MSA_3R_12, + OPC_DPSUB_U_df = (0x5 << 23) | OPC_MSA_3R_13, + OPC_ILVR_df = (0x5 << 23) | OPC_MSA_3R_14, + OPC_HADD_U_df = (0x5 << 23) | OPC_MSA_3R_15, + OPC_BINSL_df = (0x6 << 23) | OPC_MSA_3R_0D, + OPC_MAX_A_df = (0x6 << 23) | OPC_MSA_3R_0E, + OPC_AVER_S_df = (0x6 << 23) | OPC_MSA_3R_10, + OPC_MOD_S_df = (0x6 << 23) | OPC_MSA_3R_12, + OPC_ILVEV_df = (0x6 << 23) | OPC_MSA_3R_14, + OPC_HSUB_S_df = (0x6 << 23) | OPC_MSA_3R_15, + OPC_BINSR_df = (0x7 << 23) | OPC_MSA_3R_0D, + OPC_MIN_A_df = (0x7 << 23) | OPC_MSA_3R_0E, + OPC_AVER_U_df = (0x7 << 23) | OPC_MSA_3R_10, + OPC_MOD_U_df = (0x7 << 23) | OPC_MSA_3R_12, + OPC_ILVOD_df = (0x7 << 23) | OPC_MSA_3R_14, + OPC_HSUB_U_df = (0x7 << 23) | OPC_MSA_3R_15, + + /* ELM instructions df(bits 21..16) = _b, _h, _w, _d */ + OPC_SLDI_df = (0x0 << 22) | (0x00 << 16) | OPC_MSA_ELM, + OPC_CTCMSA = (0x0 << 22) | (0x3E << 16) | OPC_MSA_ELM, + OPC_SPLATI_df = (0x1 << 22) | (0x00 << 16) | OPC_MSA_ELM, + OPC_CFCMSA = (0x1 << 22) | (0x3E << 16) | OPC_MSA_ELM, + OPC_COPY_S_df = (0x2 << 22) | (0x00 << 16) | OPC_MSA_ELM, + OPC_MOVE_V = (0x2 << 22) | (0x3E << 16) | OPC_MSA_ELM, + OPC_COPY_U_df = (0x3 << 22) | (0x00 << 16) | OPC_MSA_ELM, + OPC_INSERT_df = (0x4 << 22) | (0x00 << 16) | OPC_MSA_ELM, + OPC_INSVE_df = (0x5 << 22) | (0x00 << 16) | OPC_MSA_ELM, + + /* 3RF instruction _df(bit 21) = _w, _d */ + OPC_FCAF_df = (0x0 << 22) | OPC_MSA_3RF_1A, + OPC_FADD_df = (0x0 << 22) | OPC_MSA_3RF_1B, + OPC_FCUN_df = (0x1 << 22) | OPC_MSA_3RF_1A, + OPC_FSUB_df = (0x1 << 22) | OPC_MSA_3RF_1B, + OPC_FCOR_df = (0x1 << 22) | OPC_MSA_3RF_1C, + OPC_FCEQ_df = (0x2 << 22) | OPC_MSA_3RF_1A, + OPC_FMUL_df = (0x2 << 22) | OPC_MSA_3RF_1B, + OPC_FCUNE_df = (0x2 << 22) | OPC_MSA_3RF_1C, + OPC_FCUEQ_df = (0x3 << 22) | OPC_MSA_3RF_1A, + OPC_FDIV_df = (0x3 << 22) | OPC_MSA_3RF_1B, + OPC_FCNE_df = (0x3 << 22) | OPC_MSA_3RF_1C, + OPC_FCLT_df = (0x4 << 22) | OPC_MSA_3RF_1A, + OPC_FMADD_df = (0x4 << 22) | OPC_MSA_3RF_1B, + OPC_MUL_Q_df = (0x4 << 22) | OPC_MSA_3RF_1C, + OPC_FCULT_df = (0x5 << 22) | OPC_MSA_3RF_1A, + OPC_FMSUB_df = (0x5 << 22) | OPC_MSA_3RF_1B, + OPC_MADD_Q_df = (0x5 << 22) | OPC_MSA_3RF_1C, + OPC_FCLE_df = (0x6 << 22) | OPC_MSA_3RF_1A, + OPC_MSUB_Q_df = (0x6 << 22) | OPC_MSA_3RF_1C, + OPC_FCULE_df = (0x7 << 22) | OPC_MSA_3RF_1A, + OPC_FEXP2_df = (0x7 << 22) | OPC_MSA_3RF_1B, + OPC_FSAF_df = (0x8 << 22) | OPC_MSA_3RF_1A, + OPC_FEXDO_df = (0x8 << 22) | OPC_MSA_3RF_1B, + OPC_FSUN_df = (0x9 << 22) | OPC_MSA_3RF_1A, + OPC_FSOR_df = (0x9 << 22) | OPC_MSA_3RF_1C, + OPC_FSEQ_df = (0xA << 22) | OPC_MSA_3RF_1A, + OPC_FTQ_df = (0xA << 22) | OPC_MSA_3RF_1B, + OPC_FSUNE_df = (0xA << 22) | OPC_MSA_3RF_1C, + OPC_FSUEQ_df = (0xB << 22) | OPC_MSA_3RF_1A, + OPC_FSNE_df = (0xB << 22) | OPC_MSA_3RF_1C, + OPC_FSLT_df = (0xC << 22) | OPC_MSA_3RF_1A, + OPC_FMIN_df = (0xC << 22) | OPC_MSA_3RF_1B, + OPC_MULR_Q_df = (0xC << 22) | OPC_MSA_3RF_1C, + OPC_FSULT_df = (0xD << 22) | OPC_MSA_3RF_1A, + OPC_FMIN_A_df = (0xD << 22) | OPC_MSA_3RF_1B, + OPC_MADDR_Q_df = (0xD << 22) | OPC_MSA_3RF_1C, + OPC_FSLE_df = (0xE << 22) | OPC_MSA_3RF_1A, + OPC_FMAX_df = (0xE << 22) | OPC_MSA_3RF_1B, + OPC_MSUBR_Q_df = (0xE << 22) | OPC_MSA_3RF_1C, + OPC_FSULE_df = (0xF << 22) | OPC_MSA_3RF_1A, + OPC_FMAX_A_df = (0xF << 22) | OPC_MSA_3RF_1B, + + /* BIT instruction df(bits 22..16) = _B _H _W _D */ + OPC_SLLI_df = (0x0 << 23) | OPC_MSA_BIT_09, + OPC_SAT_S_df = (0x0 << 23) | OPC_MSA_BIT_0A, + OPC_SRAI_df = (0x1 << 23) | OPC_MSA_BIT_09, + OPC_SAT_U_df = (0x1 << 23) | OPC_MSA_BIT_0A, + OPC_SRLI_df = (0x2 << 23) | OPC_MSA_BIT_09, + OPC_SRARI_df = (0x2 << 23) | OPC_MSA_BIT_0A, + OPC_BCLRI_df = (0x3 << 23) | OPC_MSA_BIT_09, + OPC_SRLRI_df = (0x3 << 23) | OPC_MSA_BIT_0A, + OPC_BSETI_df = (0x4 << 23) | OPC_MSA_BIT_09, + OPC_BNEGI_df = (0x5 << 23) | OPC_MSA_BIT_09, + OPC_BINSLI_df = (0x6 << 23) | OPC_MSA_BIT_09, + OPC_BINSRI_df = (0x7 << 23) | OPC_MSA_BIT_09, +}; + /* global register indices */ static TCGv_ptr cpu_env; static TCGv cpu_gpr[32], cpu_PC; From 863f264d10f917a8c3b2f8f6c3f78d0189fa48e7 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:40 +0000 Subject: [PATCH 21/34] target-mips: add msa_reset(), global msa register add msa_reset() and global msa register (d type only) Reviewed-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/translate.c | 56 ++++++++++++++++++++++++++++++++++++ target-mips/translate_init.c | 34 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 555f89b843..baa1826bf6 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1356,6 +1356,7 @@ static TCGv cpu_dspctrl, btarget, bcond; static TCGv_i32 hflags; static TCGv_i32 fpu_fcr0, fpu_fcr31; static TCGv_i64 fpu_f64[32]; +static TCGv_i64 msa_wr_d[64]; static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; static target_ulong gen_opc_btarget[OPC_BUF_SIZE]; @@ -1454,6 +1455,25 @@ static const char * const fregnames[] = { "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; +static const char * const msaregnames[] = { + "w0.d0", "w0.d1", "w1.d0", "w1.d1", + "w2.d0", "w2.d1", "w3.d0", "w3.d1", + "w4.d0", "w4.d1", "w5.d0", "w5.d1", + "w6.d0", "w6.d1", "w7.d0", "w7.d1", + "w8.d0", "w8.d1", "w9.d0", "w9.d1", + "w10.d0", "w10.d1", "w11.d0", "w11.d1", + "w12.d0", "w12.d1", "w13.d0", "w13.d1", + "w14.d0", "w14.d1", "w15.d0", "w15.d1", + "w16.d0", "w16.d1", "w17.d0", "w17.d1", + "w18.d0", "w18.d1", "w19.d0", "w19.d1", + "w20.d0", "w20.d1", "w21.d0", "w21.d1", + "w22.d0", "w22.d1", "w23.d0", "w23.d1", + "w24.d0", "w24.d1", "w25.d0", "w25.d1", + "w26.d0", "w26.d1", "w27.d0", "w27.d1", + "w28.d0", "w28.d1", "w29.d0", "w29.d1", + "w30.d0", "w30.d1", "w31.d0", "w31.d1", +}; + #define MIPS_DEBUG(fmt, ...) \ do { \ if (MIPS_DEBUG_DISAS) { \ @@ -17206,6 +17226,27 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) } } +/* MIPS SIMD Architecture (MSA) */ +static inline int check_msa_access(DisasContext *ctx) +{ + if (unlikely((ctx->hflags & MIPS_HFLAG_FPU) && + !(ctx->hflags & MIPS_HFLAG_F64))) { + generate_exception(ctx, EXCP_RI); + return 0; + } + + if (unlikely(!(ctx->hflags & MIPS_HFLAG_MSA))) { + if (ctx->insn_flags & ASE_MSA) { + generate_exception(ctx, EXCP_MSADIS); + return 0; + } else { + generate_exception(ctx, EXCP_RI); + return 0; + } + } + return 1; +} + static void decode_opc (CPUMIPSState *env, DisasContext *ctx) { int32_t offset; @@ -18136,6 +18177,15 @@ void mips_tcg_init(void) fpu_f64[i] = tcg_global_mem_new_i64(TCG_AREG0, off, fregnames[i]); } + for (i = 0; i < 32; i++) { + int off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[0]); + msa_wr_d[i * 2] = + tcg_global_mem_new_i64(TCG_AREG0, off, msaregnames[i * 2]); + off = offsetof(CPUMIPSState, active_fpu.fpr[i].wr.d[1]); + msa_wr_d[i * 2 + 1] = + tcg_global_mem_new_i64(TCG_AREG0, off, msaregnames[i * 2 + 1]); + } + cpu_PC = tcg_global_mem_new(TCG_AREG0, offsetof(CPUMIPSState, active_tc.PC), "PC"); for (i = 0; i < MIPS_DSP_ACC; i++) { @@ -18243,6 +18293,7 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask; env->CP0_PageGrain = env->cpu_model->CP0_PageGrain; env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0; + env->msair = env->cpu_model->MSAIR; env->insn_flags = env->cpu_model->insn_flags; #if defined(CONFIG_USER_ONLY) @@ -18340,6 +18391,11 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_Status |= (1 << CP0St_FR); } + /* MSA */ + if (env->CP0_Config3 & (1 << CP0C3_MSAP)) { + msa_reset(env); + } + compute_hflags(env); cs->exception_index = EXCP_NONE; } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 0b70d05449..a69a724d2e 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -84,6 +84,7 @@ struct mips_def_t { int32_t CP0_TCStatus_rw_bitmask; int32_t CP0_SRSCtl; int32_t CP1_fcr0; + int32_t MSAIR; int32_t SEGBITS; int32_t PABITS; int32_t CP0_SRSConf0_rw_bitmask; @@ -729,3 +730,36 @@ static void mvp_init (CPUMIPSState *env, const mips_def_t *def) (0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) | (0x1 << CP0MVPC1_PCP1); } + +static void msa_reset(CPUMIPSState *env) +{ +#ifdef CONFIG_USER_ONLY + /* MSA access enabled */ + env->CP0_Config5 |= 1 << CP0C5_MSAEn; + env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR); +#endif + + /* MSA CSR: + - non-signaling floating point exception mode off (NX bit is 0) + - Cause, Enables, and Flags are all 0 + - round to nearest / ties to even (RM bits are 0) */ + env->active_tc.msacsr = 0; + + /* tininess detected after rounding.*/ + set_float_detect_tininess(float_tininess_after_rounding, + &env->active_tc.msa_fp_status); + + /* clear float_status exception flags */ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); + + /* set float_status rounding mode */ + set_float_rounding_mode(float_round_nearest_even, + &env->active_tc.msa_fp_status); + + /* set float_status flush modes */ + set_flush_to_zero(0, &env->active_tc.msa_fp_status); + set_flush_inputs_to_zero(0, &env->active_tc.msa_fp_status); + + /* clear float_status nan mode */ + set_default_nan_mode(0, &env->active_tc.msa_fp_status); +} From 42daa9bed40baaec86329e72768f310b8ca9b601 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:41 +0000 Subject: [PATCH 22/34] target-mips: add msa_helper.c add msa_helper.c Reviewed-by: James Hogan Reviewed-by: Leon Alrae Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/Makefile.objs | 2 +- target-mips/msa_helper.c | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 target-mips/msa_helper.c diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs index 716244f3d5..108fd9b501 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 +obj-y += gdbstub.o msa_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c new file mode 100644 index 0000000000..b65fb271a9 --- /dev/null +++ b/target-mips/msa_helper.c @@ -0,0 +1,49 @@ +/* + * MIPS SIMD Architecture Module Instruction emulation helpers for QEMU. + * + * Copyright (c) 2014 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 "cpu.h" +#include "exec/helper-proto.h" + +/* Data format min and max values */ +#define DF_BITS(df) (1 << ((df) + 3)) + +#define DF_MAX_INT(df) (int64_t)((1LL << (DF_BITS(df) - 1)) - 1) +#define M_MAX_INT(m) (int64_t)((1LL << ((m) - 1)) - 1) + +#define DF_MIN_INT(df) (int64_t)(-(1LL << (DF_BITS(df) - 1))) +#define M_MIN_INT(m) (int64_t)(-(1LL << ((m) - 1))) + +#define DF_MAX_UINT(df) (uint64_t)(-1ULL >> (64 - DF_BITS(df))) +#define M_MAX_UINT(m) (uint64_t)(-1ULL >> (64 - (m))) + +#define UNSIGNED(x, df) ((x) & DF_MAX_UINT(df)) +#define SIGNED(x, df) \ + ((((int64_t)x) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df))) + +/* Element-by-element access macros */ +#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df)) + +static inline void msa_move_v(wr_t *pwd, wr_t *pws) +{ + uint32_t i; + + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + pwd->d[i] = pws->d[i]; + } +} From 5692c6e1f8ac1ed883076dec7dd14065b8df27dd Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:42 +0000 Subject: [PATCH 23/34] target-mips: add MSA branch instructions add MSA branch instructions Reviewed-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/translate.c | 334 ++++++++++++++++++++++++++-------------- 1 file changed, 220 insertions(+), 114 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index baa1826bf6..056a16233e 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17247,6 +17247,93 @@ static inline int check_msa_access(DisasContext *ctx) return 1; } +static void gen_check_zero_element(TCGv tresult, uint8_t df, uint8_t wt) +{ + /* generates tcg ops to check if any element is 0 */ + /* Note this function only works with MSA_WRLEN = 128 */ + uint64_t eval_zero_or_big = 0; + uint64_t eval_big = 0; + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + switch (df) { + case DF_BYTE: + eval_zero_or_big = 0x0101010101010101ULL; + eval_big = 0x8080808080808080ULL; + break; + case DF_HALF: + eval_zero_or_big = 0x0001000100010001ULL; + eval_big = 0x8000800080008000ULL; + break; + case DF_WORD: + eval_zero_or_big = 0x0000000100000001ULL; + eval_big = 0x8000000080000000ULL; + break; + case DF_DOUBLE: + eval_zero_or_big = 0x0000000000000001ULL; + eval_big = 0x8000000000000000ULL; + break; + } + tcg_gen_subi_i64(t0, msa_wr_d[wt<<1], eval_zero_or_big); + tcg_gen_andc_i64(t0, t0, msa_wr_d[wt<<1]); + tcg_gen_andi_i64(t0, t0, eval_big); + tcg_gen_subi_i64(t1, msa_wr_d[(wt<<1)+1], eval_zero_or_big); + tcg_gen_andc_i64(t1, t1, msa_wr_d[(wt<<1)+1]); + tcg_gen_andi_i64(t1, t1, eval_big); + tcg_gen_or_i64(t0, t0, t1); + /* if all bits are zero then all elements are not zero */ + /* if some bit is non-zero then some element is zero */ + tcg_gen_setcondi_i64(TCG_COND_NE, t0, t0, 0); + tcg_gen_trunc_i64_tl(tresult, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +static void gen_msa_branch(CPUMIPSState *env, DisasContext *ctx, uint32_t op1) +{ + uint8_t df = (ctx->opcode >> 21) & 0x3; + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + int64_t s16 = (int16_t)ctx->opcode; + + check_msa_access(ctx); + + if (ctx->insn_flags & ISA_MIPS32R6 && ctx->hflags & MIPS_HFLAG_BMASK) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + generate_exception(ctx, EXCP_RI); + return; + } + switch (op1) { + case OPC_BZ_V: + case OPC_BNZ_V: + { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_or_i64(t0, msa_wr_d[wt<<1], msa_wr_d[(wt<<1)+1]); + tcg_gen_setcondi_i64((op1 == OPC_BZ_V) ? + TCG_COND_EQ : TCG_COND_NE, t0, t0, 0); + tcg_gen_trunc_i64_tl(bcond, t0); + tcg_temp_free_i64(t0); + } + break; + case OPC_BZ_B: + case OPC_BZ_H: + case OPC_BZ_W: + case OPC_BZ_D: + gen_check_zero_element(bcond, df, wt); + break; + case OPC_BNZ_B: + case OPC_BNZ_H: + case OPC_BNZ_W: + case OPC_BNZ_D: + gen_check_zero_element(bcond, df, wt); + tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, bcond, 0); + break; + } + + ctx->btarget = ctx->pc + (s16 << 2) + 4; + + ctx->hflags |= MIPS_HFLAG_BC; + ctx->hflags |= MIPS_HFLAG_BDS32; +} + static void decode_opc (CPUMIPSState *env, DisasContext *ctx) { int32_t offset; @@ -17568,133 +17655,152 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_CP1: - if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { + op1 = MASK_CP1(ctx->opcode); + + switch (op1) { + case OPC_MFHC1: + case OPC_MTHC1: check_cp1_enabled(ctx); - op1 = MASK_CP1(ctx->opcode); - switch (op1) { - case OPC_MFHC1: - case OPC_MTHC1: - check_insn(ctx, ISA_MIPS32R2); - case OPC_MFC1: - case OPC_CFC1: - case OPC_MTC1: - case OPC_CTC1: - gen_cp1(ctx, op1, rt, rd); - break; + check_insn(ctx, ISA_MIPS32R2); + case OPC_MFC1: + case OPC_CFC1: + case OPC_MTC1: + case OPC_CTC1: + check_cp1_enabled(ctx); + gen_cp1(ctx, op1, rt, rd); + break; #if defined(TARGET_MIPS64) - case OPC_DMFC1: - case OPC_DMTC1: - check_insn(ctx, ISA_MIPS3); - gen_cp1(ctx, op1, rt, rd); - break; + case OPC_DMFC1: + case OPC_DMTC1: + check_cp1_enabled(ctx); + check_insn(ctx, ISA_MIPS3); + gen_cp1(ctx, op1, rt, rd); + break; #endif - case OPC_BC1EQZ: /* OPC_BC1ANY2 */ - if (ctx->insn_flags & ISA_MIPS32R6) { - /* OPC_BC1EQZ */ - gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), - rt, imm << 2); - } else { - /* OPC_BC1ANY2 */ - check_cop1x(ctx); - check_insn(ctx, ASE_MIPS3D); - gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), - (rt >> 2) & 0x7, imm << 2); - } - break; - case OPC_BC1NEZ: - check_insn(ctx, ISA_MIPS32R6); + case OPC_BC1EQZ: /* OPC_BC1ANY2 */ + check_cp1_enabled(ctx); + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_BC1EQZ */ gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), rt, imm << 2); - break; - case OPC_BC1ANY4: - check_insn_opc_removed(ctx, ISA_MIPS32R6); + } else { + /* OPC_BC1ANY2 */ check_cop1x(ctx); check_insn(ctx, ASE_MIPS3D); - /* fall through */ - case OPC_BC1: - check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); - break; - case OPC_PS_FMT: - check_insn_opc_removed(ctx, ISA_MIPS32R6); - case OPC_S_FMT: - case OPC_D_FMT: - gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, - (imm >> 8) & 0x7); - break; - case OPC_W_FMT: - case OPC_L_FMT: - { - int r6_op = ctx->opcode & FOP(0x3f, 0x1f); - if (ctx->insn_flags & ISA_MIPS32R6) { - switch (r6_op) { - case R6_OPC_CMP_AF_S: - case R6_OPC_CMP_UN_S: - case R6_OPC_CMP_EQ_S: - case R6_OPC_CMP_UEQ_S: - case R6_OPC_CMP_LT_S: - case R6_OPC_CMP_ULT_S: - case R6_OPC_CMP_LE_S: - case R6_OPC_CMP_ULE_S: - case R6_OPC_CMP_SAF_S: - case R6_OPC_CMP_SUN_S: - case R6_OPC_CMP_SEQ_S: - case R6_OPC_CMP_SEUQ_S: - case R6_OPC_CMP_SLT_S: - case R6_OPC_CMP_SULT_S: - case R6_OPC_CMP_SLE_S: - case R6_OPC_CMP_SULE_S: - case R6_OPC_CMP_OR_S: - case R6_OPC_CMP_UNE_S: - case R6_OPC_CMP_NE_S: - case R6_OPC_CMP_SOR_S: - case R6_OPC_CMP_SUNE_S: - case R6_OPC_CMP_SNE_S: - gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa); - break; - case R6_OPC_CMP_AF_D: - case R6_OPC_CMP_UN_D: - case R6_OPC_CMP_EQ_D: - case R6_OPC_CMP_UEQ_D: - case R6_OPC_CMP_LT_D: - case R6_OPC_CMP_ULT_D: - case R6_OPC_CMP_LE_D: - case R6_OPC_CMP_ULE_D: - case R6_OPC_CMP_SAF_D: - case R6_OPC_CMP_SUN_D: - case R6_OPC_CMP_SEQ_D: - case R6_OPC_CMP_SEUQ_D: - case R6_OPC_CMP_SLT_D: - case R6_OPC_CMP_SULT_D: - case R6_OPC_CMP_SLE_D: - case R6_OPC_CMP_SULE_D: - case R6_OPC_CMP_OR_D: - case R6_OPC_CMP_UNE_D: - case R6_OPC_CMP_NE_D: - case R6_OPC_CMP_SOR_D: - case R6_OPC_CMP_SUNE_D: - case R6_OPC_CMP_SNE_D: - gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa); - break; - default: - gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, - (imm >> 8) & 0x7); - break; - } - } else { + } + break; + case OPC_BC1NEZ: + check_cp1_enabled(ctx); + check_insn(ctx, ISA_MIPS32R6); + gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode), + rt, imm << 2); + break; + case OPC_BC1ANY4: + check_cp1_enabled(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); + check_cop1x(ctx); + check_insn(ctx, ASE_MIPS3D); + /* fall through */ + case OPC_BC1: + check_cp1_enabled(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); + gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), + (rt >> 2) & 0x7, imm << 2); + break; + case OPC_PS_FMT: + check_cp1_enabled(ctx); + check_insn_opc_removed(ctx, ISA_MIPS32R6); + case OPC_S_FMT: + case OPC_D_FMT: + check_cp1_enabled(ctx); + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, + (imm >> 8) & 0x7); + break; + case OPC_W_FMT: + case OPC_L_FMT: + { + int r6_op = ctx->opcode & FOP(0x3f, 0x1f); + check_cp1_enabled(ctx); + if (ctx->insn_flags & ISA_MIPS32R6) { + switch (r6_op) { + case R6_OPC_CMP_AF_S: + case R6_OPC_CMP_UN_S: + case R6_OPC_CMP_EQ_S: + case R6_OPC_CMP_UEQ_S: + case R6_OPC_CMP_LT_S: + case R6_OPC_CMP_ULT_S: + case R6_OPC_CMP_LE_S: + case R6_OPC_CMP_ULE_S: + case R6_OPC_CMP_SAF_S: + case R6_OPC_CMP_SUN_S: + case R6_OPC_CMP_SEQ_S: + case R6_OPC_CMP_SEUQ_S: + case R6_OPC_CMP_SLT_S: + case R6_OPC_CMP_SULT_S: + case R6_OPC_CMP_SLE_S: + case R6_OPC_CMP_SULE_S: + case R6_OPC_CMP_OR_S: + case R6_OPC_CMP_UNE_S: + case R6_OPC_CMP_NE_S: + case R6_OPC_CMP_SOR_S: + case R6_OPC_CMP_SUNE_S: + case R6_OPC_CMP_SNE_S: + gen_r6_cmp_s(ctx, ctx->opcode & 0x1f, rt, rd, sa); + break; + case R6_OPC_CMP_AF_D: + case R6_OPC_CMP_UN_D: + case R6_OPC_CMP_EQ_D: + case R6_OPC_CMP_UEQ_D: + case R6_OPC_CMP_LT_D: + case R6_OPC_CMP_ULT_D: + case R6_OPC_CMP_LE_D: + case R6_OPC_CMP_ULE_D: + case R6_OPC_CMP_SAF_D: + case R6_OPC_CMP_SUN_D: + case R6_OPC_CMP_SEQ_D: + case R6_OPC_CMP_SEUQ_D: + case R6_OPC_CMP_SLT_D: + case R6_OPC_CMP_SULT_D: + case R6_OPC_CMP_SLE_D: + case R6_OPC_CMP_SULE_D: + case R6_OPC_CMP_OR_D: + case R6_OPC_CMP_UNE_D: + case R6_OPC_CMP_NE_D: + case R6_OPC_CMP_SOR_D: + case R6_OPC_CMP_SUNE_D: + case R6_OPC_CMP_SNE_D: + gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa); + break; + default: gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, (imm >> 8) & 0x7); + break; } - break; + } else { + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, + (imm >> 8) & 0x7); } - default: - MIPS_INVAL("cp1"); - generate_exception (ctx, EXCP_RI); - break; - } - } else { - generate_exception_err(ctx, EXCP_CpU, 1); + break; + } + case OPC_BZ_V: + case OPC_BNZ_V: + case OPC_BZ_B: + case OPC_BZ_H: + case OPC_BZ_W: + case OPC_BZ_D: + case OPC_BNZ_B: + case OPC_BNZ_H: + case OPC_BNZ_W: + case OPC_BNZ_D: + check_insn(ctx, ASE_MSA); + gen_msa_branch(env, ctx, op1); + break; + default: + MIPS_INVAL("cp1"); + generate_exception(ctx, EXCP_RI); + break; } break; From 4c7895465e069b204e8eb4731ac7f37cd3b1a4eb Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:43 +0000 Subject: [PATCH 24/34] target-mips: add MSA I8 format instructions add MSA I8 format instructions Reviewed-by: James Hogan Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 10 +++++ target-mips/msa_helper.c | 66 ++++++++++++++++++++++++++++++++ target-mips/translate.c | 82 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index aea12a90d6..5fd627ea17 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -748,3 +748,13 @@ DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env) #endif DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env) DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env) + +/* MIPS SIMD Architecture */ +DEF_HELPER_4(msa_andi_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ori_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nori_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_xori_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmnzi_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmzi_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bseli_b, void, env, i32, i32, i32) +DEF_HELPER_5(msa_shf_df, void, env, i32, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index b65fb271a9..bae86d4e05 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -47,3 +47,69 @@ static inline void msa_move_v(wr_t *pwd, wr_t *pws) pwd->d[i] = pws->d[i]; } } + +#define MSA_FN_IMM8(FUNC, DEST, OPERATION) \ +void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ + uint32_t i8) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + uint32_t i; \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + DEST = OPERATION; \ + } \ +} + +MSA_FN_IMM8(andi_b, pwd->b[i], pws->b[i] & i8) +MSA_FN_IMM8(ori_b, pwd->b[i], pws->b[i] | i8) +MSA_FN_IMM8(nori_b, pwd->b[i], ~(pws->b[i] | i8)) +MSA_FN_IMM8(xori_b, pwd->b[i], pws->b[i] ^ i8) + +#define BIT_MOVE_IF_NOT_ZERO(dest, arg1, arg2, df) \ + UNSIGNED(((dest & (~arg2)) | (arg1 & arg2)), df) +MSA_FN_IMM8(bmnzi_b, pwd->b[i], + BIT_MOVE_IF_NOT_ZERO(pwd->b[i], pws->b[i], i8, DF_BYTE)) + +#define BIT_MOVE_IF_ZERO(dest, arg1, arg2, df) \ + UNSIGNED((dest & arg2) | (arg1 & (~arg2)), df) +MSA_FN_IMM8(bmzi_b, pwd->b[i], + BIT_MOVE_IF_ZERO(pwd->b[i], pws->b[i], i8, DF_BYTE)) + +#define BIT_SELECT(dest, arg1, arg2, df) \ + UNSIGNED((arg1 & (~dest)) | (arg2 & dest), df) +MSA_FN_IMM8(bseli_b, pwd->b[i], + BIT_SELECT(pwd->b[i], pws->b[i], i8, DF_BYTE)) + +#undef MSA_FN_IMM8 + +#define SHF_POS(i, imm) (((i) & 0xfc) + (((imm) >> (2 * ((i) & 0x03))) & 0x03)) + +void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t imm) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t wx, *pwx = &wx; + uint32_t i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + pwx->b[i] = pws->b[SHF_POS(i, imm)]; + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + pwx->h[i] = pws->h[SHF_POS(i, imm)]; + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + pwx->w[i] = pws->w[SHF_POS(i, imm)]; + } + break; + default: + assert(0); + } + msa_move_v(pwd, pwx); +} diff --git a/target-mips/translate.c b/target-mips/translate.c index 056a16233e..aba3ccb0b3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17334,6 +17334,84 @@ static void gen_msa_branch(CPUMIPSState *env, DisasContext *ctx, uint32_t op1) ctx->hflags |= MIPS_HFLAG_BDS32; } +static void gen_msa_i8(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_I8(op) (MASK_MSA_MINOR(op) | (op & (0x03 << 24))) + uint8_t i8 = (ctx->opcode >> 16) & 0xff; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 ti8 = tcg_const_i32(i8); + + switch (MASK_MSA_I8(ctx->opcode)) { + case OPC_ANDI_B: + gen_helper_msa_andi_b(cpu_env, twd, tws, ti8); + break; + case OPC_ORI_B: + gen_helper_msa_ori_b(cpu_env, twd, tws, ti8); + break; + case OPC_NORI_B: + gen_helper_msa_nori_b(cpu_env, twd, tws, ti8); + break; + case OPC_XORI_B: + gen_helper_msa_xori_b(cpu_env, twd, tws, ti8); + break; + case OPC_BMNZI_B: + gen_helper_msa_bmnzi_b(cpu_env, twd, tws, ti8); + break; + case OPC_BMZI_B: + gen_helper_msa_bmzi_b(cpu_env, twd, tws, ti8); + break; + case OPC_BSELI_B: + gen_helper_msa_bseli_b(cpu_env, twd, tws, ti8); + break; + case OPC_SHF_B: + case OPC_SHF_H: + case OPC_SHF_W: + { + uint8_t df = (ctx->opcode >> 24) & 0x3; + if (df == DF_DOUBLE) { + generate_exception(ctx, EXCP_RI); + } else { + TCGv_i32 tdf = tcg_const_i32(df); + gen_helper_msa_shf_df(cpu_env, tdf, twd, tws, ti8); + tcg_temp_free_i32(tdf); + } + } + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(ti8); +} + +static void gen_msa(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t opcode = ctx->opcode; + check_insn(ctx, ASE_MSA); + check_msa_access(ctx); + + switch (MASK_MSA_MINOR(opcode)) { + case OPC_MSA_I8_00: + case OPC_MSA_I8_01: + case OPC_MSA_I8_02: + gen_msa_i8(env, ctx); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + +} + static void decode_opc (CPUMIPSState *env, DisasContext *ctx) { int32_t offset; @@ -17955,9 +18033,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_compute_branch(ctx, op, 4, rs, rt, offset, 4); } break; - case OPC_MDMX: - check_insn(ctx, ASE_MDMX); + case OPC_MSA: /* OPC_MDMX */ /* MDMX: Not implemented. */ + gen_msa(env, ctx); break; case OPC_PCREL: check_insn(ctx, ISA_MIPS32R6); From 80e7159184fadfc2dee3b6cc92013d4c4c58348a Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:44 +0000 Subject: [PATCH 25/34] target-mips: add MSA I5 format instruction add MSA I5 format instructions Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/helper.h | 13 ++++ target-mips/msa_helper.c | 142 +++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 77 +++++++++++++++++++++ 3 files changed, 232 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index 5fd627ea17..4f0354532f 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -758,3 +758,16 @@ DEF_HELPER_4(msa_bmnzi_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_bmzi_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_bseli_b, void, env, i32, i32, i32) DEF_HELPER_5(msa_shf_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_5(msa_addvi_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_subvi_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_maxi_s_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_maxi_u_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_mini_s_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_mini_u_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_ceqi_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_clti_s_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_clti_u_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_clei_s_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_clei_u_df, void, env, i32, i32, i32, s32) +DEF_HELPER_4(msa_ldi_df, void, env, i32, i32, s32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index bae86d4e05..7b577e715e 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -113,3 +113,145 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, } msa_move_v(pwd, pwx); } + +static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 + arg2; +} + +static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 - arg2; +} + +static inline int64_t msa_ceq_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 == arg2 ? -1 : 0; +} + +static inline int64_t msa_cle_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 <= arg2 ? -1 : 0; +} + +static inline int64_t msa_cle_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg1 <= u_arg2 ? -1 : 0; +} + +static inline int64_t msa_clt_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 < arg2 ? -1 : 0; +} + +static inline int64_t msa_clt_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg1 < u_arg2 ? -1 : 0; +} + +static inline int64_t msa_max_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 > arg2 ? arg1 : arg2; +} + +static inline int64_t msa_max_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg1 > u_arg2 ? arg1 : arg2; +} + +static inline int64_t msa_min_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 < arg2 ? arg1 : arg2; +} + +static inline int64_t msa_min_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg1 < u_arg2 ? arg1 : arg2; +} + +#define MSA_BINOP_IMM_DF(helper, func) \ +void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ + uint32_t wd, uint32_t ws, int32_t u5) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], u5); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pws->h[i], u5); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pws->w[i], u5); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pws->d[i], u5); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_BINOP_IMM_DF(addvi, addv) +MSA_BINOP_IMM_DF(subvi, subv) +MSA_BINOP_IMM_DF(ceqi, ceq) +MSA_BINOP_IMM_DF(clei_s, cle_s) +MSA_BINOP_IMM_DF(clei_u, cle_u) +MSA_BINOP_IMM_DF(clti_s, clt_s) +MSA_BINOP_IMM_DF(clti_u, clt_u) +MSA_BINOP_IMM_DF(maxi_s, max_s) +MSA_BINOP_IMM_DF(maxi_u, max_u) +MSA_BINOP_IMM_DF(mini_s, min_s) +MSA_BINOP_IMM_DF(mini_u, min_u) +#undef MSA_BINOP_IMM_DF + +void helper_msa_ldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + int32_t s10) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + uint32_t i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + pwd->b[i] = (int8_t)s10; + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + pwd->h[i] = (int16_t)s10; + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + pwd->w[i] = (int32_t)s10; + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + pwd->d[i] = (int64_t)s10; + } + break; + default: + assert(0); + } +} diff --git a/target-mips/translate.c b/target-mips/translate.c index aba3ccb0b3..e75b864b3b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17392,6 +17392,79 @@ static void gen_msa_i8(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(ti8); } +static void gen_msa_i5(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_I5(op) (MASK_MSA_MINOR(op) | (op & (0x7 << 23))) + uint8_t df = (ctx->opcode >> 21) & 0x3; + int8_t s5 = (int8_t) sextract32(ctx->opcode, 16, 5); + uint8_t u5 = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + + TCGv_i32 tdf = tcg_const_i32(df); + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 timm = tcg_temp_new_i32(); + tcg_gen_movi_i32(timm, u5); + + switch (MASK_MSA_I5(ctx->opcode)) { + case OPC_ADDVI_df: + gen_helper_msa_addvi_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_SUBVI_df: + gen_helper_msa_subvi_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_MAXI_S_df: + tcg_gen_movi_i32(timm, s5); + gen_helper_msa_maxi_s_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_MAXI_U_df: + gen_helper_msa_maxi_u_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_MINI_S_df: + tcg_gen_movi_i32(timm, s5); + gen_helper_msa_mini_s_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_MINI_U_df: + gen_helper_msa_mini_u_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_CEQI_df: + tcg_gen_movi_i32(timm, s5); + gen_helper_msa_ceqi_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_CLTI_S_df: + tcg_gen_movi_i32(timm, s5); + gen_helper_msa_clti_s_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_CLTI_U_df: + gen_helper_msa_clti_u_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_CLEI_S_df: + tcg_gen_movi_i32(timm, s5); + gen_helper_msa_clei_s_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_CLEI_U_df: + gen_helper_msa_clei_u_df(cpu_env, tdf, twd, tws, timm); + break; + case OPC_LDI_df: + { + int32_t s10 = sextract32(ctx->opcode, 11, 10); + tcg_gen_movi_i32(timm, s10); + gen_helper_msa_ldi_df(cpu_env, tdf, twd, timm); + } + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(tdf); + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(timm); +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -17404,6 +17477,10 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_I8_02: gen_msa_i8(env, ctx); break; + case OPC_MSA_I5_06: + case OPC_MSA_I5_07: + gen_msa_i5(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From d4cf28dec265f2f8a25ddbe818b1da62e174bcfa Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:45 +0000 Subject: [PATCH 26/34] target-mips: add MSA BIT format instructions add MSA BIT format instructions Reviewed-by: Leon Alrae Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 13 +++ target-mips/msa_helper.c | 196 +++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 88 ++++++++++++++++++ 3 files changed, 297 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index 4f0354532f..2167c4a39f 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -771,3 +771,16 @@ DEF_HELPER_5(msa_clti_u_df, void, env, i32, i32, i32, s32) DEF_HELPER_5(msa_clei_s_df, void, env, i32, i32, i32, s32) DEF_HELPER_5(msa_clei_u_df, void, env, i32, i32, i32, s32) DEF_HELPER_4(msa_ldi_df, void, env, i32, i32, s32) + +DEF_HELPER_5(msa_slli_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srai_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srli_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_bclri_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_bseti_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_bnegi_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_binsli_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_binsri_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_sat_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_sat_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srari_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index 7b577e715e..114008fe3d 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -255,3 +255,199 @@ void helper_msa_ldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, assert(0); } } + +/* Data format bit position and unsigned values */ +#define BIT_POSITION(x, df) ((uint64_t)(x) % DF_BITS(df)) + +static inline int64_t msa_sll_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return arg1 << b_arg2; +} + +static inline int64_t msa_sra_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return arg1 >> b_arg2; +} + +static inline int64_t msa_srl_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + int32_t b_arg2 = BIT_POSITION(arg2, df); + return u_arg1 >> b_arg2; +} + +static inline int64_t msa_bclr_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return UNSIGNED(arg1 & (~(1LL << b_arg2)), df); +} + +static inline int64_t msa_bset_df(uint32_t df, int64_t arg1, + int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return UNSIGNED(arg1 | (1LL << b_arg2), df); +} + +static inline int64_t msa_bneg_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return UNSIGNED(arg1 ^ (1LL << b_arg2), df); +} + +static inline int64_t msa_binsl_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_dest = UNSIGNED(dest, df); + int32_t sh_d = BIT_POSITION(arg2, df) + 1; + int32_t sh_a = DF_BITS(df) - sh_d; + if (sh_d == DF_BITS(df)) { + return u_arg1; + } else { + return UNSIGNED(UNSIGNED(u_dest << sh_d, df) >> sh_d, df) | + UNSIGNED(UNSIGNED(u_arg1 >> sh_a, df) << sh_a, df); + } +} + +static inline int64_t msa_binsr_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_dest = UNSIGNED(dest, df); + int32_t sh_d = BIT_POSITION(arg2, df) + 1; + int32_t sh_a = DF_BITS(df) - sh_d; + if (sh_d == DF_BITS(df)) { + return u_arg1; + } else { + return UNSIGNED(UNSIGNED(u_dest >> sh_d, df) << sh_d, df) | + UNSIGNED(UNSIGNED(u_arg1 << sh_a, df) >> sh_a, df); + } +} + +static inline int64_t msa_sat_s_df(uint32_t df, int64_t arg, uint32_t m) +{ + return arg < M_MIN_INT(m+1) ? M_MIN_INT(m+1) : + arg > M_MAX_INT(m+1) ? M_MAX_INT(m+1) : + arg; +} + +static inline int64_t msa_sat_u_df(uint32_t df, int64_t arg, uint32_t m) +{ + uint64_t u_arg = UNSIGNED(arg, df); + return u_arg < M_MAX_UINT(m+1) ? u_arg : + M_MAX_UINT(m+1); +} + +static inline int64_t msa_srar_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + if (b_arg2 == 0) { + return arg1; + } else { + int64_t r_bit = (arg1 >> (b_arg2 - 1)) & 1; + return (arg1 >> b_arg2) + r_bit; + } +} + +static inline int64_t msa_srlr_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + int32_t b_arg2 = BIT_POSITION(arg2, df); + if (b_arg2 == 0) { + return u_arg1; + } else { + uint64_t r_bit = (u_arg1 >> (b_arg2 - 1)) & 1; + return (u_arg1 >> b_arg2) + r_bit; + } +} + +#define MSA_BINOP_IMMU_DF(helper, func) \ +void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ + uint32_t ws, uint32_t u5) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], u5); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pws->h[i], u5); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pws->w[i], u5); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pws->d[i], u5); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_BINOP_IMMU_DF(slli, sll) +MSA_BINOP_IMMU_DF(srai, sra) +MSA_BINOP_IMMU_DF(srli, srl) +MSA_BINOP_IMMU_DF(bclri, bclr) +MSA_BINOP_IMMU_DF(bseti, bset) +MSA_BINOP_IMMU_DF(bnegi, bneg) +MSA_BINOP_IMMU_DF(sat_s, sat_s) +MSA_BINOP_IMMU_DF(sat_u, sat_u) +MSA_BINOP_IMMU_DF(srari, srar) +MSA_BINOP_IMMU_DF(srlri, srlr) +#undef MSA_BINOP_IMMU_DF + +#define MSA_TEROP_IMMU_DF(helper, func) \ +void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ + uint32_t wd, uint32_t ws, uint32_t u5) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pwd->b[i], pws->b[i], \ + u5); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pwd->h[i], pws->h[i], \ + u5); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pwd->w[i], pws->w[i], \ + u5); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pwd->d[i], pws->d[i], \ + u5); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_TEROP_IMMU_DF(binsli, binsl) +MSA_TEROP_IMMU_DF(binsri, binsr) +#undef MSA_TEROP_IMMU_DF diff --git a/target-mips/translate.c b/target-mips/translate.c index e75b864b3b..1f3bd72e1a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17465,6 +17465,90 @@ static void gen_msa_i5(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(timm); } +static void gen_msa_bit(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_BIT(op) (MASK_MSA_MINOR(op) | (op & (0x7 << 23))) + uint8_t dfm = (ctx->opcode >> 16) & 0x7f; + uint32_t df = 0, m = 0; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + + TCGv_i32 tdf; + TCGv_i32 tm; + TCGv_i32 twd; + TCGv_i32 tws; + + if ((dfm & 0x40) == 0x00) { + m = dfm & 0x3f; + df = DF_DOUBLE; + } else if ((dfm & 0x60) == 0x40) { + m = dfm & 0x1f; + df = DF_WORD; + } else if ((dfm & 0x70) == 0x60) { + m = dfm & 0x0f; + df = DF_HALF; + } else if ((dfm & 0x78) == 0x70) { + m = dfm & 0x7; + df = DF_BYTE; + } else { + generate_exception(ctx, EXCP_RI); + return; + } + + tdf = tcg_const_i32(df); + tm = tcg_const_i32(m); + twd = tcg_const_i32(wd); + tws = tcg_const_i32(ws); + + switch (MASK_MSA_BIT(ctx->opcode)) { + case OPC_SLLI_df: + gen_helper_msa_slli_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_SRAI_df: + gen_helper_msa_srai_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_SRLI_df: + gen_helper_msa_srli_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_BCLRI_df: + gen_helper_msa_bclri_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_BSETI_df: + gen_helper_msa_bseti_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_BNEGI_df: + gen_helper_msa_bnegi_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_BINSLI_df: + gen_helper_msa_binsli_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_BINSRI_df: + gen_helper_msa_binsri_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_SAT_S_df: + gen_helper_msa_sat_s_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_SAT_U_df: + gen_helper_msa_sat_u_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_SRARI_df: + gen_helper_msa_srari_df(cpu_env, tdf, twd, tws, tm); + break; + case OPC_SRLRI_df: + gen_helper_msa_srlri_df(cpu_env, tdf, twd, tws, tm); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(tdf); + tcg_temp_free_i32(tm); + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -17481,6 +17565,10 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_I5_07: gen_msa_i5(env, ctx); break; + case OPC_MSA_BIT_09: + case OPC_MSA_BIT_0A: + gen_msa_bit(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From 28f99f08cf9a5ceb01704d84834dfac0f5635866 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:46 +0000 Subject: [PATCH 27/34] target-mips: add MSA 3R format instructions add MSA 3R format instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 64 ++++ target-mips/msa_helper.c | 657 +++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 242 ++++++++++++++ 3 files changed, 963 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index 2167c4a39f..4297d4a668 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -784,3 +784,67 @@ DEF_HELPER_5(msa_sat_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_sat_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_srari_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_5(msa_sll_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_sra_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srl_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_bclr_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_bset_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_bneg_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_binsl_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_binsr_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_addv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_subv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_max_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_max_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_min_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_min_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_max_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_min_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ceq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_clt_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_clt_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_cle_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_cle_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_add_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_adds_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_adds_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_adds_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ave_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ave_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_aver_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_aver_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_subs_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_subs_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_asub_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_asub_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_div_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_div_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mod_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mod_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_splat_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_pckev_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_pckod_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ilvl_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ilvr_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ilvev_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ilvod_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_vshf_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srar_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_srlr_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_hadd_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_hadd_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_hsub_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_hsub_u_df, void, env, i32, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index 114008fe3d..f879cc7808 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -451,3 +451,660 @@ void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ MSA_TEROP_IMMU_DF(binsli, binsl) MSA_TEROP_IMMU_DF(binsri, binsr) #undef MSA_TEROP_IMMU_DF + +static inline int64_t msa_max_a_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; + uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; + return abs_arg1 > abs_arg2 ? arg1 : arg2; +} + +static inline int64_t msa_min_a_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; + uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; + return abs_arg1 < abs_arg2 ? arg1 : arg2; +} + +static inline int64_t msa_add_a_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; + uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; + return abs_arg1 + abs_arg2; +} + +static inline int64_t msa_adds_a_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t max_int = (uint64_t)DF_MAX_INT(df); + uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; + uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; + if (abs_arg1 > max_int || abs_arg2 > max_int) { + return (int64_t)max_int; + } else { + return (abs_arg1 < max_int - abs_arg2) ? abs_arg1 + abs_arg2 : max_int; + } +} + +static inline int64_t msa_adds_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t max_int = DF_MAX_INT(df); + int64_t min_int = DF_MIN_INT(df); + if (arg1 < 0) { + return (min_int - arg1 < arg2) ? arg1 + arg2 : min_int; + } else { + return (arg2 < max_int - arg1) ? arg1 + arg2 : max_int; + } +} + +static inline uint64_t msa_adds_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) +{ + uint64_t max_uint = DF_MAX_UINT(df); + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return (u_arg1 < max_uint - u_arg2) ? u_arg1 + u_arg2 : max_uint; +} + +static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + /* signed shift */ + return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1); +} + +static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + /* unsigned shift */ + return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1); +} + +static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + /* signed shift */ + return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1); +} + +static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + /* unsigned shift */ + return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1); +} + +static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t max_int = DF_MAX_INT(df); + int64_t min_int = DF_MIN_INT(df); + if (arg2 > 0) { + return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int; + } else { + return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int; + } +} + +static inline int64_t msa_subs_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return (u_arg1 > u_arg2) ? u_arg1 - u_arg2 : 0; +} + +static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t max_uint = DF_MAX_UINT(df); + if (arg2 >= 0) { + uint64_t u_arg2 = (uint64_t)arg2; + return (u_arg1 > u_arg2) ? + (int64_t)(u_arg1 - u_arg2) : + 0; + } else { + uint64_t u_arg2 = (uint64_t)(-arg2); + return (u_arg1 < max_uint - u_arg2) ? + (int64_t)(u_arg1 + u_arg2) : + (int64_t)max_uint; + } +} + +static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + int64_t max_int = DF_MAX_INT(df); + int64_t min_int = DF_MIN_INT(df); + if (u_arg1 > u_arg2) { + return u_arg1 - u_arg2 < (uint64_t)max_int ? + (int64_t)(u_arg1 - u_arg2) : + max_int; + } else { + return u_arg2 - u_arg1 < (uint64_t)(-min_int) ? + (int64_t)(u_arg1 - u_arg2) : + min_int; + } +} + +static inline int64_t msa_asub_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + /* signed compare */ + return (arg1 < arg2) ? + (uint64_t)(arg2 - arg1) : (uint64_t)(arg1 - arg2); +} + +static inline uint64_t msa_asub_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + /* unsigned compare */ + return (u_arg1 < u_arg2) ? + (uint64_t)(u_arg2 - u_arg1) : (uint64_t)(u_arg1 - u_arg2); +} + +static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 * arg2; +} + +static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + if (arg1 == DF_MIN_INT(df) && arg2 == -1) { + return DF_MIN_INT(df); + } + return arg2 ? arg1 / arg2 : 0; +} + +static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg2 ? u_arg1 / u_arg2 : 0; +} + +static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + if (arg1 == DF_MIN_INT(df) && arg2 == -1) { + return 0; + } + return arg2 ? arg1 % arg2 : 0; +} + +static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg2 ? u_arg1 % u_arg2 : 0; +} + +#define SIGNED_EVEN(a, df) \ + ((((int64_t)(a)) << (64 - DF_BITS(df)/2)) >> (64 - DF_BITS(df)/2)) + +#define UNSIGNED_EVEN(a, df) \ + ((((uint64_t)(a)) << (64 - DF_BITS(df)/2)) >> (64 - DF_BITS(df)/2)) + +#define SIGNED_ODD(a, df) \ + ((((int64_t)(a)) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df)/2)) + +#define UNSIGNED_ODD(a, df) \ + ((((uint64_t)(a)) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df)/2)) + +#define SIGNED_EXTRACT(e, o, a, df) \ + do { \ + e = SIGNED_EVEN(a, df); \ + o = SIGNED_ODD(a, df); \ + } while (0); + +#define UNSIGNED_EXTRACT(e, o, a, df) \ + do { \ + e = UNSIGNED_EVEN(a, df); \ + o = UNSIGNED_ODD(a, df); \ + } while (0); + +static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +#define CONCATENATE_AND_SLIDE(s, k) \ + do { \ + for (i = 0; i < s; i++) { \ + v[i] = pws->b[s * k + i]; \ + v[i + s] = pwd->b[s * k + i]; \ + } \ + for (i = 0; i < s; i++) { \ + pwd->b[s * k + i] = v[i + n]; \ + } \ + } while (0) + +static inline void msa_sld_df(uint32_t df, wr_t *pwd, + wr_t *pws, target_ulong rt) +{ + uint32_t n = rt % DF_ELEMENTS(df); + uint8_t v[64]; + uint32_t i, k; + + switch (df) { + case DF_BYTE: + CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_BYTE), 0); + break; + case DF_HALF: + for (k = 0; k < 2; k++) { + CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_HALF), k); + } + break; + case DF_WORD: + for (k = 0; k < 4; k++) { + CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_WORD), k); + } + break; + case DF_DOUBLE: + for (k = 0; k < 8; k++) { + CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_DOUBLE), k); + } + break; + default: + assert(0); + } +} + +static inline int64_t msa_hadd_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return SIGNED_ODD(arg1, df) + SIGNED_EVEN(arg2, df); +} + +static inline int64_t msa_hadd_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return UNSIGNED_ODD(arg1, df) + UNSIGNED_EVEN(arg2, df); +} + +static inline int64_t msa_hsub_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return SIGNED_ODD(arg1, df) - SIGNED_EVEN(arg2, df); +} + +static inline int64_t msa_hsub_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return UNSIGNED_ODD(arg1, df) - UNSIGNED_EVEN(arg2, df); +} + +#define MSA_BINOP_DF(func) \ +void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ + uint32_t wd, uint32_t ws, uint32_t wt) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], pwt->b[i]); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pws->h[i], pwt->h[i]); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pws->w[i], pwt->w[i]); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pws->d[i], pwt->d[i]); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_BINOP_DF(sll) +MSA_BINOP_DF(sra) +MSA_BINOP_DF(srl) +MSA_BINOP_DF(bclr) +MSA_BINOP_DF(bset) +MSA_BINOP_DF(bneg) +MSA_BINOP_DF(addv) +MSA_BINOP_DF(subv) +MSA_BINOP_DF(max_s) +MSA_BINOP_DF(max_u) +MSA_BINOP_DF(min_s) +MSA_BINOP_DF(min_u) +MSA_BINOP_DF(max_a) +MSA_BINOP_DF(min_a) +MSA_BINOP_DF(ceq) +MSA_BINOP_DF(clt_s) +MSA_BINOP_DF(clt_u) +MSA_BINOP_DF(cle_s) +MSA_BINOP_DF(cle_u) +MSA_BINOP_DF(add_a) +MSA_BINOP_DF(adds_a) +MSA_BINOP_DF(adds_s) +MSA_BINOP_DF(adds_u) +MSA_BINOP_DF(ave_s) +MSA_BINOP_DF(ave_u) +MSA_BINOP_DF(aver_s) +MSA_BINOP_DF(aver_u) +MSA_BINOP_DF(subs_s) +MSA_BINOP_DF(subs_u) +MSA_BINOP_DF(subsus_u) +MSA_BINOP_DF(subsuu_s) +MSA_BINOP_DF(asub_s) +MSA_BINOP_DF(asub_u) +MSA_BINOP_DF(mulv) +MSA_BINOP_DF(div_s) +MSA_BINOP_DF(div_u) +MSA_BINOP_DF(mod_s) +MSA_BINOP_DF(mod_u) +MSA_BINOP_DF(dotp_s) +MSA_BINOP_DF(dotp_u) +MSA_BINOP_DF(srar) +MSA_BINOP_DF(srlr) +MSA_BINOP_DF(hadd_s) +MSA_BINOP_DF(hadd_u) +MSA_BINOP_DF(hsub_s) +MSA_BINOP_DF(hsub_u) +#undef MSA_BINOP_DF + +void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t rt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); +} + +static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + return dest + arg1 * arg2; +} + +static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + return dest - arg1 * arg2; +} + +static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); +} + +static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); +} + +static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t even_arg1; + int64_t even_arg2; + int64_t odd_arg1; + int64_t odd_arg2; + UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); + UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); + return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); +} + +#define MSA_TEROP_DF(func) \ +void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ + uint32_t ws, uint32_t wt) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pwd->b[i], pws->b[i], \ + pwt->b[i]); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pwd->h[i], pws->h[i], \ + pwt->h[i]); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pwd->w[i], pws->w[i], \ + pwt->w[i]); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pwd->d[i], pws->d[i], \ + pwt->d[i]); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_TEROP_DF(maddv) +MSA_TEROP_DF(msubv) +MSA_TEROP_DF(dpadd_s) +MSA_TEROP_DF(dpadd_u) +MSA_TEROP_DF(dpsub_s) +MSA_TEROP_DF(dpsub_u) +MSA_TEROP_DF(binsl) +MSA_TEROP_DF(binsr) +#undef MSA_TEROP_DF + +static inline void msa_splat_df(uint32_t df, wr_t *pwd, + wr_t *pws, target_ulong rt) +{ + uint32_t n = rt % DF_ELEMENTS(df); + uint32_t i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + pwd->b[i] = pws->b[n]; + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + pwd->h[i] = pws->h[n]; + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + pwd->w[i] = pws->w[n]; + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + pwd->d[i] = pws->d[n]; + } + break; + default: + assert(0); + } +} + +void helper_msa_splat_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t rt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + msa_splat_df(df, pwd, pws, env->active_tc.gpr[rt]); +} + +#define MSA_DO_B MSA_DO(b) +#define MSA_DO_H MSA_DO(h) +#define MSA_DO_W MSA_DO(w) +#define MSA_DO_D MSA_DO(d) + +#define MSA_LOOP_B MSA_LOOP(B) +#define MSA_LOOP_H MSA_LOOP(H) +#define MSA_LOOP_W MSA_LOOP(W) +#define MSA_LOOP_D MSA_LOOP(D) + +#define MSA_LOOP_COND_B MSA_LOOP_COND(DF_BYTE) +#define MSA_LOOP_COND_H MSA_LOOP_COND(DF_HALF) +#define MSA_LOOP_COND_W MSA_LOOP_COND(DF_WORD) +#define MSA_LOOP_COND_D MSA_LOOP_COND(DF_DOUBLE) + +#define MSA_LOOP(DF) \ + for (i = 0; i < (MSA_LOOP_COND_ ## DF) ; i++) { \ + MSA_DO_ ## DF \ + } + +#define MSA_FN_DF(FUNC) \ +void helper_msa_##FUNC(CPUMIPSState *env, uint32_t df, uint32_t wd, \ + uint32_t ws, uint32_t wt) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ + wr_t wx, *pwx = &wx; \ + uint32_t i; \ + switch (df) { \ + case DF_BYTE: \ + MSA_LOOP_B \ + break; \ + case DF_HALF: \ + MSA_LOOP_H \ + break; \ + case DF_WORD: \ + MSA_LOOP_W \ + break; \ + case DF_DOUBLE: \ + MSA_LOOP_D \ + break; \ + default: \ + assert(0); \ + } \ + msa_move_v(pwd, pwx); \ +} + +#define MSA_LOOP_COND(DF) \ + (DF_ELEMENTS(DF) / 2) + +#define Rb(pwr, i) (pwr->b[i]) +#define Lb(pwr, i) (pwr->b[i + DF_ELEMENTS(DF_BYTE)/2]) +#define Rh(pwr, i) (pwr->h[i]) +#define Lh(pwr, i) (pwr->h[i + DF_ELEMENTS(DF_HALF)/2]) +#define Rw(pwr, i) (pwr->w[i]) +#define Lw(pwr, i) (pwr->w[i + DF_ELEMENTS(DF_WORD)/2]) +#define Rd(pwr, i) (pwr->d[i]) +#define Ld(pwr, i) (pwr->d[i + DF_ELEMENTS(DF_DOUBLE)/2]) + +#define MSA_DO(DF) \ + do { \ + R##DF(pwx, i) = pwt->DF[2*i]; \ + L##DF(pwx, i) = pws->DF[2*i]; \ + } while (0); +MSA_FN_DF(pckev_df) +#undef MSA_DO + +#define MSA_DO(DF) \ + do { \ + R##DF(pwx, i) = pwt->DF[2*i+1]; \ + L##DF(pwx, i) = pws->DF[2*i+1]; \ + } while (0); +MSA_FN_DF(pckod_df) +#undef MSA_DO + +#define MSA_DO(DF) \ + do { \ + pwx->DF[2*i] = L##DF(pwt, i); \ + pwx->DF[2*i+1] = L##DF(pws, i); \ + } while (0); +MSA_FN_DF(ilvl_df) +#undef MSA_DO + +#define MSA_DO(DF) \ + do { \ + pwx->DF[2*i] = R##DF(pwt, i); \ + pwx->DF[2*i+1] = R##DF(pws, i); \ + } while (0); +MSA_FN_DF(ilvr_df) +#undef MSA_DO + +#define MSA_DO(DF) \ + do { \ + pwx->DF[2*i] = pwt->DF[2*i]; \ + pwx->DF[2*i+1] = pws->DF[2*i]; \ + } while (0); +MSA_FN_DF(ilvev_df) +#undef MSA_DO + +#define MSA_DO(DF) \ + do { \ + pwx->DF[2*i] = pwt->DF[2*i+1]; \ + pwx->DF[2*i+1] = pws->DF[2*i+1]; \ + } while (0); +MSA_FN_DF(ilvod_df) +#undef MSA_DO +#undef MSA_LOOP_COND + +#define MSA_LOOP_COND(DF) \ + (DF_ELEMENTS(DF)) + +#define MSA_DO(DF) \ + do { \ + uint32_t n = DF_ELEMENTS(df); \ + uint32_t k = (pwd->DF[i] & 0x3f) % (2 * n); \ + pwx->DF[i] = \ + (pwd->DF[i] & 0xc0) ? 0 : k < n ? pwt->DF[k] : pws->DF[k - n]; \ + } while (0); +MSA_FN_DF(vshf_df) +#undef MSA_DO +#undef MSA_LOOP_COND +#undef MSA_FN_DF diff --git a/target-mips/translate.c b/target-mips/translate.c index 1f3bd72e1a..0d5a054021 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17549,6 +17549,237 @@ static void gen_msa_bit(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(tws); } +static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_3R(op) (MASK_MSA_MINOR(op) | (op & (0x7 << 23))) + uint8_t df = (ctx->opcode >> 21) & 0x3; + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + + TCGv_i32 tdf = tcg_const_i32(df); + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + + switch (MASK_MSA_3R(ctx->opcode)) { + case OPC_SLL_df: + gen_helper_msa_sll_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ADDV_df: + gen_helper_msa_addv_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_CEQ_df: + gen_helper_msa_ceq_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ADD_A_df: + gen_helper_msa_add_a_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SUBS_S_df: + gen_helper_msa_subs_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MULV_df: + gen_helper_msa_mulv_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SLD_df: + gen_helper_msa_sld_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_VSHF_df: + gen_helper_msa_vshf_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SRA_df: + gen_helper_msa_sra_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SUBV_df: + gen_helper_msa_subv_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ADDS_A_df: + gen_helper_msa_adds_a_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SUBS_U_df: + gen_helper_msa_subs_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MADDV_df: + gen_helper_msa_maddv_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SPLAT_df: + gen_helper_msa_splat_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SRAR_df: + gen_helper_msa_srar_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SRL_df: + gen_helper_msa_srl_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MAX_S_df: + gen_helper_msa_max_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_CLT_S_df: + gen_helper_msa_clt_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ADDS_S_df: + gen_helper_msa_adds_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SUBSUS_U_df: + gen_helper_msa_subsus_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MSUBV_df: + gen_helper_msa_msubv_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_PCKEV_df: + gen_helper_msa_pckev_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SRLR_df: + gen_helper_msa_srlr_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_BCLR_df: + gen_helper_msa_bclr_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MAX_U_df: + gen_helper_msa_max_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_CLT_U_df: + gen_helper_msa_clt_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ADDS_U_df: + gen_helper_msa_adds_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_SUBSUU_S_df: + gen_helper_msa_subsuu_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_PCKOD_df: + gen_helper_msa_pckod_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_BSET_df: + gen_helper_msa_bset_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MIN_S_df: + gen_helper_msa_min_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_CLE_S_df: + gen_helper_msa_cle_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_AVE_S_df: + gen_helper_msa_ave_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ASUB_S_df: + gen_helper_msa_asub_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DIV_S_df: + gen_helper_msa_div_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ILVL_df: + gen_helper_msa_ilvl_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_BNEG_df: + gen_helper_msa_bneg_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MIN_U_df: + gen_helper_msa_min_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_CLE_U_df: + gen_helper_msa_cle_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_AVE_U_df: + gen_helper_msa_ave_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ASUB_U_df: + gen_helper_msa_asub_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DIV_U_df: + gen_helper_msa_div_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ILVR_df: + gen_helper_msa_ilvr_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_BINSL_df: + gen_helper_msa_binsl_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MAX_A_df: + gen_helper_msa_max_a_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_AVER_S_df: + gen_helper_msa_aver_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MOD_S_df: + gen_helper_msa_mod_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ILVEV_df: + gen_helper_msa_ilvev_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_BINSR_df: + gen_helper_msa_binsr_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MIN_A_df: + gen_helper_msa_min_a_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_AVER_U_df: + gen_helper_msa_aver_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MOD_U_df: + gen_helper_msa_mod_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_ILVOD_df: + gen_helper_msa_ilvod_df(cpu_env, tdf, twd, tws, twt); + break; + + case OPC_DOTP_S_df: + case OPC_DOTP_U_df: + case OPC_DPADD_S_df: + case OPC_DPADD_U_df: + case OPC_DPSUB_S_df: + case OPC_HADD_S_df: + case OPC_DPSUB_U_df: + case OPC_HADD_U_df: + case OPC_HSUB_S_df: + case OPC_HSUB_U_df: + if (df == DF_BYTE) { + generate_exception(ctx, EXCP_RI); + } + switch (MASK_MSA_3R(ctx->opcode)) { + case OPC_DOTP_S_df: + gen_helper_msa_dotp_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DOTP_U_df: + gen_helper_msa_dotp_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DPADD_S_df: + gen_helper_msa_dpadd_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DPADD_U_df: + gen_helper_msa_dpadd_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DPSUB_S_df: + gen_helper_msa_dpsub_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_HADD_S_df: + gen_helper_msa_hadd_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_DPSUB_U_df: + gen_helper_msa_dpsub_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_HADD_U_df: + gen_helper_msa_hadd_u_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_HSUB_S_df: + gen_helper_msa_hsub_s_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_HSUB_U_df: + gen_helper_msa_hsub_u_df(cpu_env, tdf, twd, tws, twt); + break; + } + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); + tcg_temp_free_i32(tdf); +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -17569,6 +17800,17 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_BIT_0A: gen_msa_bit(env, ctx); break; + case OPC_MSA_3R_0D: + case OPC_MSA_3R_0E: + case OPC_MSA_3R_0F: + case OPC_MSA_3R_10: + case OPC_MSA_3R_11: + case OPC_MSA_3R_12: + case OPC_MSA_3R_13: + case OPC_MSA_3R_14: + case OPC_MSA_3R_15: + gen_msa_3r(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From 1e608ec14e0a0e9b57a889365fc8739043a46527 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:47 +0000 Subject: [PATCH 28/34] target-mips: add MSA ELM format instructions add MSA ELM format instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 10 +++ target-mips/msa_helper.c | 162 +++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 118 ++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index 4297d4a668..c9e033bdaa 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -848,3 +848,13 @@ DEF_HELPER_5(msa_hadd_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hadd_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hsub_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hsub_u_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_5(msa_sldi_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_splati_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_copy_s_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_copy_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_insert_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32) +DEF_HELPER_3(msa_ctcmsa, void, env, tl, i32) +DEF_HELPER_2(msa_cfcmsa, tl, env, i32) +DEF_HELPER_3(msa_move_v, void, env, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index f879cc7808..3a909e6b45 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -1108,3 +1108,165 @@ MSA_FN_DF(vshf_df) #undef MSA_DO #undef MSA_LOOP_COND #undef MSA_FN_DF + +void helper_msa_sldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + msa_sld_df(df, pwd, pws, n); +} + +void helper_msa_splati_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + msa_splat_df(df, pwd, pws, n); +} + +void helper_msa_copy_s_df(CPUMIPSState *env, uint32_t df, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= DF_ELEMENTS(df); + + switch (df) { + case DF_BYTE: + env->active_tc.gpr[rd] = (int8_t)env->active_fpu.fpr[ws].wr.b[n]; + break; + case DF_HALF: + env->active_tc.gpr[rd] = (int16_t)env->active_fpu.fpr[ws].wr.h[n]; + break; + case DF_WORD: + env->active_tc.gpr[rd] = (int32_t)env->active_fpu.fpr[ws].wr.w[n]; + break; +#ifdef TARGET_MIPS64 + case DF_DOUBLE: + env->active_tc.gpr[rd] = (int64_t)env->active_fpu.fpr[ws].wr.d[n]; + break; +#endif + default: + assert(0); + } +} + +void helper_msa_copy_u_df(CPUMIPSState *env, uint32_t df, uint32_t rd, + uint32_t ws, uint32_t n) +{ + n %= DF_ELEMENTS(df); + + switch (df) { + case DF_BYTE: + env->active_tc.gpr[rd] = (uint8_t)env->active_fpu.fpr[ws].wr.b[n]; + break; + case DF_HALF: + env->active_tc.gpr[rd] = (uint16_t)env->active_fpu.fpr[ws].wr.h[n]; + break; + case DF_WORD: + env->active_tc.gpr[rd] = (uint32_t)env->active_fpu.fpr[ws].wr.w[n]; + break; +#ifdef TARGET_MIPS64 + case DF_DOUBLE: + env->active_tc.gpr[rd] = (uint64_t)env->active_fpu.fpr[ws].wr.d[n]; + break; +#endif + default: + assert(0); + } +} + +void helper_msa_insert_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t rs_num, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + target_ulong rs = env->active_tc.gpr[rs_num]; + + switch (df) { + case DF_BYTE: + pwd->b[n] = (int8_t)rs; + break; + case DF_HALF: + pwd->h[n] = (int16_t)rs; + break; + case DF_WORD: + pwd->w[n] = (int32_t)rs; + break; + case DF_DOUBLE: + pwd->d[n] = (int64_t)rs; + break; + default: + assert(0); + } +} + +void helper_msa_insve_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t n) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + switch (df) { + case DF_BYTE: + pwd->b[n] = (int8_t)pws->b[0]; + break; + case DF_HALF: + pwd->h[n] = (int16_t)pws->h[0]; + break; + case DF_WORD: + pwd->w[n] = (int32_t)pws->w[0]; + break; + case DF_DOUBLE: + pwd->d[n] = (int64_t)pws->d[0]; + break; + default: + assert(0); + } +} + +void helper_msa_ctcmsa(CPUMIPSState *env, target_ulong elm, uint32_t cd) +{ + switch (cd) { + case 0: + break; + case 1: + env->active_tc.msacsr = (int32_t)elm & MSACSR_MASK; + /* set float_status rounding mode */ + set_float_rounding_mode( + ieee_rm[(env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM], + &env->active_tc.msa_fp_status); + /* set float_status flush modes */ + set_flush_to_zero( + (env->active_tc.msacsr & MSACSR_FS_MASK) != 0 ? 1 : 0, + &env->active_tc.msa_fp_status); + set_flush_inputs_to_zero( + (env->active_tc.msacsr & MSACSR_FS_MASK) != 0 ? 1 : 0, + &env->active_tc.msa_fp_status); + /* check exception */ + if ((GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED) + & GET_FP_CAUSE(env->active_tc.msacsr)) { + helper_raise_exception(env, EXCP_MSAFPE); + } + break; + } +} + +target_ulong helper_msa_cfcmsa(CPUMIPSState *env, uint32_t cs) +{ + switch (cs) { + case 0: + return env->msair; + case 1: + return env->active_tc.msacsr & MSACSR_MASK; + } + return 0; +} + +void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + msa_move_v(pwd, pws); +} diff --git a/target-mips/translate.c b/target-mips/translate.c index 0d5a054021..31a56b6a44 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17780,6 +17780,121 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(tdf); } +static void gen_msa_elm_3e(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_ELM_DF3E(op) (MASK_MSA_MINOR(op) | (op & (0x3FF << 16))) + uint8_t source = (ctx->opcode >> 11) & 0x1f; + uint8_t dest = (ctx->opcode >> 6) & 0x1f; + TCGv telm = tcg_temp_new(); + TCGv_i32 tsr = tcg_const_i32(source); + TCGv_i32 tdt = tcg_const_i32(dest); + + switch (MASK_MSA_ELM_DF3E(ctx->opcode)) { + case OPC_CTCMSA: + gen_load_gpr(telm, source); + gen_helper_msa_ctcmsa(cpu_env, telm, tdt); + break; + case OPC_CFCMSA: + gen_helper_msa_cfcmsa(telm, cpu_env, tsr); + gen_store_gpr(telm, dest); + break; + case OPC_MOVE_V: + gen_helper_msa_move_v(cpu_env, tdt, tsr); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free(telm); + tcg_temp_free_i32(tdt); + tcg_temp_free_i32(tsr); +} + +static void gen_msa_elm_df(CPUMIPSState *env, DisasContext *ctx, uint32_t df, + uint32_t n) +{ +#define MASK_MSA_ELM(op) (MASK_MSA_MINOR(op) | (op & (0xf << 22))) + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tn = tcg_const_i32(n); + TCGv_i32 tdf = tcg_const_i32(df); + + switch (MASK_MSA_ELM(ctx->opcode)) { + case OPC_SLDI_df: + gen_helper_msa_sldi_df(cpu_env, tdf, twd, tws, tn); + break; + case OPC_SPLATI_df: + gen_helper_msa_splati_df(cpu_env, tdf, twd, tws, tn); + break; + case OPC_INSVE_df: + gen_helper_msa_insve_df(cpu_env, tdf, twd, tws, tn); + break; + case OPC_COPY_S_df: + case OPC_COPY_U_df: + case OPC_INSERT_df: +#if !defined(TARGET_MIPS64) + /* Double format valid only for MIPS64 */ + if (df == DF_DOUBLE) { + generate_exception(ctx, EXCP_RI); + break; + } +#endif + switch (MASK_MSA_ELM(ctx->opcode)) { + case OPC_COPY_S_df: + gen_helper_msa_copy_s_df(cpu_env, tdf, twd, tws, tn); + break; + case OPC_COPY_U_df: + gen_helper_msa_copy_u_df(cpu_env, tdf, twd, tws, tn); + break; + case OPC_INSERT_df: + gen_helper_msa_insert_df(cpu_env, tdf, twd, tws, tn); + break; + } + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + } + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(tn); + tcg_temp_free_i32(tdf); +} + +static void gen_msa_elm(CPUMIPSState *env, DisasContext *ctx) +{ + uint8_t dfn = (ctx->opcode >> 16) & 0x3f; + uint32_t df = 0, n = 0; + + if ((dfn & 0x30) == 0x00) { + n = dfn & 0x0f; + df = DF_BYTE; + } else if ((dfn & 0x38) == 0x20) { + n = dfn & 0x07; + df = DF_HALF; + } else if ((dfn & 0x3c) == 0x30) { + n = dfn & 0x03; + df = DF_WORD; + } else if ((dfn & 0x3e) == 0x38) { + n = dfn & 0x01; + df = DF_DOUBLE; + } else if (dfn == 0x3E) { + /* CTCMSA, CFCMSA, MOVE.V */ + gen_msa_elm_3e(env, ctx); + return; + } else { + generate_exception(ctx, EXCP_RI); + return; + } + + gen_msa_elm_df(env, ctx, df, n); +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -17811,6 +17926,9 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_3R_15: gen_msa_3r(env, ctx); break; + case OPC_MSA_ELM: + gen_msa_elm(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From 7d05b9c86fa1b5620296eceed8c347815da8d688 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:48 +0000 Subject: [PATCH 29/34] target-mips: add MSA 3RF format instructions add MSA 3RF format instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 42 ++ target-mips/msa_helper.c | 1494 ++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 163 +++++ 3 files changed, 1699 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index c9e033bdaa..cee4eb47e7 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -858,3 +858,45 @@ DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32) DEF_HELPER_3(msa_ctcmsa, void, env, tl, i32) DEF_HELPER_2(msa_cfcmsa, tl, env, i32) DEF_HELPER_3(msa_move_v, void, env, i32, i32) + +DEF_HELPER_5(msa_fcaf_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcun_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fceq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcueq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fclt_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcult_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcle_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcule_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsaf_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsun_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fseq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsueq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fslt_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsult_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsle_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsule_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fadd_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsub_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmul_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fdiv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmadd_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmsub_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fexp2_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fexdo_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ftq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmin_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmin_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmax_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmax_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcor_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcune_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcne_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mul_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_madd_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_msub_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsor_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsune_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsne_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index 3a909e6b45..3f3d9ebe5e 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -743,6 +743,29 @@ static inline int64_t msa_hsub_u_df(uint32_t df, int64_t arg1, int64_t arg2) return UNSIGNED_ODD(arg1, df) - UNSIGNED_EVEN(arg2, df); } +static inline int64_t msa_mul_q_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t q_min = DF_MIN_INT(df); + int64_t q_max = DF_MAX_INT(df); + + if (arg1 == q_min && arg2 == q_min) { + return q_max; + } + return (arg1 * arg2) >> (DF_BITS(df) - 1); +} + +static inline int64_t msa_mulr_q_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int64_t q_min = DF_MIN_INT(df); + int64_t q_max = DF_MAX_INT(df); + int64_t r_bit = 1 << (DF_BITS(df) - 2); + + if (arg1 == q_min && arg2 == q_min) { + return q_max; + } + return (arg1 * arg2 + r_bit) >> (DF_BITS(df) - 1); +} + #define MSA_BINOP_DF(func) \ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ uint32_t wd, uint32_t ws, uint32_t wt) \ @@ -824,6 +847,9 @@ MSA_BINOP_DF(hadd_s) MSA_BINOP_DF(hadd_u) MSA_BINOP_DF(hsub_s) MSA_BINOP_DF(hsub_u) + +MSA_BINOP_DF(mul_q) +MSA_BINOP_DF(mulr_q) #undef MSA_BINOP_DF void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, @@ -895,6 +921,64 @@ static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); } +static inline int64_t msa_madd_q_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) + q_prod) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +static inline int64_t msa_msub_q_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) - q_prod) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +static inline int64_t msa_maddr_q_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + int64_t r_bit = 1 << (DF_BITS(df) - 2); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) + q_prod + r_bit) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +static inline int64_t msa_msubr_q_df(uint32_t df, int64_t dest, int64_t arg1, + int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + int64_t r_bit = 1 << (DF_BITS(df) - 2); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) - q_prod + r_bit) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + #define MSA_TEROP_DF(func) \ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ uint32_t ws, uint32_t wt) \ @@ -942,6 +1026,10 @@ MSA_TEROP_DF(dpsub_s) MSA_TEROP_DF(dpsub_u) MSA_TEROP_DF(binsl) MSA_TEROP_DF(binsr) +MSA_TEROP_DF(madd_q) +MSA_TEROP_DF(msub_q) +MSA_TEROP_DF(maddr_q) +MSA_TEROP_DF(msubr_q) #undef MSA_TEROP_DF static inline void msa_splat_df(uint32_t df, wr_t *pwd, @@ -1270,3 +1358,1409 @@ void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) msa_move_v(pwd, pws); } + +#define FLOAT_ONE32 make_float32(0x3f8 << 20) +#define FLOAT_ONE64 make_float64(0x3ffULL << 52) + +#define FLOAT_SNAN16 (float16_default_nan ^ 0x0220) + /* 0x7c20 */ +#define FLOAT_SNAN32 (float32_default_nan ^ 0x00400020) + /* 0x7f800020 */ +#define FLOAT_SNAN64 (float64_default_nan ^ 0x0008000000000020ULL) + /* 0x7ff0000000000020 */ + +static inline void clear_msacsr_cause(CPUMIPSState *env) +{ + SET_FP_CAUSE(env->active_tc.msacsr, 0); +} + +static inline void check_msacsr_cause(CPUMIPSState *env) +{ + if ((GET_FP_CAUSE(env->active_tc.msacsr) & + (GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)) == 0) { + UPDATE_FP_FLAGS(env->active_tc.msacsr, + GET_FP_CAUSE(env->active_tc.msacsr)); + } else { + helper_raise_exception(env, EXCP_MSAFPE); + } +} + +/* Flush-to-zero use cases for update_msacsr() */ +#define CLEAR_FS_UNDERFLOW 1 +#define CLEAR_IS_INEXACT 2 +#define RECIPROCAL_INEXACT 4 + +static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) +{ + int ieee_ex; + + int c; + int cause; + int enable; + + ieee_ex = get_float_exception_flags(&env->active_tc.msa_fp_status); + + /* QEMU softfloat does not signal all underflow cases */ + if (denormal) { + ieee_ex |= float_flag_underflow; + } + + c = ieee_ex_to_mips(ieee_ex); + enable = GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED; + + /* Set Inexact (I) when flushing inputs to zero */ + if ((ieee_ex & float_flag_input_denormal) && + (env->active_tc.msacsr & MSACSR_FS_MASK) != 0) { + if (action & CLEAR_IS_INEXACT) { + c &= ~FP_INEXACT; + } else { + c |= FP_INEXACT; + } + } + + /* Set Inexact (I) and Underflow (U) when flushing outputs to zero */ + if ((ieee_ex & float_flag_output_denormal) && + (env->active_tc.msacsr & MSACSR_FS_MASK) != 0) { + c |= FP_INEXACT; + if (action & CLEAR_FS_UNDERFLOW) { + c &= ~FP_UNDERFLOW; + } else { + c |= FP_UNDERFLOW; + } + } + + /* Set Inexact (I) when Overflow (O) is not enabled */ + if ((c & FP_OVERFLOW) != 0 && (enable & FP_OVERFLOW) == 0) { + c |= FP_INEXACT; + } + + /* Clear Exact Underflow when Underflow (U) is not enabled */ + if ((c & FP_UNDERFLOW) != 0 && (enable & FP_UNDERFLOW) == 0 && + (c & FP_INEXACT) == 0) { + c &= ~FP_UNDERFLOW; + } + + /* Reciprocal operations set only Inexact when valid and not + divide by zero */ + if ((action & RECIPROCAL_INEXACT) && + (c & (FP_INVALID | FP_DIV0)) == 0) { + c = FP_INEXACT; + } + + cause = c & enable; /* all current enabled exceptions */ + + if (cause == 0) { + /* No enabled exception, update the MSACSR Cause + with all current exceptions */ + SET_FP_CAUSE(env->active_tc.msacsr, + (GET_FP_CAUSE(env->active_tc.msacsr) | c)); + } else { + /* Current exceptions are enabled */ + if ((env->active_tc.msacsr & MSACSR_NX_MASK) == 0) { + /* Exception(s) will trap, update MSACSR Cause + with all enabled exceptions */ + SET_FP_CAUSE(env->active_tc.msacsr, + (GET_FP_CAUSE(env->active_tc.msacsr) | c)); + } + } + + return c; +} + +static inline int get_enabled_exceptions(const CPUMIPSState *env, int c) +{ + int enable = GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED; + return c & enable; +} + +static inline float16 float16_from_float32(int32 a, flag ieee STATUS_PARAM) +{ + float16 f_val; + + f_val = float32_to_float16((float32)a, ieee STATUS_VAR); + f_val = float16_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1 << 15)) : f_val; +} + +static inline float32 float32_from_float64(int64 a STATUS_PARAM) +{ + float32 f_val; + + f_val = float64_to_float32((float64)a STATUS_VAR); + f_val = float32_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1 << 31)) : f_val; +} + +static inline float32 float32_from_float16(int16_t a, flag ieee STATUS_PARAM) +{ + float32 f_val; + + f_val = float16_to_float32((float16)a, ieee STATUS_VAR); + f_val = float32_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1 << 31)) : f_val; +} + +static inline float64 float64_from_float32(int32 a STATUS_PARAM) +{ + float64 f_val; + + f_val = float32_to_float64((float64)a STATUS_VAR); + f_val = float64_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1ULL << 63)) : f_val; +} + +static inline float32 float32_from_q16(int16_t a STATUS_PARAM) +{ + float32 f_val; + + /* conversion as integer and scaling */ + f_val = int32_to_float32(a STATUS_VAR); + f_val = float32_scalbn(f_val, -15 STATUS_VAR); + + return f_val; +} + +static inline float64 float64_from_q32(int32 a STATUS_PARAM) +{ + float64 f_val; + + /* conversion as integer and scaling */ + f_val = int32_to_float64(a STATUS_VAR); + f_val = float64_scalbn(f_val, -31 STATUS_VAR); + + return f_val; +} + +static inline int16_t float32_to_q16(float32 a STATUS_PARAM) +{ + int32 q_val; + int32 q_min = 0xffff8000; + int32 q_max = 0x00007fff; + + int ieee_ex; + + if (float32_is_any_nan(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } + + /* scaling */ + a = float32_scalbn(a, 15 STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + if (ieee_ex & float_flag_overflow) { + float_raise(float_flag_inexact STATUS_VAR); + return (int32)a < 0 ? q_min : q_max; + } + + /* conversion to int */ + q_val = float32_to_int32(a STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + if (ieee_ex & float_flag_invalid) { + set_float_exception_flags(ieee_ex & (~float_flag_invalid) + STATUS_VAR); + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int32)a < 0 ? q_min : q_max; + } + + if (q_val < q_min) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int16_t)q_min; + } + + if (q_max < q_val) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int16_t)q_max; + } + + return (int16_t)q_val; +} + +static inline int32 float64_to_q32(float64 a STATUS_PARAM) +{ + int64 q_val; + int64 q_min = 0xffffffff80000000LL; + int64 q_max = 0x000000007fffffffLL; + + int ieee_ex; + + if (float64_is_any_nan(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } + + /* scaling */ + a = float64_scalbn(a, 31 STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + if (ieee_ex & float_flag_overflow) { + float_raise(float_flag_inexact STATUS_VAR); + return (int64)a < 0 ? q_min : q_max; + } + + /* conversion to integer */ + q_val = float64_to_int64(a STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + if (ieee_ex & float_flag_invalid) { + set_float_exception_flags(ieee_ex & (~float_flag_invalid) + STATUS_VAR); + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int64)a < 0 ? q_min : q_max; + } + + if (q_val < q_min) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int32)q_min; + } + + if (q_max < q_val) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int32)q_max; + } + + return (int32)q_val; +} + +#define MSA_FLOAT_COND(DEST, OP, ARG1, ARG2, BITS, QUIET) \ + do { \ + int c; \ + int64_t cond; \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + if (!QUIET) { \ + cond = float ## BITS ## _ ## OP(ARG1, ARG2, \ + &env->active_tc.msa_fp_status); \ + } else { \ + cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, \ + &env->active_tc.msa_fp_status); \ + } \ + DEST = cond ? M_MAX_UINT(BITS) : 0; \ + c = update_msacsr(env, CLEAR_IS_INEXACT, 0); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define MSA_FLOAT_AF(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, eq, ARG1, ARG2, BITS, QUIET); \ + if ((DEST & M_MAX_UINT(BITS)) == M_MAX_UINT(BITS)) { \ + DEST = 0; \ + } \ + } while (0) + +#define MSA_FLOAT_UEQ(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, eq, ARG1, ARG2, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_NE(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG2, ARG1, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_UNE(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG2, ARG1, BITS, QUIET); \ + } \ + } \ + } while (0) + +#define MSA_FLOAT_ULE(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, le, ARG1, ARG2, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_ULT(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_OR(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, le, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, le, ARG2, ARG1, BITS, QUIET); \ + } \ + } while (0) + +static inline void compare_af(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_AF(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_AF(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_un(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_COND(pwx->w[i], unordered, pws->w[i], pwt->w[i], 32, + quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_COND(pwx->d[i], unordered, pws->d[i], pwt->d[i], 64, + quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_eq(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_COND(pwx->w[i], eq, pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_COND(pwx->d[i], eq, pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_ueq(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UEQ(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UEQ(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_lt(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_COND(pwx->w[i], lt, pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_COND(pwx->d[i], lt, pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_ult(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_ULT(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_ULT(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_le(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_COND(pwx->w[i], le, pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_COND(pwx->d[i], le, pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_ule(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_ULE(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_ULE(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_or(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_OR(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_OR(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_une(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) +{ + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNE(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNE(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline void compare_ne(CPUMIPSState *env, wr_t *pwd, wr_t *pws, + wr_t *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_NE(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_NE(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_af(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcun_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_un(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fceq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_eq(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ueq(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fclt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_lt(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcult_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ult(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcle_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_le(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcule_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ule(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_af(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsun_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_un(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fseq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_eq(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ueq(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fslt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_lt(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsult_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ult(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsle_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_le(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsule_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ule(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fcor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_or(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcune_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_une(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fcne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ne(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_or(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsune_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_une(env, pwd, pws, pwt, df, 0); +} + +void helper_msa_fsne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + compare_ne(env, pwd, pws, pwt, df, 0); +} + +#define float16_is_zero(ARG) 0 +#define float16_is_zero_or_denormal(ARG) 0 + +#define IS_DENORMAL(ARG, BITS) \ + (!float ## BITS ## _is_zero(ARG) \ + && float ## BITS ## _is_zero_or_denormal(ARG)) + +#define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \ + &env->active_tc.msa_fp_status); \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +void helper_msa_fadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_BINOP(pwx->w[i], add, pws->w[i], pwt->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_BINOP(pwx->d[i], add, pws->d[i], pwt->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_fsub_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_BINOP(pwx->w[i], sub, pws->w[i], pwt->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_BINOP(pwx->d[i], sub, pws->d[i], pwt->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_fmul_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_BINOP(pwx->w[i], mul, pws->w[i], pwt->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_BINOP(pwx->d[i], mul, pws->d[i], pwt->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fdiv_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_BINOP(pwx->w[i], div, pws->w[i], pwt->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_BINOP(pwx->d[i], div, pws->d[i], pwt->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, \ + &env->active_tc.msa_fp_status); \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +void helper_msa_fmadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_MULADD(pwx->w[i], pwd->w[i], + pws->w[i], pwt->w[i], 0, 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_MULADD(pwx->d[i], pwd->d[i], + pws->d[i], pwt->d[i], 0, 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmsub_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_MULADD(pwx->w[i], pwd->w[i], + pws->w[i], pwt->w[i], + float_muladd_negate_product, 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_MULADD(pwx->d[i], pwd->d[i], + pws->d[i], pwt->d[i], + float_muladd_negate_product, 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_BINOP(pwx->w[i], scalbn, pws->w[i], + pwt->w[i] > 0x200 ? 0x200 : + pwt->w[i] < -0x200 ? -0x200 : pwt->w[i], + 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_BINOP(pwx->d[i], scalbn, pws->d[i], + pwt->d[i] > 0x1000 ? 0x1000 : + pwt->d[i] < -0x1000 ? -0x1000 : pwt->d[i], + 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define MSA_FLOAT_UNOP(DEST, OP, ARG, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + /* Half precision floats come in two formats: standard + IEEE and "ARM" format. The latter gains extra exponent + range by omitting the NaN/Inf encodings. */ + flag ieee = 1; + + MSA_FLOAT_BINOP(Lh(pwx, i), from_float32, pws->w[i], ieee, 16); + MSA_FLOAT_BINOP(Rh(pwx, i), from_float32, pwt->w[i], ieee, 16); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(Lw(pwx, i), from_float64, pws->d[i], 32); + MSA_FLOAT_UNOP(Rw(pwx, i), from_float64, pwt->d[i], 32); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +#define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## XBITS >> 6) << 6) | c; \ + } \ + } while (0) + +void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP_XD(Lh(pwx, i), to_q16, pws->w[i], 32, 16); + MSA_FLOAT_UNOP_XD(Rh(pwx, i), to_q16, pwt->w[i], 32, 16); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP_XD(Lw(pwx, i), to_q32, pws->d[i], 64, 32); + MSA_FLOAT_UNOP_XD(Rw(pwx, i), to_q32, pwt->d[i], 64, 32); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define NUMBER_QNAN_PAIR(ARG1, ARG2, BITS) \ + !float ## BITS ## _is_any_nan(ARG1) \ + && float ## BITS ## _is_quiet_nan(ARG2) + +#define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \ + &env->active_tc.msa_fp_status); \ + c = update_msacsr(env, 0, 0); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define FMAXMIN_A(F, G, X, _S, _T, BITS) \ + do { \ + uint## BITS ##_t S = _S, T = _T; \ + uint## BITS ##_t as, at, xs, xt, xd; \ + if (NUMBER_QNAN_PAIR(S, T, BITS)) { \ + T = S; \ + } \ + else if (NUMBER_QNAN_PAIR(T, S, BITS)) { \ + S = T; \ + } \ + as = float## BITS ##_abs(S); \ + at = float## BITS ##_abs(T); \ + MSA_FLOAT_MAXOP(xs, F, S, T, BITS); \ + MSA_FLOAT_MAXOP(xt, G, S, T, BITS); \ + MSA_FLOAT_MAXOP(xd, F, as, at, BITS); \ + X = (as == at || xd == float## BITS ##_abs(xs)) ? xs : xt; \ + } while (0) + +void helper_msa_fmin_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + if (NUMBER_QNAN_PAIR(pws->w[i], pwt->w[i], 32)) { + MSA_FLOAT_MAXOP(pwx->w[i], min, pws->w[i], pws->w[i], 32); + } else if (NUMBER_QNAN_PAIR(pwt->w[i], pws->w[i], 32)) { + MSA_FLOAT_MAXOP(pwx->w[i], min, pwt->w[i], pwt->w[i], 32); + } else { + MSA_FLOAT_MAXOP(pwx->w[i], min, pws->w[i], pwt->w[i], 32); + } + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + if (NUMBER_QNAN_PAIR(pws->d[i], pwt->d[i], 64)) { + MSA_FLOAT_MAXOP(pwx->d[i], min, pws->d[i], pws->d[i], 64); + } else if (NUMBER_QNAN_PAIR(pwt->d[i], pws->d[i], 64)) { + MSA_FLOAT_MAXOP(pwx->d[i], min, pwt->d[i], pwt->d[i], 64); + } else { + MSA_FLOAT_MAXOP(pwx->d[i], min, pws->d[i], pwt->d[i], 64); + } + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmin_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + FMAXMIN_A(min, max, pwx->w[i], pws->w[i], pwt->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + FMAXMIN_A(min, max, pwx->d[i], pws->d[i], pwt->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmax_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + if (NUMBER_QNAN_PAIR(pws->w[i], pwt->w[i], 32)) { + MSA_FLOAT_MAXOP(pwx->w[i], max, pws->w[i], pws->w[i], 32); + } else if (NUMBER_QNAN_PAIR(pwt->w[i], pws->w[i], 32)) { + MSA_FLOAT_MAXOP(pwx->w[i], max, pwt->w[i], pwt->w[i], 32); + } else { + MSA_FLOAT_MAXOP(pwx->w[i], max, pws->w[i], pwt->w[i], 32); + } + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + if (NUMBER_QNAN_PAIR(pws->d[i], pwt->d[i], 64)) { + MSA_FLOAT_MAXOP(pwx->d[i], max, pws->d[i], pws->d[i], 64); + } else if (NUMBER_QNAN_PAIR(pwt->d[i], pws->d[i], 64)) { + MSA_FLOAT_MAXOP(pwx->d[i], max, pwt->d[i], pwt->d[i], 64); + } else { + MSA_FLOAT_MAXOP(pwx->d[i], max, pws->d[i], pwt->d[i], 64); + } + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmax_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + FMAXMIN_A(max, min, pwx->w[i], pws->w[i], pwt->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + FMAXMIN_A(max, min, pwx->d[i], pws->d[i], pwt->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} diff --git a/target-mips/translate.c b/target-mips/translate.c index 31a56b6a44..aae023cc88 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -17895,6 +17895,164 @@ static void gen_msa_elm(CPUMIPSState *env, DisasContext *ctx) gen_msa_elm_df(env, ctx, df, n); } +static void gen_msa_3rf(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_3RF(op) (MASK_MSA_MINOR(op) | (op & (0xf << 22))) + uint8_t df = (ctx->opcode >> 21) & 0x1; + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + TCGv_i32 tdf = tcg_temp_new_i32(); + + /* adjust df value for floating-point instruction */ + tcg_gen_movi_i32(tdf, df + 2); + + switch (MASK_MSA_3RF(ctx->opcode)) { + case OPC_FCAF_df: + gen_helper_msa_fcaf_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FADD_df: + gen_helper_msa_fadd_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCUN_df: + gen_helper_msa_fcun_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSUB_df: + gen_helper_msa_fsub_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCOR_df: + gen_helper_msa_fcor_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCEQ_df: + gen_helper_msa_fceq_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMUL_df: + gen_helper_msa_fmul_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCUNE_df: + gen_helper_msa_fcune_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCUEQ_df: + gen_helper_msa_fcueq_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FDIV_df: + gen_helper_msa_fdiv_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCNE_df: + gen_helper_msa_fcne_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCLT_df: + gen_helper_msa_fclt_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMADD_df: + gen_helper_msa_fmadd_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MUL_Q_df: + tcg_gen_movi_i32(tdf, df + 1); + gen_helper_msa_mul_q_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCULT_df: + gen_helper_msa_fcult_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMSUB_df: + gen_helper_msa_fmsub_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MADD_Q_df: + tcg_gen_movi_i32(tdf, df + 1); + gen_helper_msa_madd_q_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCLE_df: + gen_helper_msa_fcle_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MSUB_Q_df: + tcg_gen_movi_i32(tdf, df + 1); + gen_helper_msa_msub_q_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FCULE_df: + gen_helper_msa_fcule_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FEXP2_df: + gen_helper_msa_fexp2_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSAF_df: + gen_helper_msa_fsaf_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FEXDO_df: + gen_helper_msa_fexdo_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSUN_df: + gen_helper_msa_fsun_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSOR_df: + gen_helper_msa_fsor_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSEQ_df: + gen_helper_msa_fseq_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FTQ_df: + gen_helper_msa_ftq_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSUNE_df: + gen_helper_msa_fsune_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSUEQ_df: + gen_helper_msa_fsueq_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSNE_df: + gen_helper_msa_fsne_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSLT_df: + gen_helper_msa_fslt_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMIN_df: + gen_helper_msa_fmin_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MULR_Q_df: + tcg_gen_movi_i32(tdf, df + 1); + gen_helper_msa_mulr_q_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSULT_df: + gen_helper_msa_fsult_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMIN_A_df: + gen_helper_msa_fmin_a_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MADDR_Q_df: + tcg_gen_movi_i32(tdf, df + 1); + gen_helper_msa_maddr_q_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSLE_df: + gen_helper_msa_fsle_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMAX_df: + gen_helper_msa_fmax_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_MSUBR_Q_df: + tcg_gen_movi_i32(tdf, df + 1); + gen_helper_msa_msubr_q_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FSULE_df: + gen_helper_msa_fsule_df(cpu_env, tdf, twd, tws, twt); + break; + case OPC_FMAX_A_df: + gen_helper_msa_fmax_a_df(cpu_env, tdf, twd, tws, twt); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); + tcg_temp_free_i32(tdf); +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -17929,6 +18087,11 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_ELM: gen_msa_elm(env, ctx); break; + case OPC_MSA_3RF_1A: + case OPC_MSA_3RF_1B: + case OPC_MSA_3RF_1C: + gen_msa_3rf(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From cbe50b9a8e70eff6fead3f4bfc7a76e3db70c56c Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:49 +0000 Subject: [PATCH 30/34] target-mips: add MSA VEC/2R format instructions add MSA VEC/2R format instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 12 ++++ target-mips/msa_helper.c | 140 +++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 113 +++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index cee4eb47e7..3185c1d356 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -900,3 +900,15 @@ DEF_HELPER_5(msa_fsne_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index 3f3d9ebe5e..a96a64882f 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -114,6 +114,34 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } +#define MSA_FN_VECTOR(FUNC, DEST, OPERATION) \ +void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ + uint32_t wt) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ + uint32_t i; \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + DEST = OPERATION; \ + } \ +} + +MSA_FN_VECTOR(and_v, pwd->d[i], pws->d[i] & pwt->d[i]) +MSA_FN_VECTOR(or_v, pwd->d[i], pws->d[i] | pwt->d[i]) +MSA_FN_VECTOR(nor_v, pwd->d[i], ~(pws->d[i] | pwt->d[i])) +MSA_FN_VECTOR(xor_v, pwd->d[i], pws->d[i] ^ pwt->d[i]) +MSA_FN_VECTOR(bmnz_v, pwd->d[i], + BIT_MOVE_IF_NOT_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) +MSA_FN_VECTOR(bmz_v, pwd->d[i], + BIT_MOVE_IF_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) +MSA_FN_VECTOR(bsel_v, pwd->d[i], + BIT_SELECT(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) +#undef BIT_MOVE_IF_NOT_ZERO +#undef BIT_MOVE_IF_ZERO +#undef BIT_SELECT +#undef MSA_FN_VECTOR + static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2) { return arg1 + arg2; @@ -1359,6 +1387,118 @@ void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) msa_move_v(pwd, pws); } +static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg) +{ + uint64_t x; + + x = UNSIGNED(arg, df); + + x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL); + x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); + x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL); + x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL); + x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL); + x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32)); + + return x; +} + +static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg) +{ + uint64_t x, y; + int n, c; + + x = UNSIGNED(arg, df); + n = DF_BITS(df); + c = DF_BITS(df) / 2; + + do { + y = x >> c; + if (y != 0) { + n = n - c; + x = y; + } + c = c >> 1; + } while (c != 0); + + return n - x; +} + +static inline int64_t msa_nloc_df(uint32_t df, int64_t arg) +{ + return msa_nlzc_df(df, UNSIGNED((~arg), df)); +} + +void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t rs) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + uint32_t i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + pwd->b[i] = (int8_t)env->active_tc.gpr[rs]; + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + pwd->h[i] = (int16_t)env->active_tc.gpr[rs]; + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + pwd->w[i] = (int32_t)env->active_tc.gpr[rs]; + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + pwd->d[i] = (int64_t)env->active_tc.gpr[rs]; + } + break; + default: + assert(0); + } +} + +#define MSA_UNOP_DF(func) \ +void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ + uint32_t wd, uint32_t ws) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pws->b[i]); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pws->h[i]); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pws->w[i]); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pws->d[i]); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_UNOP_DF(nlzc) +MSA_UNOP_DF(nloc) +MSA_UNOP_DF(pcnt) + #define FLOAT_ONE32 make_float32(0x3f8 << 20) #define FLOAT_ONE64 make_float64(0x3ffULL << 52) diff --git a/target-mips/translate.c b/target-mips/translate.c index aae023cc88..acaf5a32bc 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -18053,6 +18053,116 @@ static void gen_msa_3rf(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(tdf); } +static void gen_msa_2r(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_2R(op) (MASK_MSA_MINOR(op) | (op & (0x1f << 21)) | \ + (op & (0x7 << 18))) + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + uint8_t df = (ctx->opcode >> 16) & 0x3; + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + TCGv_i32 tdf = tcg_const_i32(df); + + switch (MASK_MSA_2R(ctx->opcode)) { + case OPC_FILL_df: +#if !defined(TARGET_MIPS64) + /* Double format valid only for MIPS64 */ + if (df == DF_DOUBLE) { + generate_exception(ctx, EXCP_RI); + break; + } +#endif + gen_helper_msa_fill_df(cpu_env, tdf, twd, tws); /* trs */ + break; + case OPC_PCNT_df: + gen_helper_msa_pcnt_df(cpu_env, tdf, twd, tws); + break; + case OPC_NLOC_df: + gen_helper_msa_nloc_df(cpu_env, tdf, twd, tws); + break; + case OPC_NLZC_df: + gen_helper_msa_nlzc_df(cpu_env, tdf, twd, tws); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); + tcg_temp_free_i32(tdf); +} + +static void gen_msa_vec_v(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_VEC(op) (MASK_MSA_MINOR(op) | (op & (0x1f << 21))) + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + + switch (MASK_MSA_VEC(ctx->opcode)) { + case OPC_AND_V: + gen_helper_msa_and_v(cpu_env, twd, tws, twt); + break; + case OPC_OR_V: + gen_helper_msa_or_v(cpu_env, twd, tws, twt); + break; + case OPC_NOR_V: + gen_helper_msa_nor_v(cpu_env, twd, tws, twt); + break; + case OPC_XOR_V: + gen_helper_msa_xor_v(cpu_env, twd, tws, twt); + break; + case OPC_BMNZ_V: + gen_helper_msa_bmnz_v(cpu_env, twd, tws, twt); + break; + case OPC_BMZ_V: + gen_helper_msa_bmz_v(cpu_env, twd, tws, twt); + break; + case OPC_BSEL_V: + gen_helper_msa_bsel_v(cpu_env, twd, tws, twt); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); +} + +static void gen_msa_vec(CPUMIPSState *env, DisasContext *ctx) +{ + switch (MASK_MSA_VEC(ctx->opcode)) { + case OPC_AND_V: + case OPC_OR_V: + case OPC_NOR_V: + case OPC_XOR_V: + case OPC_BMNZ_V: + case OPC_BMZ_V: + case OPC_BSEL_V: + gen_msa_vec_v(env, ctx); + break; + case OPC_MSA_2R: + gen_msa_2r(env, ctx); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -18092,6 +18202,9 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_3RF_1C: gen_msa_3rf(env, ctx); break; + case OPC_MSA_VEC: + gen_msa_vec(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From 3bdeb68866ef2eb212b660381e080f412cc7c817 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:50 +0000 Subject: [PATCH 31/34] target-mips: add MSA 2RF format instructions add MSA 2RF format instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 17 ++ target-mips/msa_helper.c | 530 +++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 74 ++++++ 3 files changed, 621 insertions(+) diff --git a/target-mips/helper.h b/target-mips/helper.h index 3185c1d356..cb8b40efbf 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -912,3 +912,20 @@ DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_fclass_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ftrunc_s_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ftrunc_u_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_fsqrt_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_frsqrt_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_frcp_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_frint_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_flog2_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_fexupl_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_fexupr_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffql_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffqr_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ftint_s_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ftint_u_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffint_s_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffint_u_df, void, env, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index a96a64882f..b08f37f787 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -1498,6 +1498,7 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ MSA_UNOP_DF(nlzc) MSA_UNOP_DF(nloc) MSA_UNOP_DF(pcnt) +#undef MSA_UNOP_DF #define FLOAT_ONE32 make_float32(0x3f8 << 20) #define FLOAT_ONE64 make_float64(0x3ffULL << 52) @@ -2904,3 +2905,532 @@ void helper_msa_fmax_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } + +void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df, + uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + if (df == DF_WORD) { + pwd->w[0] = helper_float_class_s(pws->w[0]); + pwd->w[1] = helper_float_class_s(pws->w[1]); + pwd->w[2] = helper_float_class_s(pws->w[2]); + pwd->w[3] = helper_float_class_s(pws->w[3]); + } else { + pwd->d[0] = helper_float_class_d(pws->d[0]); + pwd->d[1] = helper_float_class_d(pws->d[1]); + } +} + +#define MSA_FLOAT_UNOP0(DEST, OP, ARG, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } else if (float ## BITS ## _is_any_nan(ARG)) { \ + DEST = 0; \ + } \ + } while (0) + +void helper_msa_ftrunc_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP0(pwx->w[i], to_int32_round_to_zero, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP0(pwx->d[i], to_int64_round_to_zero, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftrunc_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP0(pwx->w[i], to_uint32_round_to_zero, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP0(pwx->d[i], to_uint64_round_to_zero, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP(pwx->w[i], sqrt, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], sqrt, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define MSA_FLOAT_RECIPROCAL(DEST, ARG, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, \ + &env->active_tc.msa_fp_status); \ + c = update_msacsr(env, float ## BITS ## _is_infinity(ARG) || \ + float ## BITS ## _is_quiet_nan(DEST) ? \ + 0 : RECIPROCAL_INEXACT, \ + IS_DENORMAL(DEST, BITS)); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +void helper_msa_frsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_RECIPROCAL(pwx->w[i], float32_sqrt(pws->w[i], + &env->active_tc.msa_fp_status), 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_RECIPROCAL(pwx->d[i], float64_sqrt(pws->d[i], + &env->active_tc.msa_fp_status), 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_frcp_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_RECIPROCAL(pwx->w[i], pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_RECIPROCAL(pwx->d[i], pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_frint_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP(pwx->w[i], round_to_int, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], round_to_int, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define MSA_FLOAT_LOGB(DEST, ARG, BITS) \ + do { \ + int c; \ + \ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + set_float_rounding_mode(float_round_down, \ + &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## log2(ARG, \ + &env->active_tc.msa_fp_status); \ + DEST = float ## BITS ## _ ## round_to_int(DEST, \ + &env->active_tc.msa_fp_status); \ + set_float_rounding_mode(ieee_rm[(env->active_tc.msacsr & \ + MSACSR_RM_MASK) >> MSACSR_RM], \ + &env->active_tc.msa_fp_status); \ + \ + set_float_exception_flags( \ + get_float_exception_flags(&env->active_tc.msa_fp_status) \ + & (~float_flag_inexact), \ + &env->active_tc.msa_fp_status); \ + \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + \ + if (get_enabled_exceptions(env, c)) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +void helper_msa_flog2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_LOGB(pwx->w[i], pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_LOGB(pwx->d[i], pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fexupl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + /* Half precision floats come in two formats: standard + IEEE and "ARM" format. The latter gains extra exponent + range by omitting the NaN/Inf encodings. */ + flag ieee = 1; + + MSA_FLOAT_BINOP(pwx->w[i], from_float16, Lh(pws, i), ieee, 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], from_float32, Lw(pws, i), 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_fexupr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + /* Half precision floats come in two formats: standard + IEEE and "ARM" format. The latter gains extra exponent + range by omitting the NaN/Inf encodings. */ + flag ieee = 1; + + MSA_FLOAT_BINOP(pwx->w[i], from_float16, Rh(pws, i), ieee, 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], from_float32, Rw(pws, i), 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_ffql_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP(pwx->w[i], from_q16, Lh(pws, i), 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], from_q32, Lw(pws, i), 64); + } + break; + default: + assert(0); + } + + msa_move_v(pwd, pwx); +} + +void helper_msa_ffqr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP(pwx->w[i], from_q16, Rh(pws, i), 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], from_q32, Rw(pws, i), 64); + } + break; + default: + assert(0); + } + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP0(pwx->w[i], to_int32, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP0(pwx->d[i], to_int64, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP0(pwx->w[i], to_uint32, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP0(pwx->d[i], to_uint64, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define float32_from_int32 int32_to_float32 +#define float32_from_uint32 uint32_to_float32 + +#define float64_from_int64 int64_to_float64 +#define float64_from_uint64 uint64_to_float64 + +void helper_msa_ffint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP(pwx->w[i], from_int32, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], from_int64, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + uint32_t i; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + MSA_FLOAT_UNOP(pwx->w[i], from_uint32, pws->w[i], 32); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + MSA_FLOAT_UNOP(pwx->d[i], from_uint64, pws->d[i], 64); + } + break; + default: + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} diff --git a/target-mips/translate.c b/target-mips/translate.c index acaf5a32bc..73d686e081 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -18098,6 +18098,77 @@ static void gen_msa_2r(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(tdf); } +static void gen_msa_2rf(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_2RF(op) (MASK_MSA_MINOR(op) | (op & (0x1f << 21)) | \ + (op & (0xf << 17))) + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + uint8_t df = (ctx->opcode >> 16) & 0x1; + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + /* adjust df value for floating-point instruction */ + TCGv_i32 tdf = tcg_const_i32(df + 2); + + switch (MASK_MSA_2RF(ctx->opcode)) { + case OPC_FCLASS_df: + gen_helper_msa_fclass_df(cpu_env, tdf, twd, tws); + break; + case OPC_FTRUNC_S_df: + gen_helper_msa_ftrunc_s_df(cpu_env, tdf, twd, tws); + break; + case OPC_FTRUNC_U_df: + gen_helper_msa_ftrunc_u_df(cpu_env, tdf, twd, tws); + break; + case OPC_FSQRT_df: + gen_helper_msa_fsqrt_df(cpu_env, tdf, twd, tws); + break; + case OPC_FRSQRT_df: + gen_helper_msa_frsqrt_df(cpu_env, tdf, twd, tws); + break; + case OPC_FRCP_df: + gen_helper_msa_frcp_df(cpu_env, tdf, twd, tws); + break; + case OPC_FRINT_df: + gen_helper_msa_frint_df(cpu_env, tdf, twd, tws); + break; + case OPC_FLOG2_df: + gen_helper_msa_flog2_df(cpu_env, tdf, twd, tws); + break; + case OPC_FEXUPL_df: + gen_helper_msa_fexupl_df(cpu_env, tdf, twd, tws); + break; + case OPC_FEXUPR_df: + gen_helper_msa_fexupr_df(cpu_env, tdf, twd, tws); + break; + case OPC_FFQL_df: + gen_helper_msa_ffql_df(cpu_env, tdf, twd, tws); + break; + case OPC_FFQR_df: + gen_helper_msa_ffqr_df(cpu_env, tdf, twd, tws); + break; + case OPC_FTINT_S_df: + gen_helper_msa_ftint_s_df(cpu_env, tdf, twd, tws); + break; + case OPC_FTINT_U_df: + gen_helper_msa_ftint_u_df(cpu_env, tdf, twd, tws); + break; + case OPC_FFINT_S_df: + gen_helper_msa_ffint_s_df(cpu_env, tdf, twd, tws); + break; + case OPC_FFINT_U_df: + gen_helper_msa_ffint_u_df(cpu_env, tdf, twd, tws); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); + tcg_temp_free_i32(tdf); +} + static void gen_msa_vec_v(CPUMIPSState *env, DisasContext *ctx) { #define MASK_MSA_VEC(op) (MASK_MSA_MINOR(op) | (op & (0x1f << 21))) @@ -18156,6 +18227,9 @@ static void gen_msa_vec(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_2R: gen_msa_2r(env, ctx); break; + case OPC_MSA_2RF: + gen_msa_2rf(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From f7685877f596cfe7e873be5479f975ae985edba9 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:51 +0000 Subject: [PATCH 32/34] target-mips: add MSA MI10 format instructions add MSA MI10 format instructions update LSA and DLSA for MSA add 16, 64 bit load and store Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- target-mips/helper.h | 3 ++ target-mips/op_helper.c | 84 +++++++++++++++++++++++++++++++++++++++-- target-mips/translate.c | 49 +++++++++++++++++++++++- 3 files changed, 131 insertions(+), 5 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index cb8b40efbf..9d0275891c 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -929,3 +929,6 @@ DEF_HELPER_4(msa_ftint_s_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ftint_u_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ffint_s_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ffint_u_df, void, env, i32, i32, i32) + +DEF_HELPER_5(msa_ld_df, void, env, i32, i32, i32, s32) +DEF_HELPER_5(msa_st_df, void, env, i32, i32, i32, s32) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 2a977210de..638c9f9dfb 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -90,10 +90,10 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ } \ } #endif +HELPER_LD(lbu, ldub, uint8_t) +HELPER_LD(lhu, lduw, uint16_t) HELPER_LD(lw, ldl, int32_t) -#ifdef TARGET_MIPS64 HELPER_LD(ld, ldq, int64_t) -#endif #undef HELPER_LD #if defined(CONFIG_USER_ONLY) @@ -118,10 +118,9 @@ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ } #endif HELPER_ST(sb, stb, uint8_t) +HELPER_ST(sh, stw, uint16_t) HELPER_ST(sw, stl, uint32_t) -#ifdef TARGET_MIPS64 HELPER_ST(sd, stq, uint64_t) -#endif #undef HELPER_ST target_ulong helper_clo (target_ulong arg1) @@ -3626,3 +3625,80 @@ FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))) FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))) + +/* MSA */ +/* Data format min and max values */ +#define DF_BITS(df) (1 << ((df) + 3)) + +/* Element-by-element access macros */ +#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df)) + +void helper_msa_ld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs, + int32_t s10) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + target_ulong addr = env->active_tc.gpr[rs] + (s10 << df); + int i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + pwd->b[i] = do_lbu(env, addr + (i << DF_BYTE), + env->hflags & MIPS_HFLAG_KSU); + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + pwd->h[i] = do_lhu(env, addr + (i << DF_HALF), + env->hflags & MIPS_HFLAG_KSU); + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + pwd->w[i] = do_lw(env, addr + (i << DF_WORD), + env->hflags & MIPS_HFLAG_KSU); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + pwd->d[i] = do_ld(env, addr + (i << DF_DOUBLE), + env->hflags & MIPS_HFLAG_KSU); + } + break; + } +} + +void helper_msa_st_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs, + int32_t s10) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + target_ulong addr = env->active_tc.gpr[rs] + (s10 << df); + int i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + do_sb(env, addr + (i << DF_BYTE), pwd->b[i], + env->hflags & MIPS_HFLAG_KSU); + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + do_sh(env, addr + (i << DF_HALF), pwd->h[i], + env->hflags & MIPS_HFLAG_KSU); + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + do_sw(env, addr + (i << DF_WORD), pwd->w[i], + env->hflags & MIPS_HFLAG_KSU); + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + do_sd(env, addr + (i << DF_DOUBLE), pwd->d[i], + env->hflags & MIPS_HFLAG_KSU); + } + break; + } +} diff --git a/target-mips/translate.c b/target-mips/translate.c index 73d686e081..2117ce82e0 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -16319,7 +16319,8 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) gen_trap(ctx, op1, rs, rt, -1); break; case OPC_LSA: /* OPC_PMON */ - if (ctx->insn_flags & ISA_MIPS32R6) { + if ((ctx->insn_flags & ISA_MIPS32R6) || + (env->CP0_Config3 & (1 << CP0C3_MSAP))) { decode_opc_special_r6(env, ctx); } else { /* Pmon entry point, also R4010 selsl */ @@ -16417,6 +16418,12 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) break; } break; + case OPC_DLSA: + if ((ctx->insn_flags & ISA_MIPS32R6) || + (env->CP0_Config3 & (1 << CP0C3_MSAP))) { + decode_opc_special_r6(env, ctx); + } + break; #endif default: if (ctx->insn_flags & ISA_MIPS32R6) { @@ -18279,6 +18286,46 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_VEC: gen_msa_vec(env, ctx); break; + case OPC_LD_B: + case OPC_LD_H: + case OPC_LD_W: + case OPC_LD_D: + case OPC_ST_B: + case OPC_ST_H: + case OPC_ST_W: + case OPC_ST_D: + { + int32_t s10 = sextract32(ctx->opcode, 16, 10); + uint8_t rs = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + uint8_t df = (ctx->opcode >> 0) & 0x3; + + TCGv_i32 tdf = tcg_const_i32(df); + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 trs = tcg_const_i32(rs); + TCGv_i32 ts10 = tcg_const_i32(s10); + + switch (MASK_MSA_MINOR(opcode)) { + case OPC_LD_B: + case OPC_LD_H: + case OPC_LD_W: + case OPC_LD_D: + gen_helper_msa_ld_df(cpu_env, tdf, twd, trs, ts10); + break; + case OPC_ST_B: + case OPC_ST_H: + case OPC_ST_W: + case OPC_ST_D: + gen_helper_msa_st_df(cpu_env, tdf, twd, trs, ts10); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tdf); + tcg_temp_free_i32(trs); + tcg_temp_free_i32(ts10); + } + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI); From ed8a933f977e39fc696d92f0b9f93100319a8668 Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:52 +0000 Subject: [PATCH 33/34] disas/mips.c: disassemble MSA instructions disassemble MIPS SIMD Architecture instructions Signed-off-by: Yongbok Kim Signed-off-by: Leon Alrae --- disas/mips.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 714 insertions(+), 2 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 4974bc0da2..2614c52a4b 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -220,6 +220,28 @@ see . */ #define OP_SH_MTACC_D 13 #define OP_MASK_MTACC_D 0x3 +/* MSA */ +#define OP_MASK_1BIT 0x1 +#define OP_SH_1BIT 16 +#define OP_MASK_2BIT 0x3 +#define OP_SH_2BIT 16 +#define OP_MASK_3BIT 0x7 +#define OP_SH_3BIT 16 +#define OP_MASK_4BIT 0xf +#define OP_SH_4BIT 16 +#define OP_MASK_5BIT 0x1f +#define OP_SH_5BIT 16 +#define OP_MASK_10BIT 0x3ff +#define OP_SH_10BIT 11 +#define OP_MASK_MSACR11 0x1f +#define OP_SH_MSACR11 11 +#define OP_MASK_MSACR6 0x1f +#define OP_SH_MSACR6 6 +#define OP_MASK_GPR 0x1f +#define OP_SH_GPR 6 +#define OP_MASK_1_TO_4 0x3 +#define OP_SH_1_TO_4 6 + #define OP_OP_COP0 0x10 #define OP_OP_COP1 0x11 #define OP_OP_COP2 0x12 @@ -510,6 +532,9 @@ struct mips_opcode /* Instruction writes MDMX accumulator. */ #define INSN2_WRITE_MDMX_ACC 0x00000004 +/* Reads the general purpose register in OP_*_RD. */ +#define INSN2_READ_GPR_D 0x00000200 + /* Instruction is actually a macro. It should be ignored by the disassembler, and requires special treatment by the assembler. */ #define INSN_MACRO 0xffffffff @@ -567,7 +592,12 @@ struct mips_opcode #define INSN_5500 0x02000000 /* MDMX ASE */ -#define INSN_MDMX 0x04000000 +#define INSN_MDMX 0x00000000 /* Deprecated */ + +/* MIPS MSA Extension */ +#define INSN_MSA 0x04000000 +#define INSN_MSA64 0x04000000 + /* MT ASE */ #define INSN_MT 0x08000000 /* SmartMIPS ASE */ @@ -1204,6 +1234,17 @@ extern const int bfd_mips16_num_opcodes; /* MIPS MT ASE support. */ #define MT32 INSN_MT +/* MSA */ +#define MSA INSN_MSA +#define MSA64 INSN_MSA64 +#define WR_VD INSN_WRITE_FPR_D /* Reuse INSN_WRITE_FPR_D */ +#define RD_VD WR_VD /* Reuse WR_VD */ +#define RD_VT INSN_READ_FPR_T /* Reuse INSN_READ_FPR_T */ +#define RD_VS INSN_READ_FPR_S /* Reuse INSN_READ_FPR_S */ +#define RD_d INSN2_READ_GPR_D /* Reuse INSN2_READ_GPR_D */ + +#define RD_rd6 0 + /* The order of overloaded instructions matters. Label arguments and register arguments look the same. Instructions that can have either for arguments must apear in the correct order in this table for the @@ -1363,6 +1404,541 @@ const struct mips_opcode mips_builtin_opcodes[] = {"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, {"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, {"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, + +/* MSA */ +{"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sll.h", "+d,+e,+f", 0x7820000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sll.w", "+d,+e,+f", 0x7840000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sll.d", "+d,+e,+f", 0x7860000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"slli.b", "+d,+e,+7", 0x78700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"slli.h", "+d,+e,+8", 0x78600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"slli.w", "+d,+e,+9", 0x78400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"slli.d", "+d,+e,'", 0x78000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"sra.b", "+d,+e,+f", 0x7880000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sra.h", "+d,+e,+f", 0x78a0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sra.w", "+d,+e,+f", 0x78c0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sra.d", "+d,+e,+f", 0x78e0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srai.b", "+d,+e,+7", 0x78f00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srai.h", "+d,+e,+8", 0x78e00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srai.w", "+d,+e,+9", 0x78c00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srai.d", "+d,+e,'", 0x78800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"srl.b", "+d,+e,+f", 0x7900000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srl.h", "+d,+e,+f", 0x7920000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srl.w", "+d,+e,+f", 0x7940000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srl.d", "+d,+e,+f", 0x7960000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srli.b", "+d,+e,+7", 0x79700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srli.h", "+d,+e,+8", 0x79600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srli.w", "+d,+e,+9", 0x79400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srli.d", "+d,+e,'", 0x79000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"bclr.b", "+d,+e,+f", 0x7980000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclr.h", "+d,+e,+f", 0x79a0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclr.w", "+d,+e,+f", 0x79c0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclr.d", "+d,+e,+f", 0x79e0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclri.b", "+d,+e,+7", 0x79f00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"bclri.h", "+d,+e,+8", 0x79e00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"bclri.w", "+d,+e,+9", 0x79c00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"bclri.d", "+d,+e,'", 0x79800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"bset.b", "+d,+e,+f", 0x7a00000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bset.h", "+d,+e,+f", 0x7a20000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bset.w", "+d,+e,+f", 0x7a40000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bset.d", "+d,+e,+f", 0x7a60000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bseti.b", "+d,+e,+7", 0x7a700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"bseti.h", "+d,+e,+8", 0x7a600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"bseti.w", "+d,+e,+9", 0x7a400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"bseti.d", "+d,+e,'", 0x7a000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"bneg.b", "+d,+e,+f", 0x7a80000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bneg.h", "+d,+e,+f", 0x7aa0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bneg.w", "+d,+e,+f", 0x7ac0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bneg.d", "+d,+e,+f", 0x7ae0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bnegi.b", "+d,+e,+7", 0x7af00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"bnegi.h", "+d,+e,+8", 0x7ae00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"bnegi.w", "+d,+e,+9", 0x7ac00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"bnegi.d", "+d,+e,'", 0x7a800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"binsl.b", "+d,+e,+f", 0x7b00000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsl.h", "+d,+e,+f", 0x7b20000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsl.w", "+d,+e,+f", 0x7b40000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsl.d", "+d,+e,+f", 0x7b60000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsli.b", "+d,+e,+7", 0x7b700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"binsli.h", "+d,+e,+8", 0x7b600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"binsli.w", "+d,+e,+9", 0x7b400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"binsli.d", "+d,+e,'", 0x7b000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"binsr.b", "+d,+e,+f", 0x7b80000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsr.h", "+d,+e,+f", 0x7ba0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsr.w", "+d,+e,+f", 0x7bc0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsr.d", "+d,+e,+f", 0x7be0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsri.b", "+d,+e,+7", 0x7bf00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"binsri.h", "+d,+e,+8", 0x7be00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"binsri.w", "+d,+e,+9", 0x7bc00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"binsri.d", "+d,+e,'", 0x7b800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"addv.b", "+d,+e,+f", 0x7800000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addv.h", "+d,+e,+f", 0x7820000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addv.w", "+d,+e,+f", 0x7840000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addv.d", "+d,+e,+f", 0x7860000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addvi.b", "+d,+e,k", 0x78000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"addvi.h", "+d,+e,k", 0x78200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"addvi.w", "+d,+e,k", 0x78400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"addvi.d", "+d,+e,k", 0x78600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subv.b", "+d,+e,+f", 0x7880000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subv.h", "+d,+e,+f", 0x78a0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subv.w", "+d,+e,+f", 0x78c0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subv.d", "+d,+e,+f", 0x78e0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subvi.b", "+d,+e,k", 0x78800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subvi.h", "+d,+e,k", 0x78a00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subvi.w", "+d,+e,k", 0x78c00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subvi.d", "+d,+e,k", 0x78e00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"max_s.b", "+d,+e,+f", 0x7900000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_s.h", "+d,+e,+f", 0x7920000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_s.w", "+d,+e,+f", 0x7940000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_s.d", "+d,+e,+f", 0x7960000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maxi_s.b", "+d,+e,+5", 0x79000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_s.h", "+d,+e,+5", 0x79200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_s.w", "+d,+e,+5", 0x79400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_s.d", "+d,+e,+5", 0x79600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"max_u.b", "+d,+e,+f", 0x7980000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_u.h", "+d,+e,+f", 0x79a0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_u.w", "+d,+e,+f", 0x79c0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_u.d", "+d,+e,+f", 0x79e0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maxi_u.b", "+d,+e,k", 0x79800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_u.h", "+d,+e,k", 0x79a00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_u.w", "+d,+e,k", 0x79c00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_u.d", "+d,+e,k", 0x79e00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"min_s.b", "+d,+e,+f", 0x7a00000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_s.h", "+d,+e,+f", 0x7a20000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_s.w", "+d,+e,+f", 0x7a40000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_s.d", "+d,+e,+f", 0x7a60000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mini_s.b", "+d,+e,+5", 0x7a000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_s.h", "+d,+e,+5", 0x7a200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_s.w", "+d,+e,+5", 0x7a400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_s.d", "+d,+e,+5", 0x7a600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"min_u.b", "+d,+e,+f", 0x7a80000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_u.h", "+d,+e,+f", 0x7aa0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_u.w", "+d,+e,+f", 0x7ac0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_u.d", "+d,+e,+f", 0x7ae0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mini_u.b", "+d,+e,k", 0x7a800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_u.h", "+d,+e,k", 0x7aa00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_u.w", "+d,+e,k", 0x7ac00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_u.d", "+d,+e,k", 0x7ae00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"max_a.b", "+d,+e,+f", 0x7b00000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_a.h", "+d,+e,+f", 0x7b20000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_a.w", "+d,+e,+f", 0x7b40000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_a.d", "+d,+e,+f", 0x7b60000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.b", "+d,+e,+f", 0x7b80000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.h", "+d,+e,+f", 0x7ba0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.w", "+d,+e,+f", 0x7bc0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.d", "+d,+e,+f", 0x7be0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.b", "+d,+e,+f", 0x7800000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.h", "+d,+e,+f", 0x7820000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.w", "+d,+e,+f", 0x7840000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.d", "+d,+e,+f", 0x7860000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceqi.b", "+d,+e,+5", 0x78000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ceqi.h", "+d,+e,+5", 0x78200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ceqi.w", "+d,+e,+5", 0x78400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ceqi.d", "+d,+e,+5", 0x78600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clt_s.b", "+d,+e,+f", 0x7900000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_s.h", "+d,+e,+f", 0x7920000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_s.w", "+d,+e,+f", 0x7940000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_s.d", "+d,+e,+f", 0x7960000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clti_s.b", "+d,+e,+5", 0x79000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_s.h", "+d,+e,+5", 0x79200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_s.w", "+d,+e,+5", 0x79400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_s.d", "+d,+e,+5", 0x79600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clt_u.b", "+d,+e,+f", 0x7980000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_u.h", "+d,+e,+f", 0x79a0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_u.w", "+d,+e,+f", 0x79c0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_u.d", "+d,+e,+f", 0x79e0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clti_u.b", "+d,+e,k", 0x79800007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_u.h", "+d,+e,k", 0x79a00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_u.w", "+d,+e,k", 0x79c00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_u.d", "+d,+e,k", 0x79e00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"cle_s.b", "+d,+e,+f", 0x7a00000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_s.h", "+d,+e,+f", 0x7a20000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_s.w", "+d,+e,+f", 0x7a40000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_s.d", "+d,+e,+f", 0x7a60000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clei_s.b", "+d,+e,+5", 0x7a000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_s.h", "+d,+e,+5", 0x7a200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_s.w", "+d,+e,+5", 0x7a400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_s.d", "+d,+e,+5", 0x7a600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"cle_u.b", "+d,+e,+f", 0x7a80000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_u.h", "+d,+e,+f", 0x7aa0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_u.w", "+d,+e,+f", 0x7ac0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_u.d", "+d,+e,+f", 0x7ae0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clei_u.b", "+d,+e,k", 0x7a800007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_u.h", "+d,+e,k", 0x7aa00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_u.w", "+d,+e,k", 0x7ac00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_u.d", "+d,+e,k", 0x7ae00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ld.b", "+d,+^(d)", 0x78000020, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"ld.h", "+d,+#(d)", 0x78000021, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"ld.w", "+d,+$(d)", 0x78000022, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"ld.d", "+d,+%(d)", 0x78000023, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"st.b", "+d,+^(d)", 0x78000024, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"st.h", "+d,+#(d)", 0x78000025, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"st.w", "+d,+$(d)", 0x78000026, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"st.d", "+d,+%(d)", 0x78000027, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"sat_s.b", "+d,+e,+7", 0x7870000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"sat_s.h", "+d,+e,+8", 0x7860000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_s.w", "+d,+e,+9", 0x7840000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_s.d", "+d,+e,'", 0x7800000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.b", "+d,+e,+7", 0x78f0000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.h", "+d,+e,+8", 0x78e0000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.w", "+d,+e,+9", 0x78c0000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.d", "+d,+e,'", 0x7880000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"add_a.b", "+d,+e,+f", 0x78000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"add_a.h", "+d,+e,+f", 0x78200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"add_a.w", "+d,+e,+f", 0x78400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"add_a.d", "+d,+e,+f", 0x78600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.b", "+d,+e,+f", 0x78800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.h", "+d,+e,+f", 0x78a00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.w", "+d,+e,+f", 0x78c00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.d", "+d,+e,+f", 0x78e00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.b", "+d,+e,+f", 0x79000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.h", "+d,+e,+f", 0x79200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.w", "+d,+e,+f", 0x79400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.d", "+d,+e,+f", 0x79600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.b", "+d,+e,+f", 0x79800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.h", "+d,+e,+f", 0x79a00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.w", "+d,+e,+f", 0x79c00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.d", "+d,+e,+f", 0x79e00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.b", "+d,+e,+f", 0x7a000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.h", "+d,+e,+f", 0x7a200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.w", "+d,+e,+f", 0x7a400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.d", "+d,+e,+f", 0x7a600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.b", "+d,+e,+f", 0x7a800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.h", "+d,+e,+f", 0x7aa00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.w", "+d,+e,+f", 0x7ac00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.d", "+d,+e,+f", 0x7ae00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.b", "+d,+e,+f", 0x7b000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.h", "+d,+e,+f", 0x7b200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.w", "+d,+e,+f", 0x7b400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.d", "+d,+e,+f", 0x7b600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.b", "+d,+e,+f", 0x7b800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.h", "+d,+e,+f", 0x7ba00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.w", "+d,+e,+f", 0x7bc00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.d", "+d,+e,+f", 0x7be00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.b", "+d,+e,+f", 0x78000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.h", "+d,+e,+f", 0x78200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.w", "+d,+e,+f", 0x78400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.d", "+d,+e,+f", 0x78600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.b", "+d,+e,+f", 0x78800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.h", "+d,+e,+f", 0x78a00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.w", "+d,+e,+f", 0x78c00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.d", "+d,+e,+f", 0x78e00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.b", "+d,+e,+f", 0x79000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.h", "+d,+e,+f", 0x79200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.w", "+d,+e,+f", 0x79400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.d", "+d,+e,+f", 0x79600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.b", "+d,+e,+f", 0x79800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.h", "+d,+e,+f", 0x79a00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.w", "+d,+e,+f", 0x79c00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.d", "+d,+e,+f", 0x79e00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.b", "+d,+e,+f", 0x7a000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.h", "+d,+e,+f", 0x7a200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.w", "+d,+e,+f", 0x7a400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.d", "+d,+e,+f", 0x7a600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.b", "+d,+e,+f", 0x7a800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.h", "+d,+e,+f", 0x7aa00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.w", "+d,+e,+f", 0x7ac00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.d", "+d,+e,+f", 0x7ae00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.b", "+d,+e,+f", 0x78000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.h", "+d,+e,+f", 0x78200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.w", "+d,+e,+f", 0x78400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.d", "+d,+e,+f", 0x78600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.b", "+d,+e,+f", 0x78800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.h", "+d,+e,+f", 0x78a00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.w", "+d,+e,+f", 0x78c00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.d", "+d,+e,+f", 0x78e00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.b", "+d,+e,+f", 0x79000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.h", "+d,+e,+f", 0x79200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.w", "+d,+e,+f", 0x79400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.d", "+d,+e,+f", 0x79600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.b", "+d,+e,+f", 0x7a000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.h", "+d,+e,+f", 0x7a200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.w", "+d,+e,+f", 0x7a400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.d", "+d,+e,+f", 0x7a600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.b", "+d,+e,+f", 0x7a800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.h", "+d,+e,+f", 0x7aa00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.w", "+d,+e,+f", 0x7ac00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.d", "+d,+e,+f", 0x7ae00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.b", "+d,+e,+f", 0x7b000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.h", "+d,+e,+f", 0x7b200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.w", "+d,+e,+f", 0x7b400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.d", "+d,+e,+f", 0x7b600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.b", "+d,+e,+f", 0x7b800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.h", "+d,+e,+f", 0x7ba00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.w", "+d,+e,+f", 0x7bc00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.d", "+d,+e,+f", 0x7be00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_s.h", "+d,+e,+f", 0x78200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_s.w", "+d,+e,+f", 0x78400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_s.d", "+d,+e,+f", 0x78600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_u.h", "+d,+e,+f", 0x78a00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_u.w", "+d,+e,+f", 0x78c00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_u.d", "+d,+e,+f", 0x78e00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_s.h", "+d,+e,+f", 0x79200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_s.w", "+d,+e,+f", 0x79400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_s.d", "+d,+e,+f", 0x79600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_u.h", "+d,+e,+f", 0x79a00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_u.w", "+d,+e,+f", 0x79c00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_u.d", "+d,+e,+f", 0x79e00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_s.h", "+d,+e,+f", 0x7a200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_s.w", "+d,+e,+f", 0x7a400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_s.d", "+d,+e,+f", 0x7a600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_u.h", "+d,+e,+f", 0x7aa00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_u.w", "+d,+e,+f", 0x7ac00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_u.d", "+d,+e,+f", 0x7ae00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sld.b", "+d,+e[t]", 0x78000014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sld.h", "+d,+e[t]", 0x78200014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sld.w", "+d,+e[t]", 0x78400014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sld.d", "+d,+e[t]", 0x78600014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sldi.b", "+d,+e[+9]", 0x78000019, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"sldi.h", "+d,+e[+8]", 0x78200019, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"sldi.w", "+d,+e[+7]", 0x78300019, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"sldi.d", "+d,+e[+6]", 0x78380019, 0xfffc003f, WR_VD|RD_VS, 0, MSA}, +{"splat.b", "+d,+e[t]", 0x78800014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splat.h", "+d,+e[t]", 0x78a00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splat.w", "+d,+e[t]", 0x78c00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splat.d", "+d,+e[t]", 0x78e00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splati.b", "+d,+e[+9]", 0x78400019, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"splati.h", "+d,+e[+8]", 0x78600019, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"splati.w", "+d,+e[+7]", 0x78700019, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"splati.d", "+d,+e[+6]", 0x78780019, 0xfffc003f, WR_VD|RD_VS, 0, MSA}, +{"pckev.b", "+d,+e,+f", 0x79000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckev.h", "+d,+e,+f", 0x79200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckev.w", "+d,+e,+f", 0x79400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckev.d", "+d,+e,+f", 0x79600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.b", "+d,+e,+f", 0x79800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.h", "+d,+e,+f", 0x79a00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.w", "+d,+e,+f", 0x79c00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.d", "+d,+e,+f", 0x79e00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.b", "+d,+e,+f", 0x7a000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.h", "+d,+e,+f", 0x7a200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.w", "+d,+e,+f", 0x7a400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.d", "+d,+e,+f", 0x7a600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.b", "+d,+e,+f", 0x7a800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.h", "+d,+e,+f", 0x7aa00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.w", "+d,+e,+f", 0x7ac00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.d", "+d,+e,+f", 0x7ae00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.b", "+d,+e,+f", 0x7b000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.h", "+d,+e,+f", 0x7b200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.w", "+d,+e,+f", 0x7b400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.d", "+d,+e,+f", 0x7b600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.b", "+d,+e,+f", 0x7b800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.h", "+d,+e,+f", 0x7ba00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.w", "+d,+e,+f", 0x7bc00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.d", "+d,+e,+f", 0x7be00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.b", "+d,+e,+f", 0x78000015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.h", "+d,+e,+f", 0x78200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.w", "+d,+e,+f", 0x78400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.d", "+d,+e,+f", 0x78600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.b", "+d,+e,+f", 0x78800015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.h", "+d,+e,+f", 0x78a00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.w", "+d,+e,+f", 0x78c00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.d", "+d,+e,+f", 0x78e00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srari.b", "+d,+e,+7", 0x7970000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srari.h", "+d,+e,+8", 0x7960000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srari.w", "+d,+e,+9", 0x7940000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srari.d", "+d,+e,'", 0x7900000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"srlr.b", "+d,+e,+f", 0x79000015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlr.h", "+d,+e,+f", 0x79200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlr.w", "+d,+e,+f", 0x79400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlr.d", "+d,+e,+f", 0x79600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlri.b", "+d,+e,+7", 0x79f0000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srlri.h", "+d,+e,+8", 0x79e0000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srlri.w", "+d,+e,+9", 0x79c0000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srlri.d", "+d,+e,'", 0x7980000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"hadd_s.h", "+d,+e,+f", 0x7a200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_s.w", "+d,+e,+f", 0x7a400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_s.d", "+d,+e,+f", 0x7a600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_u.h", "+d,+e,+f", 0x7aa00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_u.w", "+d,+e,+f", 0x7ac00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_u.d", "+d,+e,+f", 0x7ae00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_s.h", "+d,+e,+f", 0x7b200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_s.w", "+d,+e,+f", 0x7b400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_s.d", "+d,+e,+f", 0x7b600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_u.h", "+d,+e,+f", 0x7ba00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_u.w", "+d,+e,+f", 0x7bc00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_u.d", "+d,+e,+f", 0x7be00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"and.v", "+d,+e,+f", 0x7800001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"andi.b", "+d,+e,5", 0x78000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"or.v", "+d,+e,+f", 0x7820001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ori.b", "+d,+e,5", 0x79000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"nor.v", "+d,+e,+f", 0x7840001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"nori.b", "+d,+e,5", 0x7a000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"xor.v", "+d,+e,+f", 0x7860001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"xori.b", "+d,+e,5", 0x7b000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bmnz.v", "+d,+e,+f", 0x7880001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bmnzi.b", "+d,+e,5", 0x78000001, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bmz.v", "+d,+e,+f", 0x78a0001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bmzi.b", "+d,+e,5", 0x79000001, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bsel.v", "+d,+e,+f", 0x78c0001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bseli.b", "+d,+e,5", 0x7a000001, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"shf.b", "+d,+e,5", 0x78000002, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"shf.h", "+d,+e,5", 0x79000002, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"shf.w", "+d,+e,5", 0x7a000002, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bnz.v", "+f,p", 0x45e00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.v", "+f,p", 0x45600000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"fill.b", "+d,d", 0x7b00001e, 0xffff003f, WR_VD, RD_d, MSA}, +{"fill.h", "+d,d", 0x7b01001e, 0xffff003f, WR_VD, RD_d, MSA}, +{"fill.w", "+d,d", 0x7b02001e, 0xffff003f, WR_VD, RD_d, MSA}, +{"fill.d", "+d,d", 0x7b03001e, 0xffff003f, WR_VD, RD_d, MSA64}, +{"pcnt.b", "+d,+e", 0x7b04001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"pcnt.h", "+d,+e", 0x7b05001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"pcnt.w", "+d,+e", 0x7b06001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"pcnt.d", "+d,+e", 0x7b07001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.b", "+d,+e", 0x7b08001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.h", "+d,+e", 0x7b09001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.w", "+d,+e", 0x7b0a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.d", "+d,+e", 0x7b0b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.b", "+d,+e", 0x7b0c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.h", "+d,+e", 0x7b0d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.w", "+d,+e", 0x7b0e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.d", "+d,+e", 0x7b0f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"copy_s.b", "+i,+e[+9]", 0x78800019, 0xffe0003f, RD_VS, RD_rd6, MSA}, +{"copy_s.h", "+i,+e[+8]", 0x78a00019, 0xfff0003f, RD_VS, RD_rd6, MSA}, +{"copy_s.w", "+i,+e[+7]", 0x78b00019, 0xfff8003f, RD_VS, RD_rd6, MSA}, +{"copy_s.d", "+i,+e[+6]", 0x78b80019, 0xfffc003f, RD_VS, RD_rd6, MSA64}, +{"copy_u.b", "+i,+e[+9]", 0x78c00019, 0xffe0003f, RD_VS, RD_rd6, MSA}, +{"copy_u.h", "+i,+e[+8]", 0x78e00019, 0xfff0003f, RD_VS, RD_rd6, MSA}, +{"copy_u.w", "+i,+e[+7]", 0x78f00019, 0xfff8003f, RD_VS, RD_rd6, MSA}, +{"copy_u.d", "+i,+e[+6]", 0x78f80019, 0xfffc003f, RD_VS, RD_rd6, MSA64}, +{"insert.b", "+d[+9],d", 0x79000019, 0xffe0003f, WR_VD|RD_VD, RD_d, MSA}, +{"insert.h", "+d[+8],d", 0x79200019, 0xfff0003f, WR_VD|RD_VD, RD_d, MSA}, +{"insert.w", "+d[+7],d", 0x79300019, 0xfff8003f, WR_VD|RD_VD, RD_d, MSA}, +{"insert.d", "+d[+6],d", 0x79380019, 0xfffc003f, WR_VD|RD_VD, RD_d, MSA64}, +{"insve.b", "+d[+9],+e[+~]", 0x79400019, 0xffe0003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"insve.h", "+d[+8],+e[+~]", 0x79600019, 0xfff0003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"insve.w", "+d[+7],+e[+~]", 0x79700019, 0xfff8003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"insve.d", "+d[+6],+e[+~]", 0x79780019, 0xfffc003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"bnz.b", "+f,p", 0x47800000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bnz.h", "+f,p", 0x47a00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bnz.w", "+f,p", 0x47c00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bnz.d", "+f,p", 0x47e00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.b", "+f,p", 0x47000000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.h", "+f,p", 0x47200000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.w", "+f,p", 0x47400000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.d", "+f,p", 0x47600000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"ldi.b", "+d,+0", 0x7b000007, 0xffe0003f, WR_VD, 0, MSA}, +{"ldi.h", "+d,+0", 0x7b200007, 0xffe0003f, WR_VD, 0, MSA}, +{"ldi.w", "+d,+0", 0x7b400007, 0xffe0003f, WR_VD, 0, MSA}, +{"ldi.d", "+d,+0", 0x7b600007, 0xffe0003f, WR_VD, 0, MSA}, +{"fcaf.w", "+d,+e,+f", 0x7800001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcaf.d", "+d,+e,+f", 0x7820001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcun.w", "+d,+e,+f", 0x7840001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcun.d", "+d,+e,+f", 0x7860001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fceq.w", "+d,+e,+f", 0x7880001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fceq.d", "+d,+e,+f", 0x78a0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcueq.w", "+d,+e,+f", 0x78c0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcueq.d", "+d,+e,+f", 0x78e0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fclt.w", "+d,+e,+f", 0x7900001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fclt.d", "+d,+e,+f", 0x7920001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcult.w", "+d,+e,+f", 0x7940001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcult.d", "+d,+e,+f", 0x7960001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcle.w", "+d,+e,+f", 0x7980001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcle.d", "+d,+e,+f", 0x79a0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcule.w", "+d,+e,+f", 0x79c0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcule.d", "+d,+e,+f", 0x79e0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsaf.w", "+d,+e,+f", 0x7a00001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsaf.d", "+d,+e,+f", 0x7a20001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsun.w", "+d,+e,+f", 0x7a40001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsun.d", "+d,+e,+f", 0x7a60001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fseq.w", "+d,+e,+f", 0x7a80001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fseq.d", "+d,+e,+f", 0x7aa0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsueq.w", "+d,+e,+f", 0x7ac0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsueq.d", "+d,+e,+f", 0x7ae0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fslt.w", "+d,+e,+f", 0x7b00001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fslt.d", "+d,+e,+f", 0x7b20001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsult.w", "+d,+e,+f", 0x7b40001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsult.d", "+d,+e,+f", 0x7b60001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsle.w", "+d,+e,+f", 0x7b80001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsle.d", "+d,+e,+f", 0x7ba0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsule.w", "+d,+e,+f", 0x7bc0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsule.d", "+d,+e,+f", 0x7be0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fadd.w", "+d,+e,+f", 0x7800001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fadd.d", "+d,+e,+f", 0x7820001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsub.w", "+d,+e,+f", 0x7840001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsub.d", "+d,+e,+f", 0x7860001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmul.w", "+d,+e,+f", 0x7880001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmul.d", "+d,+e,+f", 0x78a0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fdiv.w", "+d,+e,+f", 0x78c0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fdiv.d", "+d,+e,+f", 0x78e0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmadd.w", "+d,+e,+f", 0x7900001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmadd.d", "+d,+e,+f", 0x7920001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmsub.w", "+d,+e,+f", 0x7940001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmsub.d", "+d,+e,+f", 0x7960001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexp2.w", "+d,+e,+f", 0x79c0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexp2.d", "+d,+e,+f", 0x79e0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexdo.h", "+d,+e,+f", 0x7a00001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexdo.w", "+d,+e,+f", 0x7a20001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ftq.h", "+d,+e,+f", 0x7a80001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ftq.w", "+d,+e,+f", 0x7aa0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin.w", "+d,+e,+f", 0x7b00001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin.d", "+d,+e,+f", 0x7b20001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin_a.w", "+d,+e,+f", 0x7b40001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin_a.d", "+d,+e,+f", 0x7b60001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax.w", "+d,+e,+f", 0x7b80001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax.d", "+d,+e,+f", 0x7ba0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax_a.w", "+d,+e,+f", 0x7bc0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax_a.d", "+d,+e,+f", 0x7be0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcor.w", "+d,+e,+f", 0x7840001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcor.d", "+d,+e,+f", 0x7860001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcune.w", "+d,+e,+f", 0x7880001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcune.d", "+d,+e,+f", 0x78a0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcne.w", "+d,+e,+f", 0x78c0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcne.d", "+d,+e,+f", 0x78e0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mul_q.h", "+d,+e,+f", 0x7900001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mul_q.w", "+d,+e,+f", 0x7920001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"madd_q.h", "+d,+e,+f", 0x7940001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"madd_q.w", "+d,+e,+f", 0x7960001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msub_q.h", "+d,+e,+f", 0x7980001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msub_q.w", "+d,+e,+f", 0x79a0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsor.w", "+d,+e,+f", 0x7a40001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsor.d", "+d,+e,+f", 0x7a60001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsune.w", "+d,+e,+f", 0x7a80001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsune.d", "+d,+e,+f", 0x7aa0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsne.w", "+d,+e,+f", 0x7ac0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsne.d", "+d,+e,+f", 0x7ae0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulr_q.h", "+d,+e,+f", 0x7b00001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulr_q.w", "+d,+e,+f", 0x7b20001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddr_q.h", "+d,+e,+f", 0x7b40001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddr_q.w", "+d,+e,+f", 0x7b60001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubr_q.h", "+d,+e,+f", 0x7b80001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubr_q.w", "+d,+e,+f", 0x7ba0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fclass.w", "+d,+e", 0x7b20001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fclass.d", "+d,+e", 0x7b21001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fsqrt.w", "+d,+e", 0x7b26001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fsqrt.d", "+d,+e", 0x7b27001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frsqrt.w", "+d,+e", 0x7b28001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frsqrt.d", "+d,+e", 0x7b29001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frcp.w", "+d,+e", 0x7b2a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frcp.d", "+d,+e", 0x7b2b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frint.w", "+d,+e", 0x7b2c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frint.d", "+d,+e", 0x7b2d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"flog2.w", "+d,+e", 0x7b2e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"flog2.d", "+d,+e", 0x7b2f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupl.w", "+d,+e", 0x7b30001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupl.d", "+d,+e", 0x7b31001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupr.w", "+d,+e", 0x7b32001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupr.d", "+d,+e", 0x7b33001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffql.w", "+d,+e", 0x7b34001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffql.d", "+d,+e", 0x7b35001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffqr.w", "+d,+e", 0x7b36001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffqr.d", "+d,+e", 0x7b37001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_s.w", "+d,+e", 0x7b38001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_s.d", "+d,+e", 0x7b39001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_u.w", "+d,+e", 0x7b3a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_u.d", "+d,+e", 0x7b3b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_s.w", "+d,+e", 0x7b3c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_s.d", "+d,+e", 0x7b3d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_u.w", "+d,+e", 0x7b3e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_u.d", "+d,+e", 0x7b3f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_s.w", "+d,+e", 0x7b40001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_s.d", "+d,+e", 0x7b41001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_u.w", "+d,+e", 0x7b42001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_u.d", "+d,+e", 0x7b43001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ctcmsa", "+h,d", 0x783e0019, 0xffff003f, COD, RD_d, MSA}, +{"cfcmsa", "+i,+g", 0x787e0019, 0xffff003f, COD, 0, MSA}, +{"move.v", "+d,+e", 0x78be0019, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"lsa", "d,v,t,+@", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, MSA}, +{"dlsa", "d,v,t,+@", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, MSA64}, + {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, {"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ @@ -3000,6 +3576,13 @@ static const char * const mips_fpr_names_64[32] = "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" }; +static const char * const mips_wr_names[32] = { + "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", + "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", + "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", + "w24", "w25", "w26", "w27", "w28", "w29", "w30", "w31" +}; + static const char * const mips_cp0_names_numeric[32] = { "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", @@ -3218,6 +3801,20 @@ static const char * const mips_hwr_names_mips3264r2[32] = "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; +static const char * const mips_msa_control_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_msa_control_names_mips3264r2[32] = { + "MSAIR", "MSACSR", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + struct mips_abi_choice { const char *name; @@ -3335,7 +3932,7 @@ static const struct mips_arch_choice mips_arch_choices[] = { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2 - | INSN_MIPS3D | INSN_MT), + | INSN_MIPS3D | INSN_MT | INSN_MSA), mips_cp0_names_mips3264r2, mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_hwr_names_mips3264r2 }, @@ -3689,6 +4286,89 @@ print_insn_args (const char *d, (l >> OP_SH_UDI4) & OP_MASK_UDI4); break; + case '5': /* 5-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_RT) & OP_MASK_RT); + if (delta & 0x10) { /* test sign bit */ + delta |= ~OP_MASK_RT; + } + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '6': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_2BIT) & OP_MASK_2BIT); + break; + + case '7': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_3BIT) & OP_MASK_3BIT); + break; + + case '8': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_4BIT) & OP_MASK_4BIT); + break; + + case '9': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_5BIT) & OP_MASK_5BIT); + break; + + case ':': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_1BIT) & OP_MASK_1BIT); + break; + + case '!': /* 10-bit pc-relative target in bit 11 */ + delta = ((l >> OP_SH_10BIT) & OP_MASK_10BIT); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_10BIT; + } + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + + case '~': + (*info->fprintf_func) (info->stream, "0"); + break; + + case '@': + (*info->fprintf_func) (info->stream, "0x%lx", + ((l >> OP_SH_1_TO_4) & OP_MASK_1_TO_4)+1); + break; + + case '^': /* 10-bit signed immediate << 0 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '#': /* 10-bit signed immediate << 1 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta << 1); + break; + + case '$': /* 10-bit signed immediate << 2 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta << 2); + break; + + case '%': /* 10-bit signed immediate << 3 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta << 3); + break; + case 'C': case 'H': msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; @@ -3796,6 +4476,38 @@ print_insn_args (const char *d, break; } + case 'd': + (*info->fprintf_func) (info->stream, "%s", + mips_wr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'e': + (*info->fprintf_func) (info->stream, "%s", + mips_wr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'f': + (*info->fprintf_func) (info->stream, "%s", + mips_wr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'g': + (*info->fprintf_func) (info->stream, "%s", + mips_msa_control_names_mips3264r2[(l >> OP_SH_MSACR11) + & OP_MASK_MSACR11]); + break; + + case 'h': + (*info->fprintf_func) (info->stream, "%s", + mips_msa_control_names_mips3264r2[(l >> OP_SH_MSACR6) + & OP_MASK_MSACR6]); + break; + + case 'i': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_GPR) & OP_MASK_GPR]); + break; + default: /* xgettext:c-format */ (*info->fprintf_func) (info->stream, From 55a2201e79d063766509ed2f2f2e8837b9e1facf Mon Sep 17 00:00:00 2001 From: Yongbok Kim Date: Sat, 1 Nov 2014 05:28:53 +0000 Subject: [PATCH 34/34] target-mips: add MSA support to mips32r5-generic add MSA support to mips32r5-generic core definition Signed-off-by: Yongbok Kim Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index a69a724d2e..4dee1caf92 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -358,7 +358,7 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) | (1 << CP0C1_CA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M), + .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP), .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M), .CP0_Config4_rw_bitmask = 0, .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_UFR), @@ -376,7 +376,7 @@ static const mips_def_t mips_defs[] = (0x93 << FCR0_PRID), .SEGBITS = 32, .PABITS = 32, - .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_DSP | ASE_DSPR2, + .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_DSP | ASE_DSPR2 | ASE_MSA, .mmu_type = MMU_TYPE_R4000, }, #if defined(TARGET_MIPS64)