target-ppc: convert SLB/TLB instructions to TCG

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5895 c046a42c-6fe2-441c-8c8c-71466251a162
master
aurel32 2008-12-06 21:46:17 +00:00
parent 331dadde19
commit 74d37793f4
7 changed files with 272 additions and 332 deletions

View File

@ -582,7 +582,7 @@ struct CPUPPCState {
#endif
/* segment registers */
target_ulong sdr1;
target_ulong sr[16];
target_ulong sr[32];
/* BATs */
int nb_BATs;
target_ulong DBAT[2][8];

View File

@ -2110,13 +2110,6 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value)
}
}
#if 0 // Unused
target_ulong do_load_sr (CPUPPCState *env, int srnum)
{
return env->sr[srnum];
}
#endif
void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
{
#if defined (DEBUG_MMU)

View File

@ -163,10 +163,28 @@ DEF_HELPER_2(efdcmpgt, i32, i64, i64)
DEF_HELPER_2(efdcmpeq, i32, i64, i64)
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_1(load_6xx_tlbd, void, tl)
DEF_HELPER_1(load_6xx_tlbi, void, tl)
DEF_HELPER_1(load_74xx_tlbd, void, tl)
DEF_HELPER_1(load_74xx_tlbi, void, tl)
DEF_HELPER_1(4xx_tlbre_hi, tl, tl)
DEF_HELPER_1(4xx_tlbre_lo, tl, tl)
DEF_HELPER_2(4xx_tlbwe_hi, void, tl, tl)
DEF_HELPER_2(4xx_tlbwe_lo, void, tl, tl)
DEF_HELPER_1(4xx_tlbsx, tl, tl)
DEF_HELPER_2(440_tlbre, tl, i32, tl)
DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
DEF_HELPER_1(440_tlbsx, tl, tl)
DEF_HELPER_1(6xx_tlbd, void, tl)
DEF_HELPER_1(6xx_tlbi, void, tl)
DEF_HELPER_1(74xx_tlbd, void, tl)
DEF_HELPER_1(74xx_tlbi, void, tl)
DEF_HELPER_0(tlbia, void)
DEF_HELPER_1(tlbie, void, tl)
#if defined(TARGET_PPC64)
DEF_HELPER_1(load_slb, tl, tl)
DEF_HELPER_2(store_slb, void, tl, tl)
DEF_HELPER_0(slbia, void)
DEF_HELPER_1(slbie, void, tl)
#endif
DEF_HELPER_1(load_sr, tl, tl);
DEF_HELPER_2(store_sr, void, tl, tl);
DEF_HELPER_1(602_mfrom, tl, tl)
#endif

View File

@ -27,33 +27,6 @@
#include "op_helper.h"
#if !defined(CONFIG_USER_ONLY)
/* Segment registers load and store */
void OPPROTO op_load_sr (void)
{
T0 = env->sr[T1];
RETURN();
}
void OPPROTO op_store_sr (void)
{
do_store_sr(env, T1, T0);
RETURN();
}
#if defined(TARGET_PPC64)
void OPPROTO op_load_slb (void)
{
T0 = ppc_load_slb(env, T1);
RETURN();
}
void OPPROTO op_store_slb (void)
{
ppc_store_slb(env, T1, T0);
RETURN();
}
#endif /* defined(TARGET_PPC64) */
void OPPROTO op_load_sdr1 (void)
{
T0 = env->sdr1;
@ -218,13 +191,6 @@ void OPPROTO op_store_dbatl (void)
}
#endif /* !defined(CONFIG_USER_ONLY) */
/*** Integer shift ***/
void OPPROTO op_srli_T1 (void)
{
T1 = (uint32_t)T1 >> PARAM1;
RETURN();
}
/* Return from interrupt */
#if !defined(CONFIG_USER_ONLY)
/* Exception vectors */
@ -243,50 +209,6 @@ void OPPROTO op_store_excp_vector (void)
}
#endif
#if !defined(CONFIG_USER_ONLY)
/* tlbia */
void OPPROTO op_tlbia (void)
{
ppc_tlb_invalidate_all(env);
RETURN();
}
/* tlbie */
void OPPROTO op_tlbie (void)
{
ppc_tlb_invalidate_one(env, (uint32_t)T0);
RETURN();
}
#if defined(TARGET_PPC64)
void OPPROTO op_tlbie_64 (void)
{
ppc_tlb_invalidate_one(env, T0);
RETURN();
}
#endif
#if defined(TARGET_PPC64)
void OPPROTO op_slbia (void)
{
ppc_slb_invalidate_all(env);
RETURN();
}
void OPPROTO op_slbie (void)
{
ppc_slb_invalidate_one(env, (uint32_t)T0);
RETURN();
}
void OPPROTO op_slbie_64 (void)
{
ppc_slb_invalidate_one(env, T0);
RETURN();
}
#endif
#endif
/* 601 specific */
void OPPROTO op_load_601_rtcl (void)
{
@ -338,78 +260,6 @@ void OPPROTO op_store_601_batu (void)
}
#endif /* !defined(CONFIG_USER_ONLY) */
/* POWER instructions not implemented in PowerPC 601 */
#if !defined(CONFIG_USER_ONLY)
void OPPROTO op_POWER_mfsri (void)
{
T1 = T0 >> 28;
T0 = env->sr[T1];
RETURN();
}
#endif
/* PowerPC 4xx specific micro-ops */
#if !defined(CONFIG_USER_ONLY)
void OPPROTO op_440_tlbre (void)
{
do_440_tlbre(PARAM1);
RETURN();
}
void OPPROTO op_440_tlbsx (void)
{
T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF);
RETURN();
}
void OPPROTO op_4xx_tlbsx_check (void)
{
int tmp;
tmp = xer_so;
if ((int)T0 != -1)
tmp |= 0x02;
env->crf[0] = tmp;
RETURN();
}
void OPPROTO op_440_tlbwe (void)
{
do_440_tlbwe(PARAM1);
RETURN();
}
void OPPROTO op_4xx_tlbre_lo (void)
{
do_4xx_tlbre_lo();
RETURN();
}
void OPPROTO op_4xx_tlbre_hi (void)
{
do_4xx_tlbre_hi();
RETURN();
}
void OPPROTO op_4xx_tlbsx (void)
{
T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]);
RETURN();
}
void OPPROTO op_4xx_tlbwe_lo (void)
{
do_4xx_tlbwe_lo();
RETURN();
}
void OPPROTO op_4xx_tlbwe_hi (void)
{
do_4xx_tlbwe_hi();
RETURN();
}
#endif
/* SPR micro-ops */
/* 440 specific */
#if !defined(CONFIG_USER_ONLY)

