Commit 4b3686fa authored by bellard's avatar bellard
Browse files

PowerPC merge


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@861 c046a42c-6fe2-441c-8c8c-71466251a162
parent 85c4adf6
......@@ -135,6 +135,8 @@ void do_sraw(void);
void do_fctiw (void);
void do_fctiwz (void);
void do_fnmadd (void);
void do_fnmsub (void);
void do_fnmadds (void);
void do_fnmsubs (void);
void do_fsqrt (void);
......@@ -147,7 +149,11 @@ void do_fcmpo (void);
void do_fabs (void);
void do_fnabs (void);
void do_check_reservation (void);
void do_icbi (void);
void do_store_sr (uint32_t srnum);
void do_store_ibat (int ul, int nr);
void do_store_dbat (int ul, int nr);
void do_tlbia (void);
void do_tlbie (void);
......
......@@ -28,9 +28,6 @@
//#define DEBUG_EXCEPTIONS
extern FILE *stdout, *stderr;
void abort (void);
/*****************************************************************************/
/*****************************************************************************/
/* PPC MMU emulation */
......@@ -365,7 +362,8 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
fprintf(logfile, "%s\n", __func__);
}
if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) {
if ((access_type == ACCESS_CODE && msr_ir == 0) ||
(access_type != ACCESS_CODE && msr_dr == 0)) {
/* No address translation */
*physical = address & ~0xFFF;
*prot = PAGE_READ | PAGE_WRITE;
......@@ -441,12 +439,15 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_addrr = env->tlb_read[is_user][index].address;
tlb_addrw = env->tlb_write[is_user][index].address;
#if 0
printf("%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
#if 1
if (loglevel) {
fprintf(logfile,
"%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
"(0x%08lx 0x%08lx)\n", __func__, env,
&env->tlb_read[is_user][index], index, addr,
tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
}
#endif
}
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
......@@ -631,11 +632,14 @@ uint32_t _load_msr (CPUState *env)
void _store_msr (CPUState *env, uint32_t value)
{
#if 0 // TRY
if (((value >> MSR_IR) & 0x01) != msr_ir ||
((value >> MSR_DR) & 0x01) != msr_dr) {
((value >> MSR_DR) & 0x01) != msr_dr)
{
/* Flush all tlb when changing translation mode or privilege level */
tlb_flush(env, 1);
}
#endif
msr_pow = (value >> MSR_POW) & 0x03;
msr_ile = (value >> MSR_ILE) & 0x01;
msr_ee = (value >> MSR_EE) & 0x01;
......@@ -699,13 +703,8 @@ void do_interrupt (CPUState *env)
goto store_next;
case EXCP_MACHINE_CHECK:
if (msr_me == 0) {
printf("Machine check exception while not allowed !\n");
if (loglevel) {
fprintf(logfile,
"Machine check exception while not allowed !\n");
cpu_abort(env, "Machine check exception while not allowed\n");
}
abort();
}
msr_me = 0;
break;
case EXCP_DSI:
......@@ -801,7 +800,7 @@ void do_interrupt (CPUState *env)
env->fpscr[7] |= 0x4;
break;
case EXCP_INVAL:
printf("Invalid instruction at 0x%08x\n", env->nip);
// printf("Invalid instruction at 0x%08x\n", env->nip);
msr |= 0x00080000;
break;
case EXCP_PRIV:
......
......@@ -242,10 +242,7 @@ PPC_OP(load_srin)
PPC_OP(store_srin)
{
#if defined (DEBUG_OP)
dump_store_sr(T1 >> 28);
#endif
regs->sr[T1 >> 28] = T0;
do_store_sr(T1 >> 28);
RETURN();
}
......@@ -402,10 +399,7 @@ PPC_OP(load_ibat)
PPC_OP(store_ibat)
{
#if defined (DEBUG_OP)
dump_store_ibat(PARAM(1), PARAM(2));
#endif
regs->IBAT[PARAM(1)][PARAM(2)] = T0;
do_store_ibat(PARAM(1), PARAM(2));
}
PPC_OP(load_dbat)
......@@ -415,10 +409,7 @@ PPC_OP(load_dbat)
PPC_OP(store_dbat)
{
#if defined (DEBUG_OP)
dump_store_dbat(PARAM(1), PARAM(2));
#endif
regs->DBAT[PARAM(1)][PARAM(2)] = T0;
do_store_dbat(PARAM(1), PARAM(2));
}
/* FPSCR */
......@@ -1344,9 +1335,7 @@ PPC_OP(fmsubs)
/* fnmadd - fnmadd. - fnmadds - fnmadds. */
PPC_OP(fnmadd)
{
FT0 *= FT1;
FT0 += FT2;
FT0 = -FT0;
do_fnmadd();
RETURN();
}
......@@ -1360,9 +1349,7 @@ PPC_OP(fnmadds)
/* fnmsub - fnmsub. */
PPC_OP(fnmsub)
{
FT0 *= FT1;
FT0 -= FT2;
FT0 = -FT0;
do_fnmsub();
RETURN();
}
......@@ -1444,11 +1431,22 @@ PPC_OP(fneg)
#include "op_mem.h"
#endif
/* Special op to check and maybe clear reservation */
PPC_OP(check_reservation)
{
do_check_reservation();
RETURN();
}
/* Return from interrupt */
PPC_OP(rfi)
{
regs->nip = regs->spr[SRR0] & ~0x00000003;
#if 1 // TRY
T0 = regs->spr[SRR1] & ~0xFFF00000;
#else
T0 = regs->spr[SRR1] & ~0xFFFF0000;
#endif
do_store_msr();
#if defined (DEBUG_OP)
dump_rfi();
......
......@@ -127,11 +127,14 @@ void do_load_msr (void)
void do_store_msr (void)
{
#if 1 // TRY
if (((T0 >> MSR_IR) & 0x01) != msr_ir ||
((T0 >> MSR_DR) & 0x01) != msr_dr) {
/* Flush all tlb when changing translation mode or privilege level */
((T0 >> MSR_DR) & 0x01) != msr_dr ||
((T0 >> MSR_PR) & 0x01) != msr_pr)
{
do_tlbia();
}
#endif
msr_pow = (T0 >> MSR_POW) & 0x03;
msr_ile = (T0 >> MSR_ILE) & 0x01;
msr_ee = (T0 >> MSR_EE) & 0x01;
......@@ -157,14 +160,18 @@ void do_sraw (void)
xer_ca = 0;
if (T1 & 0x20) {
ret = (-1) * (T0 >> 31);
if (ret < 0)
if (ret < 0 && (T0 & ~0x80000000) != 0)
xer_ca = 1;
#if 1 // TRY
} else if (T1 == 0) {
ret = T0;
#endif
} else {
ret = (int32_t)T0 >> (T1 & 0x1f);
if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0)
xer_ca = 1;
}
(int32_t)T0 = ret;
T0 = ret;
}
/* Floating point operations helpers */
......@@ -267,14 +274,24 @@ void do_fctiwz (void)
fesetround(cround);
}
void do_fnmadd (void)
{
FT0 = -((FT0 * FT1) + FT2);
}
void do_fnmsub (void)
{
FT0 = -((FT0 * FT1) - FT2);
}
void do_fnmadds (void)
{
FTS0 = -((FTS0 * FTS1) + FTS2);
FT0 = -((FTS0 * FTS1) + FTS2);
}
void do_fnmsubs (void)
{
FTS0 = -((FTS0 * FTS1) - FTS2);
FT0 = -((FTS0 * FTS1) - FTS2);
}
void do_fsqrt (void)
......@@ -307,7 +324,6 @@ void do_fsel (void)
void do_fcmpu (void)
{
env->fpscr[4] &= ~0x1;
if (isnan(FT0) || isnan(FT1)) {
T0 = 0x01;
env->fpscr[4] |= 0x1;
......@@ -319,7 +335,7 @@ void do_fcmpu (void)
} else {
T0 = 0x02;
}
env->fpscr[3] |= T0;
env->fpscr[3] = T0;
}
void do_fcmpo (void)
......@@ -343,7 +359,7 @@ void do_fcmpo (void)
} else {
T0 = 0x02;
}
env->fpscr[3] |= T0;
env->fpscr[3] = T0;
}
void do_fabs (void)
......@@ -359,6 +375,12 @@ void do_fnabs (void)
/* Instruction cache invalidation helper */
#define ICACHE_LINE_SIZE 32
void do_check_reservation (void)
{
if ((env->reserve & ~(ICACHE_LINE_SIZE - 1)) == T0)
env->reserve = -1;
}
void do_icbi (void)
{
/* Invalidate one cache line */
......@@ -377,6 +399,69 @@ void do_tlbie (void)
tlb_flush_page(env, T0);
}
void do_store_sr (uint32_t srnum)
{
#if defined (DEBUG_OP)
dump_store_sr(srnum);
#endif
#if 0 // TRY
{
uint32_t base, page;
base = srnum << 28;
for (page = base; page != base + 0x100000000; page += 0x1000)
tlb_flush_page(env, page);
}
#else
tlb_flush(env, 1);
#endif
env->sr[srnum] = T0;
}
/* For BATs, we may not invalidate any TLBs if the change is only on
* protection bits for user mode.
*/
void do_store_ibat (int ul, int nr)
{
#if defined (DEBUG_OP)
dump_store_ibat(ul, nr);
#endif
#if 0 // TRY
{
uint32_t base, length, page;
base = env->IBAT[0][nr];
length = (((base >> 2) & 0x000007FF) + 1) << 17;
base &= 0xFFFC0000;
for (page = base; page != base + length; page += 0x1000)
tlb_flush_page(env, page);
}
#else
tlb_flush(env, 1);
#endif
env->IBAT[ul][nr] = T0;
}
void do_store_dbat (int ul, int nr)
{
#if defined (DEBUG_OP)
dump_store_dbat(ul, nr);
#endif
#if 0 // TRY
{
uint32_t base, length, page;
base = env->DBAT[0][nr];
length = (((base >> 2) & 0x000007FF) + 1) << 17;
base &= 0xFFFC0000;
for (page = base; page != base + length; page += 0x1000)
tlb_flush_page(env, page);
}
#else
tlb_flush(env, 1);
#endif
env->DBAT[ul][nr] = T0;
}
/*****************************************************************************/
/* Special helpers for debug */
extern FILE *stdout;
......@@ -389,7 +474,7 @@ void dump_state (void)
void dump_rfi (void)
{
#if 0
printf("Return from interrupt %d => 0x%08x\n", pos, env->nip);
printf("Return from interrupt => 0x%08x\n", env->nip);
// cpu_ppc_dump_state(env, stdout, 0);
#endif
}
......
......@@ -175,10 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void)
void OPPROTO glue(op_store_sr, REG)(void)
{
#if defined (DEBUG_OP)
dump_store_sr(REG);
#endif
env->sr[REG] = T0;
do_store_sr(REG);
RETURN();
}
#endif
......
......@@ -28,8 +28,6 @@
#include "disas.h"
//#define DO_SINGLE_STEP
//#define DO_STEP_FLUSH
//#define DEBUG_DISAS
//#define PPC_DEBUG_DISAS
enum {
......@@ -639,7 +637,7 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
}
gen_op_load_gpr_T0(rS(ctx->opcode));
if (uimm != 0)
gen_op_xori(UIMM(ctx->opcode));
gen_op_xori(uimm);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
......@@ -654,7 +652,7 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
}
gen_op_load_gpr_T0(rS(ctx->opcode));
if (uimm != 0)
gen_op_xori(UIMM(ctx->opcode) << 16);
gen_op_xori(uimm << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
......@@ -682,25 +680,29 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
#if 1 // TRY
if (sh == 0) {
gen_op_andi_(MASK(mb, me));
goto store;
}
#endif
if (mb == 0) {
if (me == 31) {
gen_op_rotlwi(sh);
goto store;
#if 0
} else if (me == (31 - sh)) {
gen_op_slwi(sh);
goto store;
} else if (sh == 0) {
gen_op_andi_(MASK(0, me));
goto store;
#endif
}
} else if (me == 31) {
#if 0
if (sh == (32 - mb)) {
gen_op_srwi(mb);
goto store;
} else if (sh == 0) {
gen_op_andi_(MASK(mb, 31));
goto store;
}
#endif
}
gen_op_rlwinm(sh, MASK(mb, me));
store:
......@@ -1268,12 +1270,16 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
/* stswi */
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
{
int nb = NB(ctx->opcode);
if (rA(ctx->opcode) == 0) {
gen_op_set_T0(0);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
}
gen_op_set_T1(NB(ctx->opcode));
if (nb == 0)
nb = 32;
gen_op_set_T1(nb);
op_ldsts(stsw, rS(ctx->opcode));
}
......@@ -1931,7 +1937,6 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
/* We need to update the time base before reading it */
switch (sprn) {
case V_TBL:
/* TBL is still in T0 */
gen_op_load_tbl();
break;
case V_TBU:
......@@ -2007,135 +2012,135 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
break;
case IBAT0U:
gen_op_store_ibat(0, 0);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT1U:
gen_op_store_ibat(0, 1);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT2U:
gen_op_store_ibat(0, 2);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT3U:
gen_op_store_ibat(0, 3);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT4U:
gen_op_store_ibat(0, 4);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT5U:
gen_op_store_ibat(0, 5);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT6U:
gen_op_store_ibat(0, 6);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT7U:
gen_op_store_ibat(0, 7);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT0L:
gen_op_store_ibat(1, 0);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT1L:
gen_op_store_ibat(1, 1);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT2L:
gen_op_store_ibat(1, 2);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT3L:
gen_op_store_ibat(1, 3);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT4L:
gen_op_store_ibat(1, 4);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT5L:
gen_op_store_ibat(1, 5);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT6L:
gen_op_store_ibat(1, 6);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case IBAT7L:
gen_op_store_ibat(1, 7);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT0U:
gen_op_store_dbat(0, 0);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT1U:
gen_op_store_dbat(0, 1);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT2U:
gen_op_store_dbat(0, 2);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT3U:
gen_op_store_dbat(0, 3);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT4U:
gen_op_store_dbat(0, 4);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT5U:
gen_op_store_dbat(0, 5);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT6U:
gen_op_store_dbat(0, 6);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT7U:
gen_op_store_dbat(0, 7);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT0L:
gen_op_store_dbat(1, 0);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT1L:
gen_op_store_dbat(1, 1);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT2L:
gen_op_store_dbat(1, 2);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT3L:
gen_op_store_dbat(1, 3);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT4L:
gen_op_store_dbat(1, 4);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT5L:
gen_op_store_dbat(1, 5);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT6L:
gen_op_store_dbat(1, 6);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case DBAT7L:
gen_op_store_dbat(1, 7);
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case SDR1:
gen_op_store_sdr1();
gen_op_tlbia();
RET_MTMSR(ctx);
break;
case O_TBL:
gen_op_store_tbl();
......@@ -2146,6 +2151,11 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
case DECR:
gen_op_store_decr();
break;
#if 0
case HID0:
gen_op_store_hid0();
break;
#endif
default:
gen_op_store_spr(sprn);