* [Qemu-devel] [PATCH v3 01/15] target-mips: add KScratch registers
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 02/15] softmmu: provide softmmu access type enum Leon Alrae
` (13 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
KScratch<n> 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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 26e7894..91e781e 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 446eb8a..167f9bc 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);
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 02/15] softmmu: provide softmmu access type enum
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 01/15] target-mips: add KScratch registers Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 13:59 ` Thomas Huth
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 03/15] target-mips: distinguish between data load and instruction fetch Leon Alrae
` (12 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
New MIPS features depend on the access type and enum is more convenient than
using the numbers directly.
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
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 e3ec4c8..427b851 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 88e3390..6b4e615 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
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [Qemu-devel] [PATCH v3 02/15] softmmu: provide softmmu access type enum
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 02/15] softmmu: provide softmmu access type enum Leon Alrae
@ 2014-10-24 13:59 ` Thomas Huth
0 siblings, 0 replies; 22+ messages in thread
From: Thomas Huth @ 2014-10-24 13:59 UTC (permalink / raw)
To: Leon Alrae; +Cc: qemu-devel, aurelien
On Fri, 24 Oct 2014 13:42:16 +0100
Leon Alrae <leon.alrae@imgtec.com> wrote:
> New MIPS features depend on the access type and enum is more convenient than
> using the numbers directly.
>
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
> 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 e3ec4c8..427b851 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 88e3390..6b4e615 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
>
I very much like the idea to get rid of these "magic" numbers!
Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 03/15] target-mips: distinguish between data load and instruction fetch
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 01/15] target-mips: add KScratch registers Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 02/15] softmmu: provide softmmu access type enum Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 04/15] target-mips: add RI and XI fields to TLB entry Leon Alrae
` (11 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 fe16820..1c9e69d 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,
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 04/15] target-mips: add RI and XI fields to TLB entry
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (2 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 03/15] target-mips: distinguish between data load and instruction fetch Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 14:29 ` Yongbok Kim
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 05/15] target-mips: update PageGrain and m{t, f}c0 EntryLo{0, 1} Leon Alrae
` (10 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
---
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 91e781e..13f3a48 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 1c9e69d..49187a3 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 5204ed8..ca65ab4 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);
}
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [Qemu-devel] [PATCH v3 04/15] target-mips: add RI and XI fields to TLB entry
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 04/15] target-mips: add RI and XI fields to TLB entry Leon Alrae
@ 2014-10-24 14:29 ` Yongbok Kim
0 siblings, 0 replies; 22+ messages in thread
From: Yongbok Kim @ 2014-10-24 14:29 UTC (permalink / raw)
To: Leon Alrae, qemu-devel; +Cc: aurelien
On 24/10/2014 13:42, Leon Alrae wrote:
> 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 <leon.alrae@imgtec.com>
> ---
> 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 91e781e..13f3a48 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 1c9e69d..49187a3 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 5204ed8..ca65ab4 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);
> }
>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
Regards,
Yongbok
^ permalink raw reply [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 05/15] target-mips: update PageGrain and m{t, f}c0 EntryLo{0, 1}
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (3 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 04/15] target-mips: add RI and XI fields to TLB entry Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 06/15] target-mips: add new Read-Inhibit and Execute-Inhibit exceptions Leon Alrae
` (9 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 13f3a48..38f90f2 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 a127db5..e7e0c8c 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 ca65ab4..4727e9c 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 167f9bc..e8933a9 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 67b7837..779afff 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;
};
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 06/15] target-mips: add new Read-Inhibit and Execute-Inhibit exceptions
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (4 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 05/15] target-mips: update PageGrain and m{t, f}c0 EntryLo{0, 1} Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 07/15] target-mips: add TLBINV support Leon Alrae
` (8 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 38f90f2..a9e1bc2 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 49187a3..37038ef 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;
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 07/15] target-mips: add TLBINV support
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (5 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 06/15] target-mips: add new Read-Inhibit and Execute-Inhibit exceptions Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 08/15] target-mips: add BadInstr and BadInstrP support Leon Alrae
` (7 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 7297825..4974bc0 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 a9e1bc2..9c38b4f 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 37038ef..05325d9 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 e7e0c8c..aea12a9 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 4727e9c..43a441a 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 e8933a9..fdb61be 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 779afff..bcfc46a 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)
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 08/15] target-mips: add BadInstr and BadInstrP support
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (6 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 07/15] target-mips: add TLBINV support Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-29 13:55 ` Yongbok Kim
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 09/15] target-mips: update cpu_save/cpu_load to support new registers Leon Alrae
` (6 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
---
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 9c38b4f..4687f4f 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 05325d9..c92b25c 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 43a441a..6c87a1f 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 fdb61be..3e6e990 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);
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [Qemu-devel] [PATCH v3 08/15] target-mips: add BadInstr and BadInstrP support
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 08/15] target-mips: add BadInstr and BadInstrP support Leon Alrae
@ 2014-10-29 13:55 ` Yongbok Kim
2014-11-01 19:27 ` Leon Alrae
0 siblings, 1 reply; 22+ messages in thread
From: Yongbok Kim @ 2014-10-29 13:55 UTC (permalink / raw)
To: Leon Alrae, qemu-devel; +Cc: aurelien
On 24/10/2014 13:42, Leon Alrae wrote:
> 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 <leon.alrae@imgtec.com>
> ---
> 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 9c38b4f..4687f4f 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 05325d9..c92b25c 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;
TLBXI requires updating the register.
DSPDIS might also.
> @@ -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 43a441a..6c87a1f 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 fdb61be..3e6e990 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);
otherwise,
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
Regards,
Yongbok
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [Qemu-devel] [PATCH v3 08/15] target-mips: add BadInstr and BadInstrP support
2014-10-29 13:55 ` Yongbok Kim
@ 2014-11-01 19:27 ` Leon Alrae
0 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-11-01 19:27 UTC (permalink / raw)
To: Yongbok Kim; +Cc: qemu-devel, aurelien
Hi Yongbok,
On 29/10/14 13:55, Yongbok Kim wrote:
> On 24/10/2014 13:42, Leon Alrae wrote:
>> case EXCP_TLBRI:
>> cause = 19;
>> + update_badinstr = 1;
>> goto set_EPC;
>> case EXCP_TLBXI:
>> cause = 20;
>
> TLBXI requires updating the register.
TLBXI exception can be generated by instruction fetch or MIPS16
PC-relative load. IIUC if TLBXI is caused by instruction fetch the value
stored in BadInstr is unpredictable as valid instruction word is not
available (the same case as TLB Refill - Instruction Fetch). Therefore
in context of Release 6 the implementation is correct. As far as MIPS16
is concerned, this is similar limitation which we discussed for patch #4
(i.e. MIPS16 PC-relative load should ignore RI bit).
Regards,
Leon
^ permalink raw reply [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 09/15] target-mips: update cpu_save/cpu_load to support new registers
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (7 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 08/15] target-mips: add BadInstr and BadInstrP support Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-29 14:02 ` Yongbok Kim
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 10/15] target-mips: add Config5.SBRI Leon Alrae
` (5 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
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 4687f4f..c66a725 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 0496faa..0ba7d73 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++) {
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [Qemu-devel] [PATCH v3 09/15] target-mips: update cpu_save/cpu_load to support new registers
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 09/15] target-mips: update cpu_save/cpu_load to support new registers Leon Alrae
@ 2014-10-29 14:02 ` Yongbok Kim
0 siblings, 0 replies; 22+ messages in thread
From: Yongbok Kim @ 2014-10-29 14:02 UTC (permalink / raw)
To: Leon Alrae, qemu-devel; +Cc: aurelien
On 24/10/2014 13:42, Leon Alrae wrote:
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
> 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 4687f4f..c66a725 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 0496faa..0ba7d73 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++) {
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
Regards,
Yongbok
^ permalink raw reply [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 10/15] target-mips: add Config5.SBRI
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (8 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 09/15] target-mips: update cpu_save/cpu_load to support new registers Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 11/15] target-mips: implement forbidden slot Leon Alrae
` (4 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 c66a725..ce9a7a2 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 3e6e990..c7a8bbc 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:
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 11/15] target-mips: implement forbidden slot
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (9 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 10/15] target-mips: add Config5.SBRI Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 12/15] target-mips: CP0_Status.CU0 no longer allows the user to access CP0 Leon Alrae
` (3 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 ce9a7a2..6367d8c 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 c7a8bbc..a383a5c 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;
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 12/15] target-mips: CP0_Status.CU0 no longer allows the user to access CP0
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (10 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 11/15] target-mips: implement forbidden slot Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 13/15] target-mips: add restrictions for possible values in registers Leon Alrae
` (2 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 6367d8c..3b975eb 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;
}
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 13/15] target-mips: add restrictions for possible values in registers
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (11 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 12/15] target-mips: CP0_Status.CU0 no longer allows the user to access CP0 Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-29 11:04 ` Yongbok Kim
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 14/15] target-mips: correctly handle access to unimplemented CP0 register Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 15/15] target-mips: enable features in MIPS64R6-generic CPU Leon Alrae
14 siblings, 1 reply; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
---
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 6c87a1f..c6de86e 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;
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [Qemu-devel] [PATCH v3 13/15] target-mips: add restrictions for possible values in registers
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 13/15] target-mips: add restrictions for possible values in registers Leon Alrae
@ 2014-10-29 11:04 ` Yongbok Kim
0 siblings, 0 replies; 22+ messages in thread
From: Yongbok Kim @ 2014-10-29 11:04 UTC (permalink / raw)
To: Leon Alrae, qemu-devel; +Cc: aurelien
On 24/10/2014 13:42, Leon Alrae wrote:
> 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 <leon.alrae@imgtec.com>
> ---
> 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 6c87a1f..c6de86e 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;
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
Regards,
Yongbok
^ permalink raw reply [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 14/15] target-mips: correctly handle access to unimplemented CP0 register
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (12 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 13/15] target-mips: add restrictions for possible values in registers Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 15/15] target-mips: enable features in MIPS64R6-generic CPU Leon Alrae
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
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 <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 a383a5c..9a8f5c9 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 */
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [Qemu-devel] [PATCH v3 15/15] target-mips: enable features in MIPS64R6-generic CPU
2014-10-24 12:42 [Qemu-devel] [PATCH v3 00/15] target-mips: add features required in MIPS64R6 Leon Alrae
` (13 preceding siblings ...)
2014-10-24 12:42 ` [Qemu-devel] [PATCH v3 14/15] target-mips: correctly handle access to unimplemented CP0 register Leon Alrae
@ 2014-10-24 12:42 ` Leon Alrae
14 siblings, 0 replies; 22+ messages in thread
From: Leon Alrae @ 2014-10-24 12:42 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
---
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 bcfc46a..0b70d05 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),
--
2.1.0
^ permalink raw reply related [flat|nested] 22+ messages in thread