View File

@ -2552,9 +2552,55 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
env = saved_env;
}
/* Segment registers load and store */
target_ulong helper_load_sr (target_ulong sr_num)
{
return env->sr[sr_num];
}
void helper_store_sr (target_ulong sr_num, target_ulong val)
{
do_store_sr(env, sr_num, val);
}
/* SLB management */
#if defined(TARGET_PPC64)
target_ulong helper_load_slb (target_ulong slb_nr)
{
return ppc_load_slb(env, slb_nr);
}
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
{
ppc_store_slb(env, slb_nr, rs);
}
void helper_slbia (void)
{
ppc_slb_invalidate_all(env);
}
void helper_slbie (target_ulong addr)
{
ppc_slb_invalidate_one(env, addr);
}
#endif /* defined(TARGET_PPC64) */
/* TLB management */
void helper_tlbia (void)
{
ppc_tlb_invalidate_all(env);
}
void helper_tlbie (target_ulong addr)
{
ppc_tlb_invalidate_one(env, addr);
}
/* Software driven TLBs management */
/* PowerPC 602/603 software TLB load instructions helpers */
static void helper_load_6xx_tlb (target_ulong new_EPN, int is_code)
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
{
target_ulong RPN, CMP, EPN;
int way;
@ -2580,18 +2626,18 @@ static void helper_load_6xx_tlb (target_ulong new_EPN, int is_code)
way, is_code, CMP, RPN);
}
void helper_load_6xx_tlbd (target_ulong EPN)
void helper_6xx_tlbd (target_ulong EPN)
{
helper_load_6xx_tlb(EPN, 0);
do_6xx_tlb(EPN, 0);
}
void helper_load_6xx_tlbi (target_ulong EPN)
void helper_6xx_tlbi (target_ulong EPN)
{
helper_load_6xx_tlb(EPN, 1);
do_6xx_tlb(EPN, 1);
}
/* PowerPC 74xx software TLB load instructions helpers */
static void helper_load_74xx_tlb (target_ulong new_EPN, int is_code)
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
{
target_ulong RPN, CMP, EPN;
int way;
@ -2612,14 +2658,14 @@ static void helper_load_74xx_tlb (target_ulong new_EPN, int is_code)
way, is_code, CMP, RPN);
}
void helper_load_74xx_tlbd (target_ulong EPN)
void helper_74xx_tlbd (target_ulong EPN)
{
helper_load_74xx_tlb(EPN, 0);
do_74xx_tlb(EPN, 0);
}
void helper_load_74xx_tlbi (target_ulong EPN)
void helper_74xx_tlbi (target_ulong EPN)
{
helper_load_74xx_tlb(EPN, 1);
do_74xx_tlb(EPN, 1);
}
static always_inline target_ulong booke_tlb_to_page_size (int size)
@ -2691,81 +2737,85 @@ static always_inline int booke_page_size_to_tlb (target_ulong page_size)
}
/* Helpers for 4xx TLB management */
void do_4xx_tlbre_lo (void)
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
int size;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->EPN;
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
ret = tlb->EPN;
if (tlb->prot & PAGE_VALID)
T0 |= 0x400;
ret |= 0x400;
size = booke_page_size_to_tlb(tlb->size);
if (size < 0 || size > 0x7)
size = 1;
T0 |= size << 7;
ret |= size << 7;
env->spr[SPR_40x_PID] = tlb->PID;
return ret;
}
void do_4xx_tlbre_hi (void)
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->RPN;
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
ret = tlb->RPN;
if (tlb->prot & PAGE_EXEC)
T0 |= 0x200;
ret |= 0x200;
if (tlb->prot & PAGE_WRITE)
T0 |= 0x100;
ret |= 0x100;
return ret;
}
void do_4xx_tlbwe_hi (void)
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
{
ppcemb_tlb_t *tlb;
target_ulong page, end;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
fprintf(logfile, "%s entry " TDX " val " TDX "\n", __func__, entry, val);
}
#endif
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
/* Invalidate previous TLB (if it's valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
" end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
" end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
}
#endif
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
}
tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
/* We cannot handle TLB size < TARGET_PAGE_SIZE.
* If this ever occurs, one should use the ppcemb target instead
* of the ppc or ppc64 one
*/
if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
"are not supported (%d)\n",
tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
}
tlb->EPN = T1 & ~(tlb->size - 1);
if (T1 & 0x40)
tlb->EPN = val & ~(tlb->size - 1);
if (val & 0x40)
tlb->prot |= PAGE_VALID;
else
tlb->prot &= ~PAGE_VALID;
if (T1 & 0x20) {
if (val & 0x20) {
/* XXX: TO BE FIXED */
cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
}
tlb->PID = env->spr[SPR_40x_PID]; /* PID */
tlb->attr = T1 & 0xFF;
tlb->attr = val & 0xFF;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
@ -2791,28 +2841,28 @@ void do_4xx_tlbwe_hi (void)
}
}
void do_4xx_tlbwe_lo (void)
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
{
ppcemb_tlb_t *tlb;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
fprintf(logfile, "%s entry " TDX " val " TDX "\n", __func__, entry, val);
}
#endif
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
tlb->RPN = T1 & 0xFFFFFC00;
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
tlb->RPN = val & 0xFFFFFC00;
tlb->prot = PAGE_READ;
if (T1 & 0x200)
if (val & 0x200)
tlb->prot |= PAGE_EXEC;
if (T1 & 0x100)
if (val & 0x100)
tlb->prot |= PAGE_WRITE;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
" size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
(int)T0, tlb->RPN, tlb->EPN, tlb->size,
(int)entry, tlb->RPN, tlb->EPN, tlb->size,
tlb->prot & PAGE_READ ? 'r' : '-',
tlb->prot & PAGE_WRITE ? 'w' : '-',
tlb->prot & PAGE_EXEC ? 'x' : '-',
@ -2821,8 +2871,13 @@ void do_4xx_tlbwe_lo (void)
#endif
}
target_ulong helper_4xx_tlbsx (target_ulong address)
{
return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
}
/* PowerPC 440 TLB management */
void do_440_tlbwe (int word)
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
{
ppcemb_tlb_t *tlb;
target_ulong EPN, RPN, size;
@ -2830,28 +2885,28 @@ void do_440_tlbwe (int word)
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s word %d T0 " TDX " T1 " TDX "\n",
__func__, word, T0, T1);
fprintf(logfile, "%s word %d entry " TDX " value " TDX "\n",
__func__, word, entry, value);
}
#endif
do_flush_tlbs = 0;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
switch (word) {
default:
/* Just here to please gcc */
case 0:
EPN = T1 & 0xFFFFFC00;
EPN = value & 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);
size = booke_tlb_to_page_size((value >> 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->attr |= (value >> 8) & 1;
if (value & 0x200) {
tlb->prot |= PAGE_VALID;
} else {
if (tlb->prot & PAGE_VALID) {
@ -2864,71 +2919,79 @@ void do_440_tlbwe (int word)
tlb_flush(env, 1);
break;
case 1:
RPN = T1 & 0xFFFFFC0F;
RPN = value & 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->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
tlb->prot = tlb->prot & PAGE_VALID;
if (T1 & 0x1)
if (value & 0x1)
tlb->prot |= PAGE_READ << 4;
if (T1 & 0x2)
if (value & 0x2)
tlb->prot |= PAGE_WRITE << 4;
if (T1 & 0x4)
if (value & 0x4)
tlb->prot |= PAGE_EXEC << 4;
if (T1 & 0x8)
if (value & 0x8)
tlb->prot |= PAGE_READ;
if (T1 & 0x10)
if (value & 0x10)
tlb->prot |= PAGE_WRITE;
if (T1 & 0x20)
if (value & 0x20)
tlb->prot |= PAGE_EXEC;
break;
}
}
void do_440_tlbre (int word)
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
int size;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
switch (word) {
default:
/* Just here to please gcc */
case 0:
T0 = tlb->EPN;
ret = tlb->EPN;
size = booke_page_size_to_tlb(tlb->size);
if (size < 0 || size > 0xF)
size = 1;
T0 |= size << 4;
ret |= size << 4;
if (tlb->attr & 0x1)
T0 |= 0x100;
ret |= 0x100;
if (tlb->prot & PAGE_VALID)
T0 |= 0x200;
ret |= 0x200;
env->spr[SPR_440_MMUCR] &= ~0x000000FF;
env->spr[SPR_440_MMUCR] |= tlb->PID;
break;
case 1:
T0 = tlb->RPN;
ret = tlb->RPN;
break;
case 2:
T0 = tlb->attr & ~0x1;
ret = tlb->attr & ~0x1;
if (tlb->prot & (PAGE_READ << 4))
T0 |= 0x1;
ret |= 0x1;
if (tlb->prot & (PAGE_WRITE << 4))
T0 |= 0x2;
ret |= 0x2;
if (tlb->prot & (PAGE_EXEC << 4))
T0 |= 0x4;
ret |= 0x4;
if (tlb->prot & PAGE_READ)
T0 |= 0x8;
ret |= 0x8;
if (tlb->prot & PAGE_WRITE)
T0 |= 0x10;
ret |= 0x10;
if (tlb->prot & PAGE_EXEC)
T0 |= 0x20;
ret |= 0x20;
break;
}
return ret;
}
target_ulong helper_440_tlbsx (target_ulong address)
{
return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
}
#endif /* !CONFIG_USER_ONLY */

View File

@ -34,20 +34,6 @@ void do_POWER_rac (void);
void do_store_hid0_601 (void);
#endif
/* PowerPC 440 specific helpers */
#if !defined(CONFIG_USER_ONLY)
void do_440_tlbre (int word);
void do_440_tlbwe (int word);
#endif
/* PowerPC 4xx specific helpers */
#if !defined(CONFIG_USER_ONLY)
void do_4xx_tlbre_lo (void);
void do_4xx_tlbre_hi (void);
void do_4xx_tlbwe_lo (void);
void do_4xx_tlbwe_hi (void);
#endif
/* PowerPC 403 specific helpers */
#if !defined(CONFIG_USER_ONLY)
void do_load_403_pb (int num);

View File

@ -4208,13 +4208,14 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
gen_op_load_sr();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
#endif
}
@ -4224,14 +4225,16 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_srli_T1(28);
gen_op_load_sr();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
#endif
}
@ -4241,13 +4244,14 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
gen_op_store_sr();
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@ -4257,14 +4261,16 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_srli_T1(28);
gen_op_store_sr();
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_store_sr(t0, cpu_gpr[rD(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@ -4276,13 +4282,14 @@ GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
gen_op_load_slb();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_load_slb(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
#endif
}
@ -4293,14 +4300,16 @@ GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_srli_T1(28);
gen_op_load_slb();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_load_slb(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
#endif
}
@ -4310,13 +4319,14 @@ GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
gen_op_store_slb();
t0 = tcg_const_tl(SR(ctx->opcode));
gen_helper_store_slb(t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@ -4327,14 +4337,16 @@ GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVREG(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVREG(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
gen_op_srli_T1(28);
gen_op_store_slb();
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_store_slb(t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
#endif /* defined(TARGET_PPC64) */
@ -4351,7 +4363,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_tlbia();
gen_helper_tlbia();
#endif
}
@ -4365,13 +4377,15 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
GEN_EXCP_PRIVOPC(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
gen_op_tlbie_64();
else
if (!ctx->sf_mode) {
TCGv t0 = tcg_temp_new();
tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
gen_helper_tlbie(t0);
tcg_temp_free(t0);
} else
#endif
gen_op_tlbie();
gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
#endif
}
@ -4403,7 +4417,7 @@ GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_op_slbia();
gen_helper_slbia();
#endif
}
@ -4417,8 +4431,7 @@ GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
GEN_EXCP_PRIVOPC(ctx);
return;
}
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
gen_op_slbie();
gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]);
#endif
}
#endif
@ -5129,7 +5142,7 @@ GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_helper_load_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
#endif
}
@ -5143,7 +5156,7 @@ GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_helper_load_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
gen_helper_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
#endif
}
@ -5158,7 +5171,7 @@ GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_helper_load_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
gen_helper_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
#endif
}
@ -5172,7 +5185,7 @@ GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_helper_load_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
gen_helper_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
#endif
}
@ -5208,18 +5221,21 @@ GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
#else
int ra = rA(ctx->opcode);
int rd = rD(ctx->opcode);
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVOPC(ctx);
return;
}
int ra = rA(ctx->opcode);
int rd = rD(ctx->opcode);
gen_addr_reg_index(cpu_T[0], ctx);
gen_op_POWER_mfsri();
tcg_gen_mov_tl(cpu_gpr[rd], cpu_T[0]);
t0 = tcg_temp_new();
gen_addr_reg_index(t0, ctx);
tcg_gen_shri_tl(t0, t0, 28);
tcg_gen_andi_tl(t0, t0, 0xF);
gen_helper_load_sr(cpu_gpr[rd], t0);
tcg_temp_free(t0);
if (ra != 0 && ra != rd)
tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[1]);
tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
#endif
}
@ -5389,18 +5405,18 @@ GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(cpu_T[0], ctx);
/* Use the same micro-ops as for tlbie */
gen_addr_reg_index(t0, ctx);
#if defined(TARGET_PPC64)
if (ctx->sf_mode)
gen_op_tlbie_64();
else
if (!ctx->sf_mode)
tcg_gen_ext32u_tl(t0, t0);
#endif
gen_op_tlbie();
gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@ -5861,14 +5877,10 @@ GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
}
switch (rB(ctx->opcode)) {
case 0:
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_4xx_tlbre_hi();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
break;
case 1:
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_4xx_tlbre_lo();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
break;
default:
GEN_EXCP_INVAL(ctx);
@ -5883,15 +5895,24 @@ GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(cpu_T[0], ctx);
gen_op_4xx_tlbsx();
if (Rc(ctx->opcode))
gen_op_4xx_tlbsx_check();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_temp_new();
gen_addr_reg_index(t0, ctx);
gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
if (Rc(ctx->opcode)) {
int l1 = gen_new_label();
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
gen_set_label(l1);
}
#endif
}
@ -5907,14 +5928,10 @@ GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
}
switch (rB(ctx->opcode)) {
case 0:
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
gen_op_4xx_tlbwe_hi();
gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
break;
case 1:
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
gen_op_4xx_tlbwe_lo();
gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
break;
default:
GEN_EXCP_INVAL(ctx);
@ -5938,9 +5955,11 @@ GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
case 0:
case 1:
case 2:
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
gen_op_440_tlbre(rB(ctx->opcode));
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
{
TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
gen_helper_440_tlbwe(t0, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
tcg_temp_free_i32(t0);
}
break;
default:
GEN_EXCP_INVAL(ctx);
@ -5955,15 +5974,24 @@ GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
#if defined(CONFIG_USER_ONLY)
GEN_EXCP_PRIVOPC(ctx);
#else
TCGv t0;
if (unlikely(!ctx->supervisor)) {
GEN_EXCP_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(cpu_T[0], ctx);
gen_op_440_tlbsx();
if (Rc(ctx->opcode))
gen_op_4xx_tlbsx_check();
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
t0 = tcg_temp_new();
gen_addr_reg_index(t0, ctx);
gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
tcg_temp_free(t0);
if (Rc(ctx->opcode)) {
int l1 = gen_new_label();
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
gen_set_label(l1);
}
#endif
}
@ -5981,9 +6009,11 @@ GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
case 0:
case 1:
case 2:
tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
gen_op_440_tlbwe(rB(ctx->opcode));
{
TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
gen_helper_440_tlbwe(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free_i32(t0);
}
break;
default:
GEN_EXCP_INVAL(ctx);