PowerPC 601 need specific callbacks for its BATs setup.

Implement PowerPC 601 HID0 register, needed for little-endian mode support.
As a consequence, we need to merge hflags coming from MSR with other ones.
Use little-endian mode from hflags instead of MSR during code translation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3524 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
j_mayer 2007-11-04 02:55:33 +00:00
parent 7a51ad822f
commit 056401eae6
8 changed files with 136 additions and 35 deletions

View File

@ -651,7 +651,8 @@ struct CPUPPCState {
/* Those resources are used only in Qemu core */
jmp_buf jmp_env;
int user_mode_only; /* user mode only simulation */
target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
target_ulong hflags_nmsr; /* specific hflags, not comming from MSR */
int mmu_idx; /* precomputed MMU index to speed up mem accesses */
/* Power management */
@ -698,6 +699,8 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr);
target_ulong do_load_dbatl (CPUPPCState *env, int nr);
void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value);
void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value);
target_ulong do_load_sdr1 (CPUPPCState *env);
void do_store_sdr1 (CPUPPCState *env, target_ulong value);
#if defined(TARGET_PPC64)

View File

@ -482,10 +482,12 @@ static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp,
int key, pp, valid, prot;
bl = (*BATl & 0x0000003F) << 17;
#if defined (DEBUG_BATS)
if (loglevel != 0) {
fprintf(logfile, "b %02x ==> bl %08x msk %08x\n",
*BATl & 0x0000003F, bl, ~bl);
}
#endif
prot = 0;
valid = (*BATl >> 6) & 1;
if (valid) {
@ -1836,6 +1838,76 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
env->DBAT[1][nr] = value;
}
void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
int do_inval;
dump_store_bat(env, 'I', 0, nr, value);
if (env->IBAT[0][nr] != value) {
do_inval = 0;
mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
if (env->IBAT[1][nr] & 0x40) {
/* Invalidate BAT only if it is valid */
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
do_inval = 1;
#endif
}
/* When storing valid upper BAT, mask BEPI and BRPN
* and invalidate all TLBs covered by this BAT
*/
env->IBAT[0][nr] = (value & 0x00001FFFUL) |
(value & ~0x0001FFFFUL & ~mask);
env->DBAT[0][nr] = env->IBAT[0][nr];
if (env->IBAT[1][nr] & 0x40) {
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
do_inval = 1;
#endif
}
#if defined(FLUSH_ALL_TLBS)
if (do_inval)
tlb_flush(env, 1);
#endif
}
}
void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
int do_inval;
dump_store_bat(env, 'I', 1, nr, value);
if (env->IBAT[1][nr] != value) {
do_inval = 0;
if (env->IBAT[1][nr] & 0x40) {
#if !defined(FLUSH_ALL_TLBS)
mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
do_inval = 1;
#endif
}
if (value & 0x40) {
#if !defined(FLUSH_ALL_TLBS)
mask = (value << 17) & 0x0FFE0000UL;
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
do_inval = 1;
#endif
}
env->IBAT[1][nr] = value;
env->DBAT[1][nr] = value;
#if defined(FLUSH_ALL_TLBS)
if (do_inval)
tlb_flush(env, 1);
#endif
}
}
/*****************************************************************************/
/* TLB management */
void ppc_tlb_invalidate_all (CPUPPCState *env)
@ -2684,6 +2756,7 @@ static always_inline void powerpc_excp (CPUState *env,
* any special case that could occur. Just store MSR and update hflags
*/
env->msr = new_msr;
env->hflags_nmsr = 0x00000000;
hreg_compute_hflags(env);
env->nip = vector;
/* Reset exception state */

View File

@ -58,6 +58,17 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env)
env->tgpr[3] = tmp;
}
static always_inline void hreg_compute_mem_idx (CPUPPCState *env)
{
#if defined (TARGET_PPC64H)
/* Precompute MMU index */
if (msr_pr == 0 && msr_hv != 0)
env->mmu_idx = 2;
else
#endif
env->mmu_idx = 1 - msr_pr;
}
static always_inline void hreg_compute_hflags (CPUPPCState *env)
{
target_ulong hflags_mask;
@ -70,14 +81,12 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env)
hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF);
#if defined (TARGET_PPC64H)
hflags_mask |= 1ULL << MSR_HV;
/* Precompute MMU index */
if (msr_pr == 0 && msr_hv != 0)
env->mmu_idx = 2;
else
#endif
#endif
env->mmu_idx = 1 - msr_pr;
hreg_compute_mem_idx(env);
env->hflags = env->msr & hflags_mask;
/* Merge with hflags coming from other registers */
env->hflags |= env->hflags_nmsr;
}
static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value)

View File

