mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-30 23:10:38 +00:00
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:
parent
4296f45902
commit
a4bb6c3e87
@ -2365,51 +2365,27 @@ void OPPROTO op_wrte (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_booke_tlbre0 (void)
|
||||
void OPPROTO op_440_tlbre (void)
|
||||
{
|
||||
do_booke_tlbre0();
|
||||
do_440_tlbre(PARAM1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_booke_tlbre1 (void)
|
||||
void OPPROTO op_440_tlbsx (void)
|
||||
{
|
||||
do_booke_tlbre1();
|
||||
do_440_tlbsx();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_booke_tlbre2 (void)
|
||||
void OPPROTO op_440_tlbsx_ (void)
|
||||
{
|
||||
do_booke_tlbre2();
|
||||
do_440_tlbsx_();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_booke_tlbsx (void)
|
||||
void OPPROTO op_440_tlbwe (void)
|
||||
{
|
||||
do_booke_tlbsx();
|
||||
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();
|
||||
do_440_tlbwe(PARAM1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -2607,95 +2607,79 @@ void do_4xx_tlbwe_lo (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* BookE TLB management */
|
||||
void do_booke_tlbwe0 (void)
|
||||
/* PowerPC 440 TLB management */
|
||||
void do_440_tlbwe (int word)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_ulong EPN, size;
|
||||
target_ulong EPN, RPN, size;
|
||||
int do_flush_tlbs;
|
||||
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
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
|
||||
do_flush_tlbs = 0;
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
EPN = T1 & 0xFFFFFC00;
|
||||
if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
|
||||
do_flush_tlbs = 1;
|
||||
tlb->EPN = EPN;
|
||||
size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
|
||||
if ((tlb->prot & PAGE_VALID) && tlb->size < size)
|
||||
do_flush_tlbs = 1;
|
||||
tlb->size = size;
|
||||
tlb->attr &= ~0x1;
|
||||
tlb->attr |= (T1 >> 8) & 1;
|
||||
if (T1 & 0x200) {
|
||||
tlb->prot |= PAGE_VALID;
|
||||
} else {
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
tlb->prot &= ~PAGE_VALID;
|
||||
switch (word) {
|
||||
default:
|
||||
/* Just here to please gcc */
|
||||
case 0:
|
||||
EPN = T1 & 0xFFFFFC00;
|
||||
if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
|
||||
do_flush_tlbs = 1;
|
||||
tlb->EPN = EPN;
|
||||
size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
|
||||
if ((tlb->prot & PAGE_VALID) && tlb->size < size)
|
||||
do_flush_tlbs = 1;
|
||||
tlb->size = size;
|
||||
tlb->attr &= ~0x1;
|
||||
tlb->attr |= (T1 >> 8) & 1;
|
||||
if (T1 & 0x200) {
|
||||
tlb->prot |= PAGE_VALID;
|
||||
} else {
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
tlb->prot &= ~PAGE_VALID;
|
||||
do_flush_tlbs = 1;
|
||||
}
|
||||
}
|
||||
tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
|
||||
if (do_flush_tlbs)
|
||||
tlb_flush(env, 1);
|
||||
break;
|
||||
case 1:
|
||||
RPN = T1 & 0xFFFFFC0F;
|
||||
if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
|
||||
tlb_flush(env, 1);
|
||||
tlb->RPN = RPN;
|
||||
break;
|
||||
case 2:
|
||||
tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
|
||||
tlb->prot = tlb->prot & PAGE_VALID;
|
||||
if (T1 & 0x1)
|
||||
tlb->prot |= PAGE_READ << 4;
|
||||
if (T1 & 0x2)
|
||||
tlb->prot |= PAGE_WRITE << 4;
|
||||
if (T1 & 0x4)
|
||||
tlb->prot |= PAGE_EXEC << 4;
|
||||
if (T1 & 0x8)
|
||||
tlb->prot |= PAGE_READ;
|
||||
if (T1 & 0x10)
|
||||
tlb->prot |= PAGE_WRITE;
|
||||
if (T1 & 0x20)
|
||||
tlb->prot |= PAGE_EXEC;
|
||||
break;
|
||||
}
|
||||
tlb->PID = env->spr[SPR_BOOKE_PID];
|
||||
if (do_flush_tlbs)
|
||||
tlb_flush(env, 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;
|
||||
if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
|
||||
tlb_flush(env, 1);
|
||||
tlb->RPN = RPN;
|
||||
}
|
||||
|
||||
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->prot = tlb->prot & PAGE_VALID;
|
||||
if (T1 & 0x1)
|
||||
tlb->prot |= PAGE_READ << 4;
|
||||
if (T1 & 0x2)
|
||||
tlb->prot |= PAGE_WRITE << 4;
|
||||
if (T1 & 0x4)
|
||||
tlb->prot |= PAGE_EXEC << 4;
|
||||
if (T1 & 0x8)
|
||||
tlb->prot |= PAGE_READ;
|
||||
if (T1 & 0x10)
|
||||
tlb->prot |= PAGE_WRITE;
|
||||
if (T1 & 0x20)
|
||||
tlb->prot |= PAGE_EXEC;
|
||||
}
|
||||
|
||||
void do_booke_tlbsx (void)
|
||||
void do_440_tlbsx (void)
|
||||
{
|
||||
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;
|
||||
|
||||
@ -2705,52 +2689,47 @@ void do_booke_tlbsx_ (void)
|
||||
env->crf[0] = tmp;
|
||||
}
|
||||
|
||||
void do_booke_tlbre0 (void)
|
||||
void do_440_tlbre (int word)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
int size;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
T0 = tlb->EPN;
|
||||
size = booke_page_size_to_tlb(tlb->size);
|
||||
if (size < 0 || size > 0xF)
|
||||
size = 1;
|
||||
T0 |= size << 4;
|
||||
if (tlb->attr & 0x1)
|
||||
T0 |= 0x100;
|
||||
if (tlb->prot & PAGE_VALID)
|
||||
T0 |= 0x200;
|
||||
env->spr[SPR_BOOKE_PID] = tlb->PID;
|
||||
}
|
||||
|
||||
void do_booke_tlbre1 (void)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
T0 = tlb->RPN;
|
||||
}
|
||||
|
||||
void do_booke_tlbre2 (void)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
T0 = tlb->attr & ~0x1;
|
||||
if (tlb->prot & (PAGE_READ << 4))
|
||||
T0 |= 0x1;
|
||||
if (tlb->prot & (PAGE_WRITE << 4))
|
||||
T0 |= 0x2;
|
||||
if (tlb->prot & (PAGE_EXEC << 4))
|
||||
T0 |= 0x4;
|
||||
if (tlb->prot & PAGE_READ)
|
||||
T0 |= 0x8;
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
T0 |= 0x10;
|
||||
if (tlb->prot & PAGE_EXEC)
|
||||
T0 |= 0x20;
|
||||
switch (word) {
|
||||
default:
|
||||
/* Just here to please gcc */
|
||||
case 0:
|
||||
T0 = tlb->EPN;
|
||||
size = booke_page_size_to_tlb(tlb->size);
|
||||
if (size < 0 || size > 0xF)
|
||||
size = 1;
|
||||
T0 |= size << 4;
|
||||
if (tlb->attr & 0x1)
|
||||
T0 |= 0x100;
|
||||
if (tlb->prot & PAGE_VALID)
|
||||
T0 |= 0x200;
|
||||
env->spr[SPR_440_MMUCR] &= ~0x000000FF;
|
||||
env->spr[SPR_440_MMUCR] |= tlb->PID;
|
||||
break;
|
||||
case 1:
|
||||
T0 = tlb->RPN;
|
||||
break;
|
||||
case 2:
|
||||
T0 = tlb->attr & ~0x1;
|
||||
if (tlb->prot & (PAGE_READ << 4))
|
||||
T0 |= 0x1;
|
||||
if (tlb->prot & (PAGE_WRITE << 4))
|
||||
T0 |= 0x2;
|
||||
if (tlb->prot & (PAGE_EXEC << 4))
|
||||
T0 |= 0x4;
|
||||
if (tlb->prot & PAGE_READ)
|
||||
T0 |= 0x8;
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
T0 |= 0x10;
|
||||
if (tlb->prot & PAGE_EXEC)
|
||||
T0 |= 0x20;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -156,16 +156,12 @@ void do_POWER_rfsvc (void);
|
||||
void do_op_602_mfrom (void);
|
||||
#endif
|
||||
|
||||
/* PowerPC BookE specific helpers */
|
||||
/* PowerPC 440 specific helpers */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void do_booke_tlbre0 (void);
|
||||
void do_booke_tlbre1 (void);
|
||||
void do_booke_tlbre2 (void);
|
||||
void do_booke_tlbsx (void);
|
||||
void do_booke_tlbsx_ (void);
|
||||
void do_booke_tlbwe0 (void);
|
||||
void do_booke_tlbwe1 (void);
|
||||
void do_booke_tlbwe2 (void);
|
||||
void do_440_tlbre (int word);
|
||||
void do_440_tlbsx (void);
|
||||
void do_440_tlbsx_ (void);
|
||||
void do_440_tlbwe (int word);
|
||||
#endif
|
||||
|
||||
/* PowerPC 4xx specific helpers */
|
||||
|
@ -4695,9 +4695,9 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* TLB management - PowerPC BookE implementation */
|
||||
/* TLB management - PowerPC 440 implementation */
|
||||
/* 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)
|
||||
RET_PRIVOPC(ctx);
|
||||
@ -4708,18 +4708,10 @@ GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
|
||||
}
|
||||
switch (rB(ctx->opcode)) {
|
||||
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:
|
||||
gen_op_load_gpr_T0(rA(ctx->opcode));
|
||||
gen_op_booke_tlbre1();
|
||||
gen_op_store_T0_gpr(rD(ctx->opcode));
|
||||
break;
|
||||
case 2:
|
||||
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));
|
||||
break;
|
||||
default:
|
||||
@ -4730,7 +4722,7 @@ GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
RET_PRIVOPC(ctx);
|
||||
@ -4741,15 +4733,15 @@ GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
|
||||
}
|
||||
gen_addr_reg_index(ctx);
|
||||
if (Rc(ctx->opcode))
|
||||
gen_op_booke_tlbsx_();
|
||||
gen_op_440_tlbsx_();
|
||||
else
|
||||
gen_op_booke_tlbsx();
|
||||
gen_op_440_tlbsx();
|
||||
gen_op_store_T0_gpr(rD(ctx->opcode));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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)
|
||||
RET_PRIVOPC(ctx);
|
||||
@ -4760,19 +4752,11 @@ GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
|
||||
}
|
||||
switch (rB(ctx->opcode)) {
|
||||
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:
|
||||
gen_op_load_gpr_T0(rA(ctx->opcode));
|
||||
gen_op_load_gpr_T1(rS(ctx->opcode));
|
||||
gen_op_booke_tlbwe1();
|
||||
break;
|
||||
case 2:
|
||||
gen_op_load_gpr_T0(rA(ctx->opcode));
|
||||
gen_op_load_gpr_T1(rS(ctx->opcode));
|
||||
gen_op_booke_tlbwe2();
|
||||
gen_op_440_tlbwe(rB(ctx->opcode));
|
||||
break;
|
||||
default:
|
||||
RET_INVAL(ctx);
|
||||
|
Loading…
Reference in New Issue
Block a user