From 800675f11742b6080e40d17b8d5f35d3a5fc5724 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 3 Nov 2014 18:47:45 +0000 Subject: [PATCH 01/30] target-mips: Correct the handling of register #72 on writes Fix an off-by-one error in `mips_cpu_gdb_write_register' for register matching how `mips_cpu_gdb_read_register' handles it. This register slot is a fake anyway, there's nothing in hardware that corresponds to it. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c index f65fec23cc..7e3a604afa 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -90,7 +90,7 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return sizeof(target_ulong); } if (env->CP0_Config1 & (1 << CP0C1_FP) - && n >= 38 && n < 73) { + && n >= 38 && n < 72) { if (n < 70) { if (env->CP0_Status & (1 << CP0St_FR)) { env->active_fpu.fpr[n - 38].d = tmp; From c7d4d98ae7057467f48c02a11ad9120021976089 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 3 Nov 2014 18:51:38 +0000 Subject: [PATCH 02/30] target-mips: Make CP1.FIR read-only here too CP1.FIR is read-only in hardware so gdbstub must respect it. We already respect it for CTC1 instructions, so do it here too. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c index 7e3a604afa..e86df0e57c 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -105,7 +105,7 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) RESTORE_ROUNDING_MODE; break; case 71: - env->active_fpu.fcr0 = tmp; + /* FIR is read-only. Ignore writes. */ break; } return sizeof(target_ulong); From 36b86e0dc2be93fc538fe7e11e0fda1a198f0135 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 3 Nov 2014 19:31:26 +0000 Subject: [PATCH 03/30] target-mips: Add 5KEc and 5KEf MIPS64r2 processors Add the 5KEc and 5KEf processors from MIPS Technologies that are the original implementation of the MIPS64r2 ISA. Silicon for these processors has never been taped out and no soft cores were released even. They do exist though, a CP0.PRId value has been assigned and experimental RTLs produced at the time the MIPS64r2 ISA has been finalized. The settings introduced here faithfully reproduce that hardware. As far the implementation goes these processors are the same as the 5Kc and the 5Kf CPUs respectively, except implementing the MIPS64r2 rather than the original MIPS64 instruction set. There must have been some updates to the CP0 architecture as mandated by the ISA, such as the addition of the EBase register, although I am not sure about the exact details, no documentation has ever been produced for these processors. The remaining parts of the microarchitecture, in particular the pipeline, stayed unchanged. Or to put it another way, the difference between a 5K and a 5KE CPU corresponds to one between a 4K and a 4KE CPU, except for the 64-bit rather than 32-bit ISA. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 148b394cf0..607f1c8cef 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -519,6 +519,51 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D, .mmu_type = MMU_TYPE_R4000, }, + { + .name = "5KEc", + .CP0_PRid = 0x00018900, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x32F8FFFF, + .SEGBITS = 42, + .PABITS = 36, + .insn_flags = CPU_MIPS64R2, + .mmu_type = MMU_TYPE_R4000, + }, + { + .name = "5KEf", + .CP0_PRid = 0x00018900, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x36F8FFFF, + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | + (0x89 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 42, + .PABITS = 36, + .insn_flags = CPU_MIPS64R2, + .mmu_type = MMU_TYPE_R4000, + }, { /* A generic CPU supporting MIPS64 Release 6 ISA. FIXME: Support IEEE 754-2008 FP and misaligned memory accesses. From 8280b12c0e4b515d707509dde4ddde05d9bda4ef Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 4 Nov 2014 15:37:17 +0000 Subject: [PATCH 04/30] target-mips: Make CP0.Config4 and CP0.Config5 registers signed Make the data type used for the CP0.Config4 and CP0.Config5 registers and their mask signed, for consistency with the remaining 32-bit CP0 registers, like CP0.Config0, etc. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/cpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c01bbdac2d..a08c2c8467 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -446,8 +446,8 @@ struct CPUMIPSState { #define CP0C3_MT 2 #define CP0C3_SM 1 #define CP0C3_TL 0 - uint32_t CP0_Config4; - uint32_t CP0_Config4_rw_bitmask; + int32_t CP0_Config4; + int32_t CP0_Config4_rw_bitmask; #define CP0C4_M 31 #define CP0C4_IE 29 #define CP0C4_KScrExist 16 @@ -456,8 +456,8 @@ struct CPUMIPSState { #define CP0C4_FTLBWays 4 #define CP0C4_FTLBSets 0 #define CP0C4_MMUSizeExt 0 - uint32_t CP0_Config5; - uint32_t CP0_Config5_rw_bitmask; + int32_t CP0_Config5; + int32_t CP0_Config5_rw_bitmask; #define CP0C5_M 31 #define CP0C5_K 30 #define CP0C5_CV 29 From 11f5ea105c06bec72e9bc9a700fa65d60afb5ec3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 4 Nov 2014 15:39:48 +0000 Subject: [PATCH 05/30] target-mips: Add M14K and M14Kc MIPS32r2 microMIPS processors Add the M14K and M14Kc processors from MIPS Technologies that are the original implementation of the microMIPS ISA. They are dual instruction set processors, implementing both the microMIPS and the standard MIPSr32 ISA. These processors correspond to the M4K and 4KEc CPUs respectively, except with support for the microMIPS instruction set added, support for the MCU ASE added and two extra interrupt lines, making a total of 8 hardware interrupts plus 2 software interrupts. The remaining parts of the microarchitecture, in particular the pipeline, stayed unchanged. The presence of the microMIPS ASE is is reflected in the configuration added. We currently have no support for the MCU ASE, including in particular the ACLR, ASET and IRET instructions in either encoding, and we have no support for the extra interrupt lines, including bits in CP0.Status and CP0.Cause registers, so these features are not marked, making our support diverge from real hardware. Signed-off-by: Sandra Loosemore Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 607f1c8cef..f0c1072be8 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -347,6 +347,47 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_DSPR2, .mmu_type = MMU_TYPE_R4000, }, + { + .name = "M14K", + .CP0_PRid = 0x00019b00, + /* Config1 implemented, fixed mapping MMU, + no virtual icache, uncached coherency. */ + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_KU) | (0x2 << CP0C0_K23) | + (0x1 << CP0C0_AR) | (MMU_TYPE_FMT << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (0x2 << CP0C3_ISA) | (1 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1258FF17, + .SEGBITS = 32, + .PABITS = 32, + .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS, + .mmu_type = MMU_TYPE_FMT, + }, + { + .name = "M14Kc", + /* This is the TLB-based MMU core. */ + .CP0_PRid = 0x00019c00, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (0x2 << CP0C3_ISA) | (0 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1278FF17, + .SEGBITS = 32, + .PABITS = 32, + .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS, + .mmu_type = MMU_TYPE_R4000, + }, { /* A generic CPU providing MIPS32 Release 5 features. FIXME: Eventually this should be replaced by a real CPU model. */ From 4386f08767240080334539ac0b07a8bfe30bffe9 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 4 Nov 2014 15:42:19 +0000 Subject: [PATCH 06/30] target-mips: Enable vectored interrupt support for the 74Kf CPU Enable vectored interrupt support for the 74Kf CPU, reflecting hardware. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index f0c1072be8..7f73aa2006 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -334,7 +334,7 @@ static const mips_def_t mips_defs[] = (1 << CP0C1_CA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_DSP2P) | (1 << CP0C3_DSPP) | - (0 << CP0C3_VInt), + (1 << CP0C3_VInt), .CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, From d75de74967f631a7d0b538d4b88f96f9c426bfe2 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 5 Nov 2014 15:34:00 +0000 Subject: [PATCH 07/30] target-mips: Fix formatting in `decode_extended_mips16_opc' Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index f0b8e6ffe4..643214aad7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -11099,7 +11099,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LD: - check_mips_64(ctx); + check_mips_64(ctx); gen_ld(ctx, OPC_LD, ry, rx, offset); break; #endif From 6225a4a0e39cb24e7b9e1d4d2c1a3e6eaee18e85 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 5 Nov 2014 15:34:58 +0000 Subject: [PATCH 08/30] target-mips: Fix formatting in `mips_defs' Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 40 +++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 7f73aa2006..1543f6c388 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -645,10 +645,11 @@ static const mips_def_t mips_defs[] = { .name = "Loongson-2E", .CP0_PRid = 0x6302, - /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/ - .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | (0x1<<5) | - (0x1<<4) | (0x1<<1), - /* Note: Config1 is only used internally, Loongson-2E has only Config0. */ + /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ + .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | + (0x1<<5) | (0x1<<4) | (0x1<<1), + /* Note: Config1 is only used internally, + Loongson-2E has only Config0. */ .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), .SYNCI_Step = 16, .CCRes = 2, @@ -660,21 +661,22 @@ static const mips_def_t mips_defs[] = .mmu_type = MMU_TYPE_R4000, }, { - .name = "Loongson-2F", - .CP0_PRid = 0x6303, - /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/ - .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | (0x1<<5) | - (0x1<<4) | (0x1<<1), - /* Note: Config1 is only used internally, Loongson-2F has only Config0. */ - .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), - .SYNCI_Step = 16, - .CCRes = 2, - .CP0_Status_rw_bitmask = 0xF5D0FF1F, /*bit5:7 not writable*/ - .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV), - .SEGBITS = 40, - .PABITS = 40, - .insn_flags = CPU_LOONGSON2F, - .mmu_type = MMU_TYPE_R4000, + .name = "Loongson-2F", + .CP0_PRid = 0x6303, + /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ + .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | + (0x1<<5) | (0x1<<4) | (0x1<<1), + /* Note: Config1 is only used internally, + Loongson-2F has only Config0. */ + .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), + .SYNCI_Step = 16, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0xF5D0FF1F, /* Bits 7:5 not writable. */ + .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV), + .SEGBITS = 40, + .PABITS = 40, + .insn_flags = CPU_LOONGSON2F, + .mmu_type = MMU_TYPE_R4000, }, { /* A generic CPU providing MIPS64 ASE DSP 2 features. From d2bfa6e6222baa0218bd0658499d38bac56ac34c Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 5 Nov 2014 15:35:31 +0000 Subject: [PATCH 09/30] target-mips: Fix formatting in `decode_opc' Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/translate.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 643214aad7..a5a5ca44ee 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -18340,7 +18340,7 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) } -static void decode_opc (CPUMIPSState *env, DisasContext *ctx) +static void decode_opc(CPUMIPSState *env, DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; @@ -18506,7 +18506,8 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) save_cpu_state(ctx, 1); gen_helper_di(t0, cpu_env); gen_store_gpr(t0, rt); - /* Stop translation as we may have switched the execution mode */ + /* Stop translation as we may have switched + the execution mode. */ ctx->bstate = BS_STOP; break; case OPC_EI: @@ -18514,7 +18515,8 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rt); - /* Stop translation as we may have switched the execution mode */ + /* Stop translation as we may have switched + the execution mode. */ ctx->bstate = BS_STOP; break; default: /* Invalid */ @@ -18780,8 +18782,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) 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); + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), + rt, rd, sa, (imm >> 8) & 0x7); + break; } } else { From 2b09f94cdbf5c54e2278d7f3aed2eceff3494790 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 5 Nov 2014 15:35:59 +0000 Subject: [PATCH 10/30] target-mips: Make `helper_float_cvtw_s' consistent with the remaining helpers Move the call to `update_fcr31' in `helper_float_cvtw_s' after the exception flag check, for consistency with the remaining helpers that do it last too. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 638c9f9dfb..5a9f207f84 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2659,11 +2659,11 @@ uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0) uint32_t wt2; wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - update_fcr31(env, GETPC()); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; } + update_fcr31(env, GETPC()); return wt2; } From 51fdea945ae7adae8d7e4a1624e35bb7f714b58f Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 5 Nov 2014 15:36:28 +0000 Subject: [PATCH 11/30] target-mips: Remove unused `FLOAT_OP' macro Remove the `FLOAT_OP' macro, unused since commit b6d96beda3a6cbf20a2d04a609eff78adebd8859 [Use temporary registers for the MIPS FPU emulation.]. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/op_helper.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 5a9f207f84..f5478010ea 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -3140,8 +3140,6 @@ uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0) return ((uint64_t)fsth2 << 32) | fst2; } -#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env) - /* binary operations */ #define FLOAT_BINOP(name) \ uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ From 8fc605b8aa257feb3e69d44794a765bd492b573b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 5 Nov 2014 15:38:01 +0000 Subject: [PATCH 12/30] target-mips: Restore the order of helpers Restore the order of helpers that used to be: unary operations (generic, then MIPS-specific), binary operations (generic, then MIPS-specific), compare operations. At one point FMA operations were inserted at a random place in the file, disregarding the preexisting order, and later on even more operations sprinkled across the file. Revert the mess by moving FMA operations to a new ternary class inserted after the binary class and move the misplaced unary and binary operations to where they belong. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/op_helper.c | 319 ++++++++++++++++++++-------------------- 1 file changed, 160 insertions(+), 159 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index f5478010ea..d25424f5bf 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2935,110 +2935,6 @@ FLOAT_UNOP(abs) FLOAT_UNOP(chs) #undef FLOAT_UNOP -#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ -uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ - uint ## bits ## _t fs, \ - uint ## bits ## _t ft, \ - uint ## bits ## _t fd) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ - &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -FLOAT_FMADDSUB(maddf_s, 32, 0) -FLOAT_FMADDSUB(maddf_d, 64, 0) -FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) -FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) -#undef FLOAT_FMADDSUB - -#define FLOAT_MINMAX(name, bits, minmaxfunc) \ -uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ - uint ## bits ## _t fs, \ - uint ## bits ## _t ft) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ - &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -FLOAT_MINMAX(max_s, 32, maxnum) -FLOAT_MINMAX(max_d, 64, maxnum) -FLOAT_MINMAX(maxa_s, 32, maxnummag) -FLOAT_MINMAX(maxa_d, 64, maxnummag) - -FLOAT_MINMAX(min_s, 32, minnum) -FLOAT_MINMAX(min_d, 64, minnum) -FLOAT_MINMAX(mina_s, 32, minnummag) -FLOAT_MINMAX(mina_d, 64, minnummag) -#undef FLOAT_MINMAX - -#define FLOAT_RINT(name, bits) \ -uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ - uint ## bits ## _t fs) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -FLOAT_RINT(rint_s, 32) -FLOAT_RINT(rint_d, 64) -#undef FLOAT_RINT - -#define FLOAT_CLASS_SIGNALING_NAN 0x001 -#define FLOAT_CLASS_QUIET_NAN 0x002 -#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 -#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 -#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 -#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 -#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 -#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 -#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 -#define FLOAT_CLASS_POSITIVE_ZERO 0x200 - -#define FLOAT_CLASS(name, bits) \ -uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \ -{ \ - if (float ## bits ## _is_signaling_nan(arg)) { \ - return FLOAT_CLASS_SIGNALING_NAN; \ - } else if (float ## bits ## _is_quiet_nan(arg)) { \ - return FLOAT_CLASS_QUIET_NAN; \ - } else if (float ## bits ## _is_neg(arg)) { \ - if (float ## bits ## _is_infinity(arg)) { \ - return FLOAT_CLASS_NEGATIVE_INFINITY; \ - } else if (float ## bits ## _is_zero(arg)) { \ - return FLOAT_CLASS_NEGATIVE_ZERO; \ - } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ - return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ - } else { \ - return FLOAT_CLASS_NEGATIVE_NORMAL; \ - } \ - } else { \ - if (float ## bits ## _is_infinity(arg)) { \ - return FLOAT_CLASS_POSITIVE_INFINITY; \ - } else if (float ## bits ## _is_zero(arg)) { \ - return FLOAT_CLASS_POSITIVE_ZERO; \ - } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ - return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ - } else { \ - return FLOAT_CLASS_POSITIVE_NORMAL; \ - } \ - } \ -} - -FLOAT_CLASS(class_s, 32) -FLOAT_CLASS(class_d, 64) -#undef FLOAT_CLASS - /* MIPS specific unary operations */ uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0) { @@ -3140,6 +3036,66 @@ uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0) return ((uint64_t)fsth2 << 32) | fst2; } +#define FLOAT_RINT(name, bits) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_RINT(rint_s, 32) +FLOAT_RINT(rint_d, 64) +#undef FLOAT_RINT + +#define FLOAT_CLASS_SIGNALING_NAN 0x001 +#define FLOAT_CLASS_QUIET_NAN 0x002 +#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 +#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 +#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 +#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 +#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 +#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 +#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 +#define FLOAT_CLASS_POSITIVE_ZERO 0x200 + +#define FLOAT_CLASS(name, bits) \ +uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \ +{ \ + if (float ## bits ## _is_signaling_nan(arg)) { \ + return FLOAT_CLASS_SIGNALING_NAN; \ + } else if (float ## bits ## _is_quiet_nan(arg)) { \ + return FLOAT_CLASS_QUIET_NAN; \ + } else if (float ## bits ## _is_neg(arg)) { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_NEGATIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_NEGATIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_NEGATIVE_NORMAL; \ + } \ + } else { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_POSITIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_POSITIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_POSITIVE_NORMAL; \ + } \ + } \ +} + +FLOAT_CLASS(class_s, 32) +FLOAT_CLASS(class_d, 64) +#undef FLOAT_CLASS + /* binary operations */ #define FLOAT_BINOP(name) \ uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ @@ -3185,61 +3141,6 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP -#define UNFUSED_FMA(prefix, a, b, c, flags) \ -{ \ - a = prefix##_mul(a, b, &env->active_fpu.fp_status); \ - if ((flags) & float_muladd_negate_c) { \ - a = prefix##_sub(a, c, &env->active_fpu.fp_status); \ - } else { \ - a = prefix##_add(a, c, &env->active_fpu.fp_status); \ - } \ - if ((flags) & float_muladd_negate_result) { \ - a = prefix##_chs(a); \ - } \ -} - -/* FMA based operations */ -#define FLOAT_FMA(name, type) \ -uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1, \ - uint64_t fdt2) \ -{ \ - UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \ - update_fcr31(env, GETPC()); \ - return fdt0; \ -} \ - \ -uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ - uint32_t fst0, uint32_t fst1, \ - uint32_t fst2) \ -{ \ - UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ - update_fcr31(env, GETPC()); \ - return fst0; \ -} \ - \ -uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1, \ - uint64_t fdt2) \ -{ \ - uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ - uint32_t fsth0 = fdt0 >> 32; \ - uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ - uint32_t fsth1 = fdt1 >> 32; \ - uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ - uint32_t fsth2 = fdt2 >> 32; \ - \ - UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ - UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \ - update_fcr31(env, GETPC()); \ - return ((uint64_t)fsth0 << 32) | fst0; \ -} -FLOAT_FMA(madd, 0) -FLOAT_FMA(msub, float_muladd_negate_c) -FLOAT_FMA(nmadd, float_muladd_negate_result) -FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) -#undef FLOAT_FMA - /* MIPS specific binary operations */ uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) { @@ -3337,6 +3238,106 @@ uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) return ((uint64_t)fsth2 << 32) | fst2; } +#define FLOAT_MINMAX(name, bits, minmaxfunc) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_MINMAX(max_s, 32, maxnum) +FLOAT_MINMAX(max_d, 64, maxnum) +FLOAT_MINMAX(maxa_s, 32, maxnummag) +FLOAT_MINMAX(maxa_d, 64, maxnummag) + +FLOAT_MINMAX(min_s, 32, minnum) +FLOAT_MINMAX(min_d, 64, minnum) +FLOAT_MINMAX(mina_s, 32, minnummag) +FLOAT_MINMAX(mina_d, 64, minnummag) +#undef FLOAT_MINMAX + +/* ternary operations */ +#define UNFUSED_FMA(prefix, a, b, c, flags) \ +{ \ + a = prefix##_mul(a, b, &env->active_fpu.fp_status); \ + if ((flags) & float_muladd_negate_c) { \ + a = prefix##_sub(a, c, &env->active_fpu.fp_status); \ + } else { \ + a = prefix##_add(a, c, &env->active_fpu.fp_status); \ + } \ + if ((flags) & float_muladd_negate_result) { \ + a = prefix##_chs(a); \ + } \ +} + +/* FMA based operations */ +#define FLOAT_FMA(name, type) \ +uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ + uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \ + update_fcr31(env, GETPC()); \ + return fdt0; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ + uint32_t fst0, uint32_t fst1, \ + uint32_t fst2) \ +{ \ + UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ + update_fcr31(env, GETPC()); \ + return fst0; \ +} \ + \ +uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ + uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ + uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ + uint32_t fsth1 = fdt1 >> 32; \ + uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ + uint32_t fsth2 = fdt2 >> 32; \ + \ + UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ + UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \ + update_fcr31(env, GETPC()); \ + return ((uint64_t)fsth0 << 32) | fst0; \ +} +FLOAT_FMA(madd, 0) +FLOAT_FMA(msub, float_muladd_negate_c) +FLOAT_FMA(nmadd, float_muladd_negate_result) +FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) +#undef FLOAT_FMA + +#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft, \ + uint ## bits ## _t fd) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_FMADDSUB(maddf_s, 32, 0) +FLOAT_FMADDSUB(maddf_d, 64, 0) +FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) +FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) +#undef FLOAT_FMADDSUB + /* compare operations */ #define FOP_COND_D(op, cond) \ void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \ From c3577479815f5bcf9d38993967bca2115af245d8 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 7 Nov 2014 20:05:35 +0000 Subject: [PATCH 13/30] target-mips: Correct MIPS16/microMIPS branch size calculation Correct MIPS16/microMIPS branch size calculation in PC adjustment needed: - to set the value of CP0.ErrorEPC at the entry to the reset exception, - for the purpose of branch reexecution in the context of device I/O. Follow the approach taken in `exception_resume_pc' for ordinary, Debug and NMI exceptions. MIPS16 and microMIPS branches can be 2 or 4 bytes in size and that has to be reflected in calculation. Original MIPS ISA branches, which is where this code originates from, are always 4 bytes long, just as all original MIPS ISA instructions. Signed-off-by: Nathan Froyd Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate.c | 3 ++- translate-all.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index a5a5ca44ee..b5d5b39092 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -19439,7 +19439,8 @@ void cpu_state_reset(CPUMIPSState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_ErrorEPC = env->active_tc.PC - 4; + env->CP0_ErrorEPC = (env->active_tc.PC + - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4)); } else { env->CP0_ErrorEPC = env->active_tc.PC; } diff --git a/translate-all.c b/translate-all.c index cf05472008..d930a5ce67 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1540,7 +1540,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) branch. */ #if defined(TARGET_MIPS) if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { - env->active_tc.PC -= 4; + env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); cpu->icount_decr.u16.low++; env->hflags &= ~MIPS_HFLAG_BMASK; } From f88f79ec9df06d26d84e1d2e0c02d2634b4d8583 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 10 Nov 2014 13:45:41 +0000 Subject: [PATCH 14/30] target-mips: Correct the handling of writes to CP0.Status for MIPSr6 Correct these issues with the handling of CP0.Status for MIPSr6: * only ignore the bit pattern of 0b11 on writes to CP0.Status.KSU, that is for processors that do implement Supervisor Mode, let the bit pattern be written to CP0.Status.UM:R0 freely (of course the value written to read-only CP0.Status.R0 will be discarded anyway); this is in accordance to the relevant architecture specification[1], * check the newly written pattern rather than the current contents of CP0.Status for the KSU bits being 0b11, * use meaningful macro names to refer to CP0.Status bits rather than magic numbers. References: [1] "MIPS Architecture For Programmers, Volume III: MIPS64 / microMIPS64 Privileged Resource Architecture", MIPS Technologies, Inc., Document Number: MD00091, Revision 6.00, March 31, 2014, Table 9.45 "Status Register Field Descriptions", pp. 210-211. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/op_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d25424f5bf..a0cc729526 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1423,10 +1423,12 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) uint32_t mask = env->CP0_Status_rw_bitmask; if (env->insn_flags & ISA_MIPS32R6) { - if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) { + bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; + + if (has_supervisor && extract32(arg1, CP0St_KSU, 2) == 0x3) { mask &= ~(3 << CP0St_KSU); } - mask &= ~(0x00180000 & arg1); + mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & arg1); } val = arg1 & mask; From 81a423e6c6d3ccaa79de4e58024369c660c1eeb4 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 10 Nov 2014 13:46:35 +0000 Subject: [PATCH 15/30] target-mips: Correct the writes to Status and Cause registers via gdbstub Make writes to CP0.Status and CP0.Cause have the same effect as executing corresponding MTC0 instructions would in Kernel Mode. Also ignore writes in the user emulation mode. Currently for requests from the GDB stub we write all the bits across both registers, ignoring any read-only locations, and do not synchronise the environment to evaluate side effects. We also write these registers in the user emulation mode even though a real kernel presents them as read only. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/cpu.h | 89 ++++++++++++++++++++++++++++++++++++++++ target-mips/gdbstub.c | 8 +++- target-mips/op_helper.c | 91 ++++------------------------------------- 3 files changed, 102 insertions(+), 86 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index a08c2c8467..dd72d1ef50 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -904,4 +904,93 @@ static inline void compute_hflags(CPUMIPSState *env) } } +#ifndef CONFIG_USER_ONLY +/* Called for updates to CP0_Status. */ +static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) +{ + int32_t tcstatus, *tcst; + uint32_t v = cpu->CP0_Status; + uint32_t cu, mx, asid, ksu; + uint32_t mask = ((1 << CP0TCSt_TCU3) + | (1 << CP0TCSt_TCU2) + | (1 << CP0TCSt_TCU1) + | (1 << CP0TCSt_TCU0) + | (1 << CP0TCSt_TMX) + | (3 << CP0TCSt_TKSU) + | (0xff << CP0TCSt_TASID)); + + cu = (v >> CP0St_CU0) & 0xf; + mx = (v >> CP0St_MX) & 0x1; + ksu = (v >> CP0St_KSU) & 0x3; + asid = env->CP0_EntryHi & 0xff; + + tcstatus = cu << CP0TCSt_TCU0; + tcstatus |= mx << CP0TCSt_TMX; + tcstatus |= ksu << CP0TCSt_TKSU; + tcstatus |= asid; + + if (tc == cpu->current_tc) { + tcst = &cpu->active_tc.CP0_TCStatus; + } else { + tcst = &cpu->tcs[tc].CP0_TCStatus; + } + + *tcst &= ~mask; + *tcst |= tcstatus; + compute_hflags(cpu); +} + +static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = env->CP0_Status_rw_bitmask; + + if (env->insn_flags & ISA_MIPS32R6) { + bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; + + if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) { + mask &= ~(3 << CP0St_KSU); + } + mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); + } + + env->CP0_Status = (env->CP0_Status & ~mask) | (val & mask); + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + sync_c0_status(env, env, env->current_tc); + } else { + compute_hflags(env); + } +} + +static inline void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = 0x00C00300; + uint32_t old = env->CP0_Cause; + int i; + + if (env->insn_flags & ISA_MIPS32R2) { + mask |= 1 << CP0Ca_DC; + } + if (env->insn_flags & ISA_MIPS32R6) { + mask &= ~((1 << CP0Ca_WP) & val); + } + + env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask); + + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { + if (env->CP0_Cause & (1 << CP0Ca_DC)) { + cpu_mips_stop_count(env); + } else { + cpu_mips_start_count(env); + } + } + + /* Set/reset software interrupts */ + for (i = 0 ; i < 2 ; i++) { + if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { + cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } +} +#endif + #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c index e86df0e57c..964e6a7733 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -112,7 +112,9 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) } switch (n) { case 32: - env->CP0_Status = tmp; +#ifndef CONFIG_USER_ONLY + cpu_mips_store_status(env, tmp); +#endif break; case 33: env->active_tc.LO[0] = tmp; @@ -124,7 +126,9 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->CP0_BadVAddr = tmp; break; case 36: - env->CP0_Cause = tmp; +#ifndef CONFIG_USER_ONLY + cpu_mips_store_cause(env, tmp); +#endif break; case 37: env->active_tc.PC = tmp & ~(target_ulong)1; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index a0cc729526..1ec2756373 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -625,40 +625,9 @@ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) These helper call synchronizes the regs for a given cpu. */ -/* Called for updates to CP0_Status. */ -static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) -{ - int32_t tcstatus, *tcst; - uint32_t v = cpu->CP0_Status; - uint32_t cu, mx, asid, ksu; - uint32_t mask = ((1 << CP0TCSt_TCU3) - | (1 << CP0TCSt_TCU2) - | (1 << CP0TCSt_TCU1) - | (1 << CP0TCSt_TCU0) - | (1 << CP0TCSt_TMX) - | (3 << CP0TCSt_TKSU) - | (0xff << CP0TCSt_TASID)); - - cu = (v >> CP0St_CU0) & 0xf; - mx = (v >> CP0St_MX) & 0x1; - ksu = (v >> CP0St_KSU) & 0x3; - asid = env->CP0_EntryHi & 0xff; - - tcstatus = cu << CP0TCSt_TCU0; - tcstatus |= mx << CP0TCSt_TMX; - tcstatus |= ksu << CP0TCSt_TKSU; - tcstatus |= asid; - - if (tc == cpu->current_tc) { - tcst = &cpu->active_tc.CP0_TCStatus; - } else { - tcst = &cpu->tcs[tc].CP0_TCStatus; - } - - *tcst &= ~mask; - *tcst |= tcstatus; - compute_hflags(cpu); -} +/* Called for updates to CP0_Status. Defined in "cpu.h" for gdbstub.c. */ +/* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, + int tc); */ /* Called for updates to CP0_TCStatus. */ static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, @@ -1420,25 +1389,10 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) { MIPSCPU *cpu = mips_env_get_cpu(env); uint32_t val, old; - uint32_t mask = env->CP0_Status_rw_bitmask; - if (env->insn_flags & ISA_MIPS32R6) { - bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; - - if (has_supervisor && extract32(arg1, CP0St_KSU, 2) == 0x3) { - mask &= ~(3 << CP0St_KSU); - } - mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & arg1); - } - - val = arg1 & mask; old = env->CP0_Status; - env->CP0_Status = (env->CP0_Status & ~mask) | val; - if (env->CP0_Config3 & (1 << CP0C3_MT)) { - sync_c0_status(env, env, env->current_tc); - } else { - compute_hflags(env); - } + cpu_mips_store_status(env, arg1); + val = env->CP0_Status; if (qemu_loglevel_mask(CPU_LOG_EXEC)) { qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x", @@ -1477,40 +1431,9 @@ void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1) env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask); } -static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1) -{ - uint32_t mask = 0x00C00300; - uint32_t old = cpu->CP0_Cause; - int i; - - 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); - - if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) { - if (cpu->CP0_Cause & (1 << CP0Ca_DC)) { - cpu_mips_stop_count(cpu); - } else { - cpu_mips_start_count(cpu); - } - } - - /* Set/reset software interrupts */ - for (i = 0 ; i < 2 ; i++) { - if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) { - cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i))); - } - } -} - void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1) { - mtc0_cause(env, arg1); + cpu_mips_store_cause(env, arg1); } void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1) @@ -1518,7 +1441,7 @@ void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); - mtc0_cause(other, arg1); + cpu_mips_store_cause(other, arg1); } target_ulong helper_mftc0_epc(CPUMIPSState *env) From 7215d7e7aea85699bf516c3e8d84f6a22584da35 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 12 Nov 2014 15:21:53 +0000 Subject: [PATCH 16/30] target-mips: Fix the 64-bit case for microMIPS MOVE16 and MOVEP Fix microMIPS MOVE16 and MOVEP instructions on 64-bit processors by using register addition operations. This copies the approach taken with MIPS16 MOVE instructions (I8_MOV32R and I8_MOVR32 opcodes) and follows the observation that OPC_ADDU expands to tcg_gen_mov_tl whenever `rt' is 0 and `rs' is not, therefore copying `rs' to `rd' verbatim. This is not the case with OPC_ADDIU where a sign-extension from bit #31 is made, unless in the uninteresting case of `rs' being 0, losing the upper 32 bits of the value copied for any proper 64-bit values. This also serves as an optimization as one op is produced in generated code rather than two (again, unless `rs' is 0, where it doesn't change anything). Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index b5d5b39092..1a275bf099 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13936,8 +13936,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) rs = rs_rt_enc[enc_rs]; rt = rs_rt_enc[enc_rt]; - gen_arith_imm(ctx, OPC_ADDIU, rd, rs, 0); - gen_arith_imm(ctx, OPC_ADDIU, re, rt, 0); + gen_arith(ctx, OPC_ADDU, rd, rs, 0); + gen_arith(ctx, OPC_ADDU, re, rt, 0); } break; case LBU16: @@ -14018,7 +14018,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) int rd = uMIPS_RD5(ctx->opcode); int rs = uMIPS_RS5(ctx->opcode); - gen_arith_imm(ctx, OPC_ADDIU, rd, rs, 0); + gen_arith(ctx, OPC_ADDU, rd, rs, 0); } break; case ANDI16: From 27e1fb13f21e132011673f0a39e17bcc97583633 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 18 Nov 2014 03:20:28 +0000 Subject: [PATCH 17/30] target-mips: Output CP0.Config2-5 in the register dump Include CP0.Config2 through CP0.Config5 registers in the register dump produced with the `info registers' monitor command. Align vertically with the registers already output. Signed-off-by: Maciej W. Rozycki Signed-off-by: Leon Alrae --- target-mips/translate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 1a275bf099..70da66f958 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -19264,6 +19264,10 @@ void mips_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->CP0_Status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", env->CP0_Config0, env->CP0_Config1, env->lladdr); + cpu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", + env->CP0_Config2, env->CP0_Config3); + cpu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n", + env->CP0_Config4, env->CP0_Config5); if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) From 90f12d735d66ac1196d9a2bced039a432eefc03d Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 18 Nov 2014 03:59:07 +0000 Subject: [PATCH 18/30] target-mips: Fix CP0.Config3.ISAOnExc write accesses Fix CP0.Config3.ISAOnExc write accesses on microMIPS processors. This bit is mandatory for any processor that implements the microMIPS instruction set. This bit is r/w for processors that implement both the standard MIPS and the microMIPS instruction set. This bit is r/o and hardwired to 1 if only the microMIPS instruction set is implemented. There is no other bit ever writable in CP0.Config3 so defining a corresponding `CP0_Config3_rw_bitmask' member in `CPUMIPSState' is I think an overkill. Therefore make the ability to write the bit rely on the presence of ASE_MICROMIPS set in the instruction flags. The read-only case of the microMIPS instruction set being implemented only can be added when we add support for such a configuration. We do not currently have such support, we have no instruction flag that would control the presence of the standard MIPS instruction set nor any associated code in instruction decoding. This change is needed to boot a microMIPS Linux kernel successfully, otherwise it hangs early on as interrupts are enabled and then the exception handler invoked loops as its first instruction is interpreted in the wrong execution mode and triggers another exception right away. And then over and over again. We already check the current setting of the CP0.Config3.ISAOnExc in `set_hflags_for_handler' to set the ISA bit correctly on the exception handler entry so it is the ability to set it that is missing only. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/helper.h | 1 + target-mips/op_helper.c | 8 ++++++++ target-mips/translate.c | 8 ++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index 9d0275891c..3bd0b029e4 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -137,6 +137,7 @@ DEF_HELPER_2(mtc0_ebase, void, env, tl) DEF_HELPER_2(mttc0_ebase, void, env, tl) DEF_HELPER_2(mtc0_config0, void, env, tl) DEF_HELPER_2(mtc0_config2, void, env, tl) +DEF_HELPER_2(mtc0_config3, void, env, tl) DEF_HELPER_2(mtc0_config4, void, env, tl) DEF_HELPER_2(mtc0_config5, void, env, tl) DEF_HELPER_2(mtc0_lladdr, void, env, tl) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1ec2756373..1267ef297c 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1503,6 +1503,14 @@ void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1) env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); } +void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1) +{ + if (env->insn_flags & ASE_MICROMIPS) { + env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) | + (arg1 & (1 << CP0C3_ISA_ON_EXC)); + } +} + void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1) { env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) | diff --git a/target-mips/translate.c b/target-mips/translate.c index 70da66f958..d4fedfbd45 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5846,8 +5846,10 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->bstate = BS_STOP; break; case 3: - /* ignored, read only */ + gen_helper_mtc0_config3(cpu_env, arg); rn = "Config3"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 4: gen_helper_mtc0_config4(cpu_env, arg); @@ -7097,8 +7099,10 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->bstate = BS_STOP; break; case 3: - /* ignored */ + gen_helper_mtc0_config3(cpu_env, arg); rn = "Config3"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 4: /* currently ignored */ From d9224450208e0de62323b64ace91f98bc31d6e2c Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 5 Dec 2014 18:47:58 +0000 Subject: [PATCH 19/30] target-mips: Tighten ISA level checks Tighten ISA level checks down to MIPS II that many of our instructions are missing. Also make sure any 64-bit instruction enables are only applied to 64-bit processors, that is ones that implement at least the MIPS III ISA. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/cpu.h | 7 +-- target-mips/helper.c | 15 ++++-- target-mips/translate.c | 107 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 114 insertions(+), 15 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index dd72d1ef50..e59cb4c6dc 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -831,9 +831,10 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; } #if defined(TARGET_MIPS64) - if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || - (env->CP0_Status & (1 << CP0St_PX)) || - (env->CP0_Status & (1 << CP0St_UX))) { + if ((env->insn_flags & ISA_MIPS3) && + (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX)))) { env->hflags |= MIPS_HFLAG_64; } diff --git a/target-mips/helper.c b/target-mips/helper.c index 3a93c206e4..c4b3658098 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -527,7 +527,10 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_DEPC = exception_resume_pc(env); env->hflags &= ~MIPS_HFLAG_BMASK; enter_debug_mode: - env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + if (env->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } + env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) @@ -548,7 +551,10 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_ErrorEPC = exception_resume_pc(env); env->hflags &= ~MIPS_HFLAG_BMASK; env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + if (env->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } + env->hflags |= MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1U << CP0Ca_BD); @@ -726,7 +732,10 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_Cause &= ~(1U << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + if (env->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } + env->hflags |= MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); } env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-mips/translate.c b/target-mips/translate.c index d4fedfbd45..2173ea5222 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2398,7 +2398,14 @@ static void gen_cop1_ldst(DisasContext *ctx, uint32_t op, int rt, { if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { check_cp1_enabled(ctx); - gen_flt_ldst(ctx, op, rt, rs, imm); + switch (op) { + case OPC_LDC1: + case OPC_SDC1: + check_insn(ctx, ISA_MIPS2); + /* Fallthrough */ + default: + gen_flt_ldst(ctx, op, rt, rs, imm); + } } else { generate_exception_err(ctx, EXCP_CpU, 1); } @@ -10997,26 +11004,32 @@ static void decode_i64_mips16 (DisasContext *ctx, { switch (funct) { case I64_LDSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 3; gen_ld(ctx, OPC_LD, ry, 29, offset); break; case I64_SDSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 3; gen_st(ctx, OPC_SD, ry, 29, offset); break; case I64_SDRASP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : (ctx->opcode & 0xff) << 3; gen_st(ctx, OPC_SD, 31, 29, offset); break; case I64_DADJSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : ((int8_t)ctx->opcode) << 3; gen_arith_imm(ctx, OPC_DADDIU, 29, 29, offset); break; case I64_LDPC: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { generate_exception(ctx, EXCP_RI); } else { @@ -11025,16 +11038,19 @@ static void decode_i64_mips16 (DisasContext *ctx, } break; case I64_DADDIU5: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : ((int8_t)(offset << 3)) >> 3; gen_arith_imm(ctx, OPC_DADDIU, ry, ry, offset); break; case I64_DADDIUPC: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 2; gen_addiupc(ctx, ry, offset, 1, extended); break; case I64_DADDIUSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 2; gen_arith_imm(ctx, OPC_DADDIU, ry, 29, offset); @@ -11103,6 +11119,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LD: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_ld(ctx, OPC_LD, ry, rx, offset); break; @@ -11147,6 +11164,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm); break; case I8_SVRS: + check_insn(ctx, ISA_MIPS32); { int xsregs = (ctx->opcode >> 24) & 0x7; int aregs = (ctx->opcode >> 16) & 0xf; @@ -11180,6 +11198,8 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_SD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_st(ctx, OPC_SD, ry, rx, offset); break; #endif @@ -11206,6 +11226,8 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_ld(ctx, OPC_LWU, ry, rx, offset); break; #endif @@ -11295,6 +11317,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; case 0x1: #if defined(TARGET_MIPS64) + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); #else @@ -11311,6 +11334,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LD: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_ld(ctx, OPC_LD, ry, rx, offset << 3); break; @@ -11321,6 +11345,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) if ((ctx->opcode >> 4) & 1) { #if defined(TARGET_MIPS64) + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); #else @@ -11372,6 +11397,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) ((int8_t)ctx->opcode) << 3); break; case I8_SVRS: + check_insn(ctx, ISA_MIPS32); { int do_ra = ctx->opcode & (1 << 6); int do_s0 = ctx->opcode & (1 << 5); @@ -11427,6 +11453,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_SD: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_st(ctx, OPC_SD, ry, rx, offset << 3); break; @@ -11454,6 +11481,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case M16_OPC_LWU: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_ld(ctx, OPC_LWU, ry, rx, offset << 2); break; @@ -11485,10 +11513,12 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) #if defined(TARGET_MIPS64) case RRR_DADDU: mips32_op = OPC_DADDU; + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); break; case RRR_DSUBU: mips32_op = OPC_DSUBU; + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); break; #endif @@ -11510,6 +11540,10 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) int link = (ctx->opcode >> 6) & 0x1; int ra = (ctx->opcode >> 5) & 0x1; + if (nd) { + check_insn(ctx, ISA_MIPS32); + } + if (link) { op = OPC_JALR; } else { @@ -11551,6 +11585,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_DSRL: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift_imm(ctx, OPC_DSRL, ry, ry, sa); break; @@ -11577,6 +11612,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) gen_HILO(ctx, OPC_MFHI, 0, rx); break; case RR_CNVT: + check_insn(ctx, ISA_MIPS32); switch (cnvt_op) { case RR_RY_CNVT_ZEB: tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]); @@ -11592,10 +11628,12 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_RY_CNVT_ZEW: + check_insn(ctx, ISA_MIPS64); check_mips_64(ctx); tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]); break; case RR_RY_CNVT_SEW: + check_insn(ctx, ISA_MIPS64); check_mips_64(ctx); tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); break; @@ -11610,18 +11648,22 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_DSRA: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift_imm(ctx, OPC_DSRA, ry, ry, sa); break; case RR_DSLLV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift(ctx, OPC_DSLLV, ry, rx, ry); break; case RR_DSRLV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift(ctx, OPC_DSRLV, ry, rx, ry); break; case RR_DSRAV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift(ctx, OPC_DSRAV, ry, rx, ry); break; @@ -11640,18 +11682,22 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_DMULT: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DMULT, 0, rx, ry); break; case RR_DMULTU: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry); break; case RR_DDIV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DDIV, 0, rx, ry); break; case RR_DDIVU: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry); break; @@ -13216,20 +13262,26 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, /* COP2: Not implemented. */ generate_exception_err(ctx, EXCP_CpU, 2); break; - case LWP: - case SWP: #ifdef TARGET_MIPS64 case LDP: case SDP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + /* Fallthrough */ #endif + case LWP: + case SWP: gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); break; - case LWM32: - case SWM32: #ifdef TARGET_MIPS64 case LDM: case SDM: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + /* Fallthrough */ #endif + case LWM32: + case SWM32: gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); break; default: @@ -13653,21 +13705,33 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, goto do_st_lr; #if defined(TARGET_MIPS64) case LDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LDL; goto do_ld_lr; case SDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_SDL; goto do_st_lr; case LDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LDR; goto do_ld_lr; case SDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_SDR; goto do_st_lr; case LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LWU; goto do_ld_lr; case LLD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LLD; goto do_ld_lr; #endif @@ -13685,6 +13749,8 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, break; #if defined(TARGET_MIPS64) case SCD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12)); break; #endif @@ -13794,9 +13860,13 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, goto do_ld; #ifdef TARGET_MIPS64 case LD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LD; goto do_ld; case SD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_SD; goto do_st; #endif @@ -16326,6 +16396,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: + check_insn(ctx, ISA_MIPS2); gen_trap(ctx, op1, rs, rt, -1); break; case OPC_LSA: /* OPC_PMON */ @@ -16350,6 +16421,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) generate_exception(ctx, EXCP_BREAK); break; case OPC_SYNC: + check_insn(ctx, ISA_MIPS2); /* Treat as NOP. */ break; @@ -18396,7 +18468,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) case OPC_BGEZL: case OPC_BLTZALL: case OPC_BGEZALL: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* Fallthrough */ case OPC_BLTZ: case OPC_BGEZ: gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4); @@ -18416,6 +18490,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_trap(ctx, op1, rs, -1, imm); break; @@ -18622,15 +18697,20 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) break; case OPC_BEQL: case OPC_BNEL: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* Fallthrough */ case OPC_BEQ: case OPC_BNE: gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); break; - case OPC_LWL: /* Load and stores */ + case OPC_LL: /* Load and stores */ + check_insn(ctx, ISA_MIPS2); + /* Fallthrough */ + case OPC_LWL: case OPC_LWR: - case OPC_LL: check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* Fallthrough */ case OPC_LB ... OPC_LH: case OPC_LW ... OPC_LHU: gen_ld(ctx, op, rt, rs, imm); @@ -18643,6 +18723,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) gen_st(ctx, op, rt, rs, imm); break; case OPC_SC: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_st_cond(ctx, op, rt, rs, imm); break; @@ -18686,6 +18767,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) case OPC_DMTC1: check_cp1_enabled(ctx); check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_cp1(ctx, op1, rt, rd); break; #endif @@ -18859,18 +18941,24 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) check_cp1_enabled(ctx); op1 = MASK_CP3(ctx->opcode); switch (op1) { + case OPC_LUXC1: + case OPC_SUXC1: + check_insn(ctx, ISA_MIPS5 | ISA_MIPS32R2); + /* Fallthrough */ case OPC_LWXC1: case OPC_LDXC1: - case OPC_LUXC1: case OPC_SWXC1: case OPC_SDXC1: - case OPC_SUXC1: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32R2); gen_flt3_ldst(ctx, op1, sa, rd, rs, rt); break; case OPC_PREFX: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32R2); /* Treat as NOP. */ break; case OPC_ALNV_PS: + check_insn(ctx, ISA_MIPS5 | ISA_MIPS32R2); + /* Fallthrough */ case OPC_MADD_S: case OPC_MADD_D: case OPC_MADD_PS: @@ -18883,6 +18971,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) case OPC_NMSUB_S: case OPC_NMSUB_D: case OPC_NMSUB_PS: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32R2); gen_flt3_arith(ctx, op1, sa, rs, rd, rt); break; default: From c48245f0c62405f27266fcf08722d8c290520418 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 19 Nov 2014 17:29:00 +0000 Subject: [PATCH 20/30] target-mips: Correct 32-bit address space wrapping Make sure the address space is unconditionally wrapped on 32-bit processors, that is ones that do not implement at least the MIPS III ISA. Also make MIPS16 SAVE and RESTORE instructions use address calculation rather than plain arithmetic operations for stack pointer manipulation so that their semantics for stack accesses follows the architecture specification. That in particular applies to user software run on 64-bit processors with the CP0.Status.UX bit clear where the address space is wrapped to 32 bits. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/cpu.h | 8 +++++--- target-mips/translate.c | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index e59cb4c6dc..f8cf143198 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -838,10 +838,12 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= MIPS_HFLAG_64; } - if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_UX))) { + if (!(env->insn_flags & ISA_MIPS3)) { env->hflags |= MIPS_HFLAG_AWRAP; - } else if (env->insn_flags & ISA_MIPS32R6) { + } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_UX))) { + env->hflags |= MIPS_HFLAG_AWRAP; + } else if (env->insn_flags & ISA_MIPS64R6) { /* Address wrapping for Supervisor and Kernel is specified in R6 */ if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) && !(env->CP0_Status & (1 << CP0St_SX))) || diff --git a/target-mips/translate.c b/target-mips/translate.c index 2173ea5222..9d90da0aad 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -10728,6 +10728,7 @@ static void gen_mips16_save (DisasContext *ctx, { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); int args, astatic; switch (aregs) { @@ -10786,7 +10787,8 @@ static void gen_mips16_save (DisasContext *ctx, gen_load_gpr(t0, 29); #define DECR_AND_STORE(reg) do { \ - tcg_gen_subi_tl(t0, t0, 4); \ + tcg_gen_movi_tl(t2, -4); \ + gen_op_addr_add(ctx, t0, t0, t2); \ gen_load_gpr(t1, reg); \ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); \ } while (0) @@ -10870,9 +10872,11 @@ static void gen_mips16_save (DisasContext *ctx, } #undef DECR_AND_STORE - tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize); + tcg_gen_movi_tl(t2, -framesize); + gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); tcg_temp_free(t0); tcg_temp_free(t1); + tcg_temp_free(t2); } static void gen_mips16_restore (DisasContext *ctx, @@ -10883,11 +10887,14 @@ static void gen_mips16_restore (DisasContext *ctx, int astatic; TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_gpr[29], framesize); + tcg_gen_movi_tl(t2, framesize); + gen_op_addr_add(ctx, t0, cpu_gpr[29], t2); #define DECR_AND_LOAD(reg) do { \ - tcg_gen_subi_tl(t0, t0, 4); \ + tcg_gen_movi_tl(t2, -4); \ + gen_op_addr_add(ctx, t0, t0, t2); \ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); \ gen_store_gpr(t1, reg); \ } while (0) @@ -10971,9 +10978,11 @@ static void gen_mips16_restore (DisasContext *ctx, } #undef DECR_AND_LOAD - tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize); + tcg_gen_movi_tl(t2, framesize); + gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); tcg_temp_free(t0); tcg_temp_free(t1); + tcg_temp_free(t2); } static void gen_addiupc (DisasContext *ctx, int rx, int imm, From cbb26c9a122c3f71fb53989817d406a2f6d08662 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 5 Dec 2014 18:46:04 +0000 Subject: [PATCH 21/30] target-mips: gdbstub: Clean up FPU register handling Rewrite the FPU register access parts of `mips_cpu_gdb_read_register' and `mips_cpu_gdb_write_register' for consistency between each other. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/gdbstub.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c index 964e6a7733..2f2ffd200d 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -29,8 +29,13 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) if (n < 32) { return gdb_get_regl(mem_buf, env->active_tc.gpr[n]); } - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - if (n >= 38 && n < 70) { + if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) { + switch (n) { + case 70: + return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31); + case 71: + return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0); + default: if (env->CP0_Status & (1 << CP0St_FR)) { return gdb_get_regl(mem_buf, env->active_fpu.fpr[n - 38].d); @@ -39,12 +44,6 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]); } } - switch (n) { - case 70: - return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31); - case 71: - return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0); - } } switch (n) { case 32: @@ -64,8 +63,10 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return gdb_get_regl(mem_buf, 0); /* fp */ case 89: return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid); - } - if (n >= 73 && n <= 88) { + default: + if (n > 89) { + return 0; + } /* 16 embedded regs. */ return gdb_get_regl(mem_buf, 0); } @@ -89,15 +90,7 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->active_tc.gpr[n] = tmp; return sizeof(target_ulong); } - if (env->CP0_Config1 & (1 << CP0C1_FP) - && n >= 38 && n < 72) { - if (n < 70) { - if (env->CP0_Status & (1 << CP0St_FR)) { - env->active_fpu.fpr[n - 38].d = tmp; - } else { - env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; - } - } + if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) { switch (n) { case 70: env->active_fpu.fcr31 = tmp & 0xFF83FFFF; @@ -107,6 +100,13 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) case 71: /* FIR is read-only. Ignore writes. */ break; + default: + if (env->CP0_Status & (1 << CP0St_FR)) { + env->active_fpu.fpr[n - 38].d = tmp; + } else { + env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; + } + break; } return sizeof(target_ulong); } From 1d725ae952a14b30c84b7bc81b218b8ba77dd311 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 20 Nov 2014 11:15:34 +0000 Subject: [PATCH 22/30] target-mips: Also apply the CP0.Status mask to MTTC0 Make CP0.Status writes made with the MTTC0 instruction respect this register's mask just like all the other places. Also preserve the current values of masked out bits. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/op_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1267ef297c..7e632f6875 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1413,9 +1413,10 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018; CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); - other->CP0_Status = arg1 & ~0xf1000018; + other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask); sync_c0_status(env, other, other_tc); } From 74797f40dc3e17633fea614f08c828020f755b28 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 20 Nov 2014 16:00:54 +0000 Subject: [PATCH 23/30] linux-user: Use the 5KEf processor for 64-bit emulation Replace the 20Kc original MIPS64 ISA processor used for 64-bit user emulation with the 5KEf processor that implements the MIPS64r2 ISA, complementing the choice of the 24Kf processor for 32-bit emulation. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 186ee4d54f..67b02316c1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3905,7 +3905,7 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_MIPS) #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) - cpu_model = "20Kc"; + cpu_model = "5KEf"; #else cpu_model = "24Kf"; #endif From bb962386b82c1b0e9e12fdb6b9bb62106bf1f822 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 2 Dec 2014 17:02:38 +0000 Subject: [PATCH 24/30] target-mips: Add missing calls to synchronise SoftFloat status Add missing calls to synchronise the SoftFloat status with the CP1.FSCR: + for the rounding and flush-to-zero modes upon processor reset, + for the flush-to-zero mode on FSCR updates through the GDB stub. Refactor code accordingly and remove the redundant RESTORE_ROUNDING_MODE macro. Signed-off-by: Thomas Schwinge Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/cpu.h | 12 ++++++++++++ target-mips/gdbstub.c | 8 +++----- target-mips/op_helper.c | 12 ------------ target-mips/translate.c | 2 ++ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f8cf143198..8875c975e0 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -777,6 +777,18 @@ target_ulong exception_resume_pc (CPUMIPSState *env); extern unsigned int ieee_rm[]; int ieee_ex_to_mips(int xcpt); +static inline void restore_rounding_mode(CPUMIPSState *env) +{ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], + &env->active_fpu.fp_status); +} + +static inline void restore_flush_mode(CPUMIPSState *env) +{ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, + &env->active_fpu.fp_status); +} + 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 2f2ffd200d..9845d880ae 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -74,10 +74,6 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return 0; } -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \ - &env->active_fpu.fp_status) - int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { MIPSCPU *cpu = MIPS_CPU(cs); @@ -95,7 +91,9 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) case 70: env->active_fpu.fcr31 = tmp & 0xFF83FFFF; /* set rounding mode */ - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); + /* set flush-to-zero mode */ + restore_flush_mode(env); break; case 71: /* FIR is read-only. Ignore writes. */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 7e632f6875..d619ba4785 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2280,18 +2280,6 @@ unsigned int ieee_rm[] = { float_round_down }; -static inline void restore_rounding_mode(CPUMIPSState *env) -{ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], - &env->active_fpu.fp_status); -} - -static inline void restore_flush_mode(CPUMIPSState *env) -{ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, - &env->active_fpu.fp_status); -} - target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { target_ulong arg1 = 0; diff --git a/target-mips/translate.c b/target-mips/translate.c index 9d90da0aad..571b7d7bec 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -19617,6 +19617,8 @@ void cpu_state_reset(CPUMIPSState *env) } compute_hflags(env); + restore_rounding_mode(env); + restore_flush_mode(env); cs->exception_index = EXCP_NONE; } From 1a4d570017bf35d99340781ecb59dd3772464031 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 2 Dec 2014 17:51:12 +0000 Subject: [PATCH 25/30] target-mips: Use local float status pointer across MSA macros Reduce line wrapping throughout MSA helper macros by using a local float status pointer rather than referring to the float status through the environment each time. No functional change. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/msa_helper.c | 69 ++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index b08f37f787..6e07f6ede3 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -1782,15 +1782,14 @@ static inline int32 float64_to_q32(float64 a STATUS_PARAM) #define MSA_FLOAT_COND(DEST, OP, ARG1, ARG2, BITS, QUIET) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ int64_t cond; \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ if (!QUIET) { \ - cond = float ## BITS ## _ ## OP(ARG1, ARG2, \ - &env->active_tc.msa_fp_status); \ + cond = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ } else { \ - cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, \ - &env->active_tc.msa_fp_status); \ + cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, status); \ } \ DEST = cond ? M_MAX_UINT(BITS) : 0; \ c = update_msacsr(env, CLEAR_IS_INEXACT, 0); \ @@ -2375,11 +2374,11 @@ void helper_msa_fsne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ 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); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2511,11 +2510,11 @@ void helper_msa_fdiv_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ 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); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, status); \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2630,10 +2629,11 @@ void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_UNOP(DEST, OP, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG, status); \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2678,10 +2678,11 @@ void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG, status); \ c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2728,11 +2729,11 @@ void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ 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); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ c = update_msacsr(env, 0, 0); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2924,10 +2925,11 @@ void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df, #define MSA_FLOAT_UNOP0(DEST, OP, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG, status); \ c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -3029,11 +3031,11 @@ void helper_msa_fsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_RECIPROCAL(DEST, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ 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); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, status); \ c = update_msacsr(env, float ## BITS ## _is_infinity(ARG) || \ float ## BITS ## _is_quiet_nan(DEST) ? \ 0 : RECIPROCAL_INEXACT, \ @@ -3138,23 +3140,20 @@ void helper_msa_frint_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_LOGB(DEST, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ 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_exception_flags(0, status); \ + set_float_rounding_mode(float_round_down, status); \ + DEST = float ## BITS ## _ ## log2(ARG, status); \ + DEST = float ## BITS ## _ ## round_to_int(DEST, status); \ set_float_rounding_mode(ieee_rm[(env->active_tc.msacsr & \ MSACSR_RM_MASK) >> MSACSR_RM], \ - &env->active_tc.msa_fp_status); \ + status); \ \ - set_float_exception_flags( \ - get_float_exception_flags(&env->active_tc.msa_fp_status) \ - & (~float_flag_inexact), \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(get_float_exception_flags(status) & \ + (~float_flag_inexact), \ + status); \ \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ From 66991d1103562591eba6b801049720976317fe61 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 2 Dec 2014 22:31:33 +0000 Subject: [PATCH 26/30] target-mips: Fix DisasContext's ulri member initialization Set DisasContext's ulri member to 0 or 1 as with other bool members. Signed-off-by: Maciej W. Rozycki Reviewed-by: Leon Alrae Signed-off-by: Leon Alrae --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 571b7d7bec..f65ed84b6b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -19116,7 +19116,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, 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); + ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; restore_cpu_state(env, &ctx); #ifdef CONFIG_USER_ONLY ctx.mem_idx = MIPS_HFLAG_UM; From 00fb4a118142650e7fa3d5007b197bc11fec6ea9 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Wed, 10 Dec 2014 15:39:42 +0000 Subject: [PATCH 27/30] target-mips: convert single case switch into if statement Signed-off-by: Leon Alrae Reviewed-by: Peter Maydell --- target-mips/translate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index f65ed84b6b..1205909f78 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1882,10 +1882,8 @@ static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n, \ { \ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ - switch (ifmt) { \ - case FMT_D: \ + if (ifmt == FMT_D) { \ check_cp1_registers(ctx, fs | ft | fd); \ - break; \ } \ gen_ldcmp_fpr ## bits(ctx, fp0, fs); \ gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ From 8e5f7570448185297917d82d61ffbe27eff47a01 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Wed, 10 Dec 2014 15:48:02 +0000 Subject: [PATCH 28/30] disas/mips: remove unused mips_msa_control_names_numeric[32] Signed-off-by: Leon Alrae Reviewed-by: Peter Maydell --- disas/mips.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/disas/mips.c b/disas/mips.c index 2614c52a4b..b94d5d9edd 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -3801,13 +3801,6 @@ 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", From 8ef39152636d27b0d3340fcf030c3edb85a436cb Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 12 Dec 2014 16:12:11 +0000 Subject: [PATCH 29/30] disas/mips: disable unused mips16_to_32_reg_map[] This array is used by print_mips16_insn_arg() which is guarded by #if 0. Therefore doing the same with the array as it generates clang warnings. Signed-off-by: Leon Alrae --- disas/mips.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disas/mips.c b/disas/mips.c index b94d5d9edd..1afe0c5511 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -3511,6 +3511,7 @@ struct mips_cp0sel_name const char * const name; }; +#if 0 /* The mips16 registers. */ static const unsigned int mips16_to_32_reg_map[] = { @@ -3518,7 +3519,7 @@ static const unsigned int mips16_to_32_reg_map[] = }; #define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] - +#endif static const char * const mips_gpr_names_numeric[32] = { From d4fa5354a246a1c6cb538a5d8ebcc21206d502fb Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Wed, 10 Dec 2014 16:30:59 +0000 Subject: [PATCH 30/30] target-mips: remove excp_names[] from linux-user as it is unused Signed-off-by: Leon Alrae Reviewed-by: Peter Maydell --- target-mips/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index c4b3658098..7d26705cb5 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -388,7 +388,6 @@ hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int r return physical; } } -#endif static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_RESET] = "reset", @@ -429,6 +428,7 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_MSADIS] = "MSA disabled", [EXCP_MSAFPE] = "MSA floating point", }; +#endif target_ulong exception_resume_pc (CPUMIPSState *env) {