@ -2190,30 +2190,27 @@ void OPPROTO op_store_601_rtcu (void)
RETURN();
}
void OPPROTO op_store_hid0_601 (void)
{
do_store_hid0_601();
RETURN();
}
void OPPROTO op_load_601_bat (void)
{
T0 = env->IBAT[PARAM1][PARAM2];
RETURN();
}
#endif /* !defined(CONFIG_USER_ONLY) */
/* 601 unified BATs store.
* To avoid using specific MMU code for 601, we store BATs in
* IBAT and DBAT simultaneously, then emulate unified BATs.
*/
#if !defined(CONFIG_USER_ONLY)
void OPPROTO op_store_601_batl (void)
{
int nr = PARAM1;
env->IBAT[1][nr] = T0;
env->DBAT[1][nr] = T0;
do_store_ibatl_601(env, PARAM1, T0);
RETURN();
}
void OPPROTO op_store_601_batu (void)
{
do_store_601_batu(PARAM1);
do_store_ibatu_601(env, PARAM1, T0);
RETURN();
}
#endif /* !defined(CONFIG_USER_ONLY) */

View File

@ -1701,12 +1701,23 @@ void do_POWER_rfsvc (void)
__do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
}
/* PowerPC 601 BAT management helper */
void do_store_601_batu (int nr)
void do_store_hid0_601 (void)
{
do_store_ibatu(env, nr, (uint32_t)T0);
env->DBAT[0][nr] = env->IBAT[0][nr];
env->DBAT[1][nr] = env->IBAT[1][nr];
uint32_t hid0;
hid0 = env->spr[SPR_HID0];
if ((T0 ^ hid0) & 0x00000008) {
/* Change current endianness */
env->hflags &= ~(1 << MSR_LE);
env->hflags_nmsr &= ~(1 << MSR_LE);
env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE);
env->hflags |= env->hflags_nmsr;
if (loglevel != 0) {
fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
__func__, T0 & 0x8 ? 'l' : 'b', env->hflags);
}
}
env->spr[SPR_HID0] = T0;
}
#endif

View File

@ -155,7 +155,6 @@ void do_load_74xx_tlb (int is_code);
#endif
/* POWER / PowerPC 601 specific helpers */
void do_store_601_batu (int nr);
void do_POWER_abso (void);
void do_POWER_clcs (void);
void do_POWER_div (void);
@ -168,6 +167,7 @@ void do_POWER_mulo (void);
#if !defined(CONFIG_USER_ONLY)
void do_POWER_rac (void);
void do_POWER_rfsvc (void);
void do_store_hid0_601 (void);
#endif
/* PowerPC 602 specific helper */

View File

@ -6801,7 +6801,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
opc_handler_t **table, *handler;
target_ulong pc_start;
uint16_t *gen_opc_end;
int supervisor;
int supervisor, little_endian;
int single_step, branch_step;
int j, lj = -1;
@ -6821,11 +6821,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
#if !defined(CONFIG_USER_ONLY)
ctx.supervisor = supervisor;
#endif
little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0;
#if defined(TARGET_PPC64)
ctx.sf_mode = msr_sf;
ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | msr_le;
ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian;
#else
ctx.mem_idx = (supervisor << 1) | msr_le;
ctx.mem_idx = (supervisor << 1) | little_endian;
#endif
ctx.dcache_line_size = env->dcache_line_size;
ctx.fpu_enabled = msr_fp;
@ -6880,18 +6881,16 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
ctx.nip, supervisor, (int)msr_ir);
}
#endif
ctx.opcode = ldl_code(ctx.nip);
if (msr_le) {
ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
((ctx.opcode & 0x00FF0000) >> 8) |
((ctx.opcode & 0x0000FF00) << 8) |
((ctx.opcode & 0x000000FF) << 24);
if (unlikely(little_endian)) {
ctx.opcode = bswap32(ldl_code(ctx.nip));
} else {
ctx.opcode = ldl_code(ctx.nip);
}
#if defined PPC_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
opc3(ctx.opcode), msr_le ? "little" : "big");
opc3(ctx.opcode), little_endian ? "little" : "big");
}
#endif
ctx.nip += 4;
@ -6986,7 +6985,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
if (loglevel & CPU_LOG_TB_IN_ASM) {
int flags;
flags = env->bfd_mach;
flags |= msr_le << 16;
flags |= little_endian << 16;
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
fprintf(logfile, "\n");

View File

@ -314,6 +314,15 @@ static void spr_write_601_rtcl (void *opaque, int sprn)
{
gen_op_store_601_rtcl();
}
static void spr_write_hid0_601 (void *opaque, int sprn)
{
DisasContext *ctx = opaque;
gen_op_store_hid0_601();
/* Must stop the translation as endianness may have changed */
GEN_STOP(ctx);
}
#endif
/* Unified bats */
@ -3259,7 +3268,7 @@ static void init_proc_601 (CPUPPCState *env)
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
&spr_read_generic, &spr_write_hid0_601,
0x80010080);
/* XXX : not implemented */
spr_register(env, SPR_HID1, "HID1",