Rework PowerPC 440 TLB management (thanks to Hollis Blanchard)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3200 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
j_mayer 2007-09-21 05:28:33 +00:00
parent 4296f45902
commit a4bb6c3e87
4 changed files with 110 additions and 175 deletions

View file

@ -2365,51 +2365,27 @@ void OPPROTO op_wrte (void)
RETURN(); RETURN();
} }
void OPPROTO op_booke_tlbre0 (void) void OPPROTO op_440_tlbre (void)
{ {
do_booke_tlbre0(); do_440_tlbre(PARAM1);
RETURN(); RETURN();
} }
void OPPROTO op_booke_tlbre1 (void) void OPPROTO op_440_tlbsx (void)
{ {
do_booke_tlbre1(); do_440_tlbsx();
RETURN(); RETURN();
} }
void OPPROTO op_booke_tlbre2 (void) void OPPROTO op_440_tlbsx_ (void)
{ {
do_booke_tlbre2(); do_440_tlbsx_();
RETURN(); RETURN();
} }
void OPPROTO op_booke_tlbsx (void) void OPPROTO op_440_tlbwe (void)
{ {
do_booke_tlbsx(); do_440_tlbwe(PARAM1);
RETURN();
}
void OPPROTO op_booke_tlbsx_ (void)
{
do_booke_tlbsx_();
RETURN();
}
void OPPROTO op_booke_tlbwe0 (void)
{
do_booke_tlbwe0();
RETURN();
}
void OPPROTO op_booke_tlbwe1 (void)
{
do_booke_tlbwe1();
RETURN();
}
void OPPROTO op_booke_tlbwe2 (void)
{
do_booke_tlbwe2();
RETURN(); RETURN();
} }

View file

@ -2607,21 +2607,26 @@ void do_4xx_tlbwe_lo (void)
#endif #endif
} }
/* BookE TLB management */ /* PowerPC 440 TLB management */
void do_booke_tlbwe0 (void) void do_440_tlbwe (int word)
{ {
ppcemb_tlb_t *tlb; ppcemb_tlb_t *tlb;
target_ulong EPN, size; target_ulong EPN, RPN, size;
int do_flush_tlbs; int do_flush_tlbs;
#if defined (DEBUG_SOFTWARE_TLB) #if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) { if (loglevel != 0) {
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n",
__func__, word, T0, T1);
} }
#endif #endif
do_flush_tlbs = 0; do_flush_tlbs = 0;
T0 &= 0x3F; T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe; tlb = &env->tlb[T0].tlbe;
switch (word) {
default:
/* Just here to please gcc */
case 0:
EPN = T1 & 0xFFFFFC00; EPN = T1 & 0xFFFFFC00;
if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
do_flush_tlbs = 1; do_flush_tlbs = 1;
@ -2640,40 +2645,17 @@ void do_booke_tlbwe0 (void)
do_flush_tlbs = 1; do_flush_tlbs = 1;
} }
} }
tlb->PID = env->spr[SPR_BOOKE_PID]; tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
if (do_flush_tlbs) if (do_flush_tlbs)
tlb_flush(env, 1); tlb_flush(env, 1);
} break;
case 1:
void do_booke_tlbwe1 (void)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t RPN;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
}
#endif
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
RPN = T1 & 0xFFFFFC0F; RPN = T1 & 0xFFFFFC0F;
if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
tlb_flush(env, 1); tlb_flush(env, 1);
tlb->RPN = RPN; tlb->RPN = RPN;
} break;
case 2:
void do_booke_tlbwe2 (void)
{
ppcemb_tlb_t *tlb;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
}
#endif
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00); tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
tlb->prot = tlb->prot & PAGE_VALID; tlb->prot = tlb->prot & PAGE_VALID;
if (T1 & 0x1) if (T1 & 0x1)
@ -2688,14 +2670,16 @@ void do_booke_tlbwe2 (void)
tlb->prot |= PAGE_WRITE; tlb->prot |= PAGE_WRITE;
if (T1 & 0x20) if (T1 & 0x20)
tlb->prot |= PAGE_EXEC; tlb->prot |= PAGE_EXEC;
break;
}
} }
void do_booke_tlbsx (void) void do_440_tlbsx (void)
{ {
T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]);
} }
void do_booke_tlbsx_ (void) void do_440_tlbsx_ (void)
{ {
int tmp = xer_so; int tmp = xer_so;
@ -2705,13 +2689,17 @@ void do_booke_tlbsx_ (void)
env->crf[0] = tmp; env->crf[0] = tmp;
} }
void do_booke_tlbre0 (void) void do_440_tlbre (int word)
{ {
ppcemb_tlb_t *tlb; ppcemb_tlb_t *tlb;
int size; int size;
T0 &= 0x3F; T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe; tlb = &env->tlb[T0].tlbe;
switch (word) {
default:
/* Just here to please gcc */
case 0:
T0 = tlb->EPN; T0 = tlb->EPN;
size = booke_page_size_to_tlb(tlb->size); size = booke_page_size_to_tlb(tlb->size);
if (size < 0 || size > 0xF) if (size < 0 || size > 0xF)
@ -2721,24 +2709,13 @@ void do_booke_tlbre0 (void)
T0 |= 0x100; T0 |= 0x100;
if (tlb->prot & PAGE_VALID) if (tlb->prot & PAGE_VALID)
T0 |= 0x200; T0 |= 0x200;
env->spr[SPR_BOOKE_PID] = tlb->PID; env->spr[SPR_440_MMUCR] &= ~0x000000FF;
} env->spr[SPR_440_MMUCR] |= tlb->PID;
break;
void do_booke_tlbre1 (void) case 1:
{
ppcemb_tlb_t *tlb;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->RPN; T0 = tlb->RPN;
} break;
case 2:
void do_booke_tlbre2 (void)
{
ppcemb_tlb_t *tlb;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->attr & ~0x1; T0 = tlb->attr & ~0x1;
if (tlb->prot & (PAGE_READ << 4)) if (tlb->prot & (PAGE_READ << 4))
T0 |= 0x1; T0 |= 0x1;
@ -2752,5 +2729,7 @@ void do_booke_tlbre2 (void)
T0 |= 0x10; T0 |= 0x10;
if (tlb->prot & PAGE_EXEC) if (tlb->prot & PAGE_EXEC)
T0 |= 0x20; T0 |= 0x20;
break;
}
} }
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */

View file

@ -156,16 +156,12 @@ void do_POWER_rfsvc (void);
void do_op_602_mfrom (void); void do_op_602_mfrom (void);
#endif #endif
/* PowerPC BookE specific helpers */ /* PowerPC 440 specific helpers */
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void do_booke_tlbre0 (void); void do_440_tlbre (int word);
void do_booke_tlbre1 (void); void do_440_tlbsx (void);
void do_booke_tlbre2 (void); void do_440_tlbsx_ (void);
void do_booke_tlbsx (void); void do_440_tlbwe (int word);
void do_booke_tlbsx_ (void);
void do_booke_tlbwe0 (void);
void do_booke_tlbwe1 (void);
void do_booke_tlbwe2 (void);
#endif #endif
/* PowerPC 4xx specific helpers */ /* PowerPC 4xx specific helpers */

View file

@ -4695,9 +4695,9 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
#endif #endif
} }
/* TLB management - PowerPC BookE implementation */ /* TLB management - PowerPC 440 implementation */
/* tlbre */ /* tlbre */
GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
{ {
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
@ -4708,18 +4708,10 @@ GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
} }
switch (rB(ctx->opcode)) { switch (rB(ctx->opcode)) {
case 0: case 0:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_booke_tlbre0();
gen_op_store_T0_gpr(rD(ctx->opcode));
break;
case 1: case 1:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_booke_tlbre1();
gen_op_store_T0_gpr(rD(ctx->opcode));
break;
case 2: case 2:
gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_booke_tlbre2(); gen_op_440_tlbre(rB(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode));
break; break;
default: default:
@ -4730,7 +4722,7 @@ GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
} }
/* tlbsx - tlbsx. */ /* tlbsx - tlbsx. */
GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
{ {
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
@ -4741,15 +4733,15 @@ GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
} }
gen_addr_reg_index(ctx); gen_addr_reg_index(ctx);
if (Rc(ctx->opcode)) if (Rc(ctx->opcode))
gen_op_booke_tlbsx_(); gen_op_440_tlbsx_();
else else
gen_op_booke_tlbsx(); gen_op_440_tlbsx();
gen_op_store_T0_gpr(rD(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode));
#endif #endif
} }
/* tlbwe */ /* tlbwe */
GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
{ {
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
@ -4760,19 +4752,11 @@ GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
} }
switch (rB(ctx->opcode)) { switch (rB(ctx->opcode)) {
case 0: case 0:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_booke_tlbwe0();
break;
case 1: case 1:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_booke_tlbwe1();
break;
case 2: case 2:
gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode)); gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_booke_tlbwe2(); gen_op_440_tlbwe(rB(ctx->opcode));
break; break;
default: default:
RET_INVAL(ctx); RET_INVAL(ctx);