target-mips: add CP0.PageGrain.ELPA support

CP0.PageGrain.ELPA enables support for large physical addresses. This field
is encoded as follows:
0: Large physical address support is disabled.
1: Large physical address support is enabled.

If this bit is a 1, the following changes occur to coprocessor 0 registers:
- The PFNX field of the EntryLo0 and EntryLo1 registers is writable and
  concatenated with the PFN field to form the full page frame number.
- Access to optional COP0 registers with PA extension, LLAddr, TagLo is
  defined.

P5600 can operate in 32-bit or 40-bit Physical Address Mode. Therefore if
XPA is disabled (CP0.PageGrain.ELPA = 0) then assume 32-bit Address Mode.
In MIPS64 assume 36 as default PABITS (when CP0.PageGrain.ELPA = 0).

env->PABITS value is constant and indicates maximum PABITS available on
a core, whereas env->PAMask is calculated from env->PABITS and is also
affected by CP0.PageGrain.ELPA.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
Leon Alrae 2015-04-14 10:09:38 +01:00
parent cd0d45c401
commit e117f52636
5 changed files with 42 additions and 12 deletions

View File

@ -224,8 +224,14 @@ struct CPUMIPSState {
uint32_t SEGBITS; uint32_t SEGBITS;
uint32_t PABITS; uint32_t PABITS;
#if defined(TARGET_MIPS64)
# define PABITS_BASE 36
#else
# define PABITS_BASE 32
#endif
target_ulong SEGMask; target_ulong SEGMask;
uint64_t PAMask; uint64_t PAMask;
#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1)
int32_t msair; int32_t msair;
#define MSAIR_ProcID 8 #define MSAIR_ProcID 8
@ -289,6 +295,7 @@ struct CPUMIPSState {
int32_t CP0_PageGrain; int32_t CP0_PageGrain;
#define CP0PG_RIE 31 #define CP0PG_RIE 31
#define CP0PG_XIE 30 #define CP0PG_XIE 30
#define CP0PG_ELPA 29
#define CP0PG_IEC 27 #define CP0PG_IEC 27
int32_t CP0_Wired; int32_t CP0_Wired;
int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0_rw_bitmask;
@ -518,7 +525,7 @@ struct CPUMIPSState {
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
uint32_t hflags; /* CPU State */ uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */ /* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0x35807FF #define MIPS_HFLAG_TMASK 0x75807FF
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */ #define MIPS_HFLAG_MODE 0x00007 /* execution modes */
/* The KSU flags must be the lowest bits in hflags. The flag order /* 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 must be the same as defined for CP0 Status. This allows to use
@ -566,6 +573,7 @@ struct CPUMIPSState {
#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ #define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */
#define MIPS_HFLAG_MSA 0x1000000 #define MIPS_HFLAG_MSA 0x1000000
#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */ #define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */
#define MIPS_HFLAG_ELPA 0x4000000
target_ulong btarget; /* Jump / branch target */ target_ulong btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */ target_ulong bcond; /* Branch condition (if needed) */
@ -801,6 +809,15 @@ static inline void restore_msa_fp_status(CPUMIPSState *env)
set_flush_inputs_to_zero(flush_to_zero, status); set_flush_inputs_to_zero(flush_to_zero, status);
} }
static inline void restore_pamask(CPUMIPSState *env)
{
if (env->hflags & MIPS_HFLAG_ELPA) {
env->PAMask = (1ULL << env->PABITS) - 1;
} else {
env->PAMask = PAMASK_BASE;
}
}
static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
target_ulong *cs_base, int *flags) target_ulong *cs_base, int *flags)
{ {
@ -848,7 +865,8 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | 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 | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE); MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
MIPS_HFLAG_ELPA);
if (!(env->CP0_Status & (1 << CP0St_EXL)) && if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) && !(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM)) { !(env->hflags & MIPS_HFLAG_DM)) {
@ -934,6 +952,11 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags |= MIPS_HFLAG_FRE; env->hflags |= MIPS_HFLAG_FRE;
} }
} }
if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
env->hflags |= MIPS_HFLAG_ELPA;
}
}
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY

View File

@ -10,6 +10,7 @@ static int cpu_post_load(void *opaque, int version_id)
restore_fp_status(env); restore_fp_status(env);
restore_msa_fp_status(env); restore_msa_fp_status(env);
compute_hflags(env); compute_hflags(env);
restore_pamask(env);
return 0; return 0;
} }

View File

@ -10,11 +10,11 @@
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
#define TARGET_LONG_BITS 64 #define TARGET_LONG_BITS 64
#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_PHYS_ADDR_SPACE_BITS 48
#define TARGET_VIRT_ADDR_SPACE_BITS 42 #define TARGET_VIRT_ADDR_SPACE_BITS 42
#else #else
#define TARGET_LONG_BITS 32 #define TARGET_LONG_BITS 32
#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_PHYS_ADDR_SPACE_BITS 40
#define TARGET_VIRT_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif #endif

View File

@ -1068,19 +1068,23 @@ void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
env->CP0_VPEOpt = arg1 & 0x0000ffff; env->CP0_VPEOpt = arg1 & 0x0000ffff;
} }
#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
{ {
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
| (rxi << (CP0EnLo_XI - 30));
} }
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1) void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
{ {
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi; env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
} }
#endif #endif
@ -1246,17 +1250,17 @@ void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
{ {
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
| (rxi << (CP0EnLo_XI - 30));
} }
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1) void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
{ {
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi; env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
} }
#endif #endif
@ -1279,10 +1283,11 @@ void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
{ {
/* SmartMIPS not implemented */ /* SmartMIPS not implemented */
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) | env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
(env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask); (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
compute_hflags(env);
restore_pamask(env);
} }
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)

View File

@ -5699,6 +5699,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
check_insn(ctx, ISA_MIPS32R2); check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_pagegrain(cpu_env, arg); gen_helper_mtc0_pagegrain(cpu_env, arg);
rn = "PageGrain"; rn = "PageGrain";
ctx->bstate = BS_STOP;
break; break;
default: default:
goto cp0_unimplemented; goto cp0_unimplemented;
@ -19578,7 +19579,6 @@ void cpu_state_reset(CPUMIPSState *env)
} }
#endif #endif
env->PABITS = env->cpu_model->PABITS; env->PABITS = env->cpu_model->PABITS;
env->PAMask = (1ULL << env->cpu_model->PABITS) - 1;
env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask; env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0; env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask; env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
@ -19699,6 +19699,7 @@ void cpu_state_reset(CPUMIPSState *env)
compute_hflags(env); compute_hflags(env);
restore_rounding_mode(env); restore_rounding_mode(env);
restore_flush_mode(env); restore_flush_mode(env);
restore_pamask(env);
cs->exception_index = EXCP_NONE; cs->exception_index = EXCP_NONE;
} }