sim-card
/
qemu
Archived
10
0
Fork 0

preliminary patch to support more PowerPC CPUs (Jocelyn Mayer)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1489 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2005-07-02 20:59:34 +00:00
parent 2f636b458f
commit 3fc6c082e3
13 changed files with 3461 additions and 1474 deletions

View File

@ -468,6 +468,7 @@ endif
ifeq ($(TARGET_ARCH), ppc)
op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h
translate.o: translate.c translate_init.c
endif
ifeq ($(TARGET_ARCH), mips)

View File

@ -253,14 +253,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
registers[96] = tswapl(env->nip);
registers[97] = tswapl(_load_msr(env));
registers[97] = tswapl(do_load_msr(env));
tmp = 0;
for (i = 0; i < 8; i++)
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr);
registers[101] = tswapl(_load_xer(env));
registers[101] = tswapl(do_load_xer(env));
registers[102] = 0;
return 103 * 4;
@ -282,13 +282,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
env->nip = tswapl(registers[96]);
_store_msr(env, tswapl(registers[97]));
do_store_msr(env, tswapl(registers[97]));
registers[98] = tswapl(registers[98]);
for (i = 0; i < 8; i++)
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]);
_store_xer(env, tswapl(registers[101]));
do_store_xer(env, tswapl(registers[101]));
}
#elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)

View File

@ -235,6 +235,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
int ret, linux_boot, i;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
const char *arch_name;
@ -286,7 +287,26 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
initrd_size = 0;
}
/* Register CPU as a 74x/75x */
cpu_ppc_register(cpu_single_env, 0x00080000);
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def); // Linux boot OK
// ppc_find_by_name("750fx", &def); // Linux boot OK
/* Linux does not boot on 750cxe (and probably other 750cx based)
* because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
*/
// ppc_find_by_name("750cxe", &def);
// ppc_find_by_name("750p", &def);
// ppc_find_by_name("740p", &def);
ppc_find_by_name("750", &def);
// ppc_find_by_name("740", &def);
// ppc_find_by_name("G3", &def);
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
// ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Set time-base frequency to 10 Mhz */
cpu_ppc_tb_init(cpu_single_env, 10UL * 1000UL * 1000UL);

View File

@ -527,6 +527,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
int ret, linux_boot, i, nb_nics1;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
@ -582,7 +583,14 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
}
/* Register CPU as a 604 */
cpu_ppc_register(cpu_single_env, 0x00040000);
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);

View File

@ -700,10 +700,11 @@ void cpu_loop(CPUPPCState *env)
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
case EXCP_DSI:
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
fprintf(stderr, "Invalid data memory access: 0x%08x\n",
env->spr[SPR_DAR]);
if (loglevel) {
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
env->spr[DAR]);
env->spr[SPR_DAR]);
}
switch (env->error_code & 0xF) {
case EXCP_DSI_TRANSLATE:
@ -1243,7 +1244,25 @@ int main(int argc, char **argv)
}
#elif defined(TARGET_PPC)
{
ppc_def_t *def;
int i;
/* Choose and initialise CPU */
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def);
// ppc_find_by_name("750fx", &def);
// ppc_find_by_name("750p", &def);
ppc_find_by_name("750", &def);
// ppc_find_by_name("G3", &def);
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
// ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env,
"Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
for (i = 0; i < 32; i++) {
if (i != 12 && i != 6 && i != 13)
env->msr[i] = (regs->msr >> i) & 1;

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* PPC emulation definitions for qemu.
* PowerPC emulation definitions for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -119,15 +119,6 @@ static inline uint32_t rotl (uint32_t i, int n)
void do_raise_exception_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception);
void do_load_cr (void);
void do_store_cr (uint32_t mask);
void do_load_xer (void);
void do_store_xer (void);
void do_load_msr (void);
void do_store_msr (void);
void do_load_fpscr (void);
void do_store_fpscr (uint32_t mask);
void do_sraw(void);
void do_fctiw (void);
@ -143,20 +134,9 @@ void do_fcmpo (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);
void dump_state (void);
void dump_rfi (void);
void dump_store_sr (int srnum);
void dump_store_ibat (int ul, int nr);
void dump_store_dbat (int ul, int nr);
void dump_store_tb (int ul);
void dump_update_tb(uint32_t param);
static inline void env_to_regs(void)
{
}

View File

@ -1,7 +1,7 @@
/*
* PPC emulation helpers for qemu.
* PowerPC emulation helpers for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -26,7 +26,7 @@
//#define ACCURATE_TLB_FLUSH
/*****************************************************************************/
/* PPC MMU emulation */
/* PowerPC MMU emulation */
/* Perform BAT hit & translation */
static int get_bat (CPUState *env, uint32_t *real, int *prot,
@ -580,7 +580,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
if (rw)
error_code |= EXCP_DSI_STORE;
/* Store fault address */
env->spr[DAR] = address;
env->spr[SPR_DAR] = address;
}
#if 0
printf("%s: set exception to %d %02x\n",
@ -593,25 +593,239 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
return ret;
}
uint32_t _load_xer (CPUState *env)
/*****************************************************************************/
/* BATs management */
#if !defined(FLUSH_ALL_TLBS)
static inline void do_invalidate_BAT (CPUPPCState *env,
target_ulong BATu, target_ulong mask)
{
target_ulong base, end, page;
base = BATu & ~0x0001FFFF;
end = base + mask + 0x00020000;
#if defined (DEBUG_BATS)
if (loglevel != 0)
fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask);
#endif
for (page = base; page != end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
#if defined (DEBUG_BATS)
if (loglevel != 0)
fprintf(logfile, "Flush done\n");
#endif
}
#endif
static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr,
target_ulong value)
{
#if defined (DEBUG_BATS)
if (loglevel != 0) {
fprintf(logfile, "Set %cBAT%d%c to 0x%08lx (0x%08lx)\n",
ID, nr, ul == 0 ? 'u' : 'l', (unsigned long)value,
(unsigned long)env->nip);
}
#endif
}
target_ulong do_load_ibatu (CPUPPCState *env, int nr)
{
return env->IBAT[0][nr];
}
target_ulong do_load_ibatl (CPUPPCState *env, int nr)
{
return env->IBAT[1][nr];
}
void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
dump_store_bat(env, 'I', 0, nr, value);
if (env->IBAT[0][nr] != value) {
mask = (value << 15) & 0x0FFE0000UL;
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#endif
/* When storing valid upper BAT, mask BEPI and BRPN
* and invalidate all TLBs covered by this BAT
*/
mask = (value << 15) & 0x0FFE0000UL;
env->IBAT[0][nr] = (value & 0x00001FFFUL) |
(value & ~0x0001FFFFUL & ~mask);
env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
(env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#endif
#if defined(FLUSH_ALL_TLBS)
tlb_flush(env, 1);
#endif
}
}
void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
{
dump_store_bat(env, 'I', 1, nr, value);
env->IBAT[1][nr] = value;
}
target_ulong do_load_dbatu (CPUPPCState *env, int nr)
{
return env->DBAT[0][nr];
}
target_ulong do_load_dbatl (CPUPPCState *env, int nr)
{
return env->DBAT[1][nr];
}
void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
dump_store_bat(env, 'D', 0, nr, value);
if (env->DBAT[0][nr] != value) {
/* When storing valid upper BAT, mask BEPI and BRPN
* and invalidate all TLBs covered by this BAT
*/
mask = (value << 15) & 0x0FFE0000UL;
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->DBAT[0][nr], mask);
#endif
mask = (value << 15) & 0x0FFE0000UL;
env->DBAT[0][nr] = (value & 0x00001FFFUL) |
(value & ~0x0001FFFFUL & ~mask);
env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
(env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->DBAT[0][nr], mask);
#else
tlb_flush(env, 1);
#endif
}
}
void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
{
dump_store_bat(env, 'D', 1, nr, value);
env->DBAT[1][nr] = value;
}
static inline void invalidate_all_tlbs (CPUPPCState *env)
{
/* XXX: this needs to be completed for sotware driven TLB support */
tlb_flush(env, 1);
}
/*****************************************************************************/
/* Special registers manipulation */
target_ulong do_load_nip (CPUPPCState *env)
{
return env->nip;
}
void do_store_nip (CPUPPCState *env, target_ulong value)
{
env->nip = value;
}
target_ulong do_load_sdr1 (CPUPPCState *env)
{
return env->sdr1;
}
void do_store_sdr1 (CPUPPCState *env, target_ulong value)
{
#if defined (DEBUG_MMU)
if (loglevel != 0) {
fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value);
}
#endif
if (env->sdr1 != value) {
env->sdr1 = value;
invalidate_all_tlbs(env);
}
}
target_ulong do_load_sr (CPUPPCState *env, int srnum)
{
return env->sr[srnum];
}
void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
{
#if defined (DEBUG_MMU)
if (loglevel != 0) {
fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n",
__func__, srnum, (unsigned long)value, env->sr[srnum]);
}
#endif
if (env->sr[srnum] != value) {
env->sr[srnum] = value;
#if !defined(FLUSH_ALL_TLBS) && 0
{
target_ulong page, end;
/* Invalidate 256 MB of virtual memory */
page = (16 << 20) * srnum;
end = page + (16 << 20);
for (; page != end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
}
#else
invalidate_all_tlbs(env);
#endif
}
}
uint32_t do_load_cr (CPUPPCState *env)
{
return (env->crf[0] << 28) |
(env->crf[1] << 24) |
(env->crf[2] << 20) |
(env->crf[3] << 16) |
(env->crf[4] << 12) |
(env->crf[5] << 8) |
(env->crf[6] << 4) |
(env->crf[7] << 0);
}
void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask)
{
int i, sh;
for (i = 0, sh = 7; i < 8; i++, sh --) {
if (mask & (1 << sh))
env->crf[i] = (value >> (sh * 4)) & 0xFUL;
}
}
uint32_t do_load_xer (CPUPPCState *env)
{
return (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_ca << XER_CA) |
(xer_bc << XER_BC);
(xer_bc << XER_BC) |
(xer_cmp << XER_CMP);
}
void _store_xer (CPUState *env, uint32_t value)
void do_store_xer (CPUPPCState *env, uint32_t value)
{
xer_so = (value >> XER_SO) & 0x01;
xer_ov = (value >> XER_OV) & 0x01;
xer_ca = (value >> XER_CA) & 0x01;
xer_bc = (value >> XER_BC) & 0x3f;
xer_cmp = (value >> XER_CMP) & 0xFF;
xer_bc = (value >> XER_BC) & 0x3F;
}
uint32_t _load_msr (CPUState *env)
target_ulong do_load_msr (CPUPPCState *env)
{
return (msr_pow << MSR_POW) |
return (msr_vr << MSR_VR) |
(msr_ap << MSR_AP) |
(msr_sa << MSR_SA) |
(msr_key << MSR_KEY) |
(msr_pow << MSR_POW) |
(msr_tlb << MSR_TLB) |
(msr_ile << MSR_ILE) |
(msr_ee << MSR_EE) |
(msr_pr << MSR_PR) |
@ -621,41 +835,141 @@ uint32_t _load_msr (CPUState *env)
(msr_se << MSR_SE) |
(msr_be << MSR_BE) |
(msr_fe1 << MSR_FE1) |
(msr_al << MSR_AL) |
(msr_ip << MSR_IP) |
(msr_ir << MSR_IR) |
(msr_dr << MSR_DR) |
(msr_pe << MSR_PE) |
(msr_px << MSR_PX) |
(msr_ri << MSR_RI) |
(msr_le << MSR_LE);
}
void _store_msr (CPUState *env, uint32_t value)
void do_compute_hflags (CPUPPCState *env)
{
#ifdef ACCURATE_TLB_FLUSH
if (((value >> MSR_IR) & 0x01) != msr_ir ||
((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;
msr_pr = (value >> MSR_PR) & 0x01;
msr_fp = (value >> MSR_FP) & 0x01;
msr_me = (value >> MSR_ME) & 0x01;
msr_fe0 = (value >> MSR_FE0) & 0x01;
msr_se = (value >> MSR_SE) & 0x01;
msr_be = (value >> MSR_BE) & 0x01;
msr_fe1 = (value >> MSR_FE1) & 0x01;
msr_ip = (value >> MSR_IP) & 0x01;
msr_ir = (value >> MSR_IR) & 0x01;
msr_dr = (value >> MSR_DR) & 0x01;
msr_ri = (value >> MSR_RI) & 0x01;
msr_le = (value >> MSR_LE) & 0x01;
/* XXX: should enter PM state if msr_pow has been set */
/* Compute current hflags */
env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
(msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
(msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) |
(msr_se << MSR_SE) | (msr_be << MSR_BE);
}
void do_store_msr (CPUPPCState *env, target_ulong value)
{
value &= env->msr_mask;
if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) {
/* Flush all tlb when changing translation mode
* When using software driven TLB, we may also need to reload
* all defined TLBs
*/
tlb_flush(env, 1);
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
#if 0
if (loglevel != 0) {
fprintf(logfile, "%s: T0 %08lx\n", __func__, value);
}
#endif
msr_vr = (value >> MSR_VR) & 1;
msr_ap = (value >> MSR_AP) & 1;
msr_sa = (value >> MSR_SA) & 1;
msr_key = (value >> MSR_KEY) & 1;
msr_pow = (value >> MSR_POW) & 1;
msr_tlb = (value >> MSR_TLB) & 1;
msr_ile = (value >> MSR_ILE) & 1;
msr_ee = (value >> MSR_EE) & 1;
msr_pr = (value >> MSR_PR) & 1;
msr_fp = (value >> MSR_FP) & 1;
msr_me = (value >> MSR_ME) & 1;
msr_fe0 = (value >> MSR_FE0) & 1;
msr_se = (value >> MSR_SE) & 1;
msr_be = (value >> MSR_BE) & 1;
msr_fe1 = (value >> MSR_FE1) & 1;
msr_al = (value >> MSR_AL) & 1;
msr_ip = (value >> MSR_IP) & 1;
msr_ir = (value >> MSR_IR) & 1;
msr_dr = (value >> MSR_DR) & 1;
msr_pe = (value >> MSR_PE) & 1;
msr_px = (value >> MSR_PX) & 1;
msr_ri = (value >> MSR_RI) & 1;
msr_le = (value >> MSR_LE) & 1;
do_compute_hflags(env);
}
float64 do_load_fpscr (CPUPPCState *env)
{
/* The 32 MSB of the target fpr are undefined.
* They'll be zero...
*/
union {
float64 d;
struct {
uint32_t u[2];
} s;
} u;
int i;
#ifdef WORDS_BIGENDIAN
#define WORD0 0
#define WORD1 1
#else
#define WORD0 1
#define WORD1 0
#endif
u.s.u[WORD0] = 0;
u.s.u[WORD1] = 0;
for (i = 0; i < 8; i++)
u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
return u.d;
}
void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask)
{
/*
* We use only the 32 LSB of the incoming fpr
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i, rnd_type;
u.d = f;
if (mask & 0x80)
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
for (i = 1; i < 7; i++) {
if (mask & (1 << (7 - i)))
env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
}
/* TODO: update FEX & VX */
/* Set rounding mode */
switch (env->fpscr[0] & 0x3) {
case 0:
/* Best approximation (round to nearest) */
rnd_type = float_round_nearest_even;
break;
case 1:
/* Smaller magnitude (round toward zero) */
rnd_type = float_round_to_zero;
break;
case 2:
/* Round toward +infinite */
rnd_type = float_round_up;
break;
default:
case 3:
/* Round toward -infinite */
rnd_type = float_round_down;
break;
}
set_float_rounding_mode(rnd_type, &env->fp_status);
}
/*****************************************************************************/
/* Exception processing */
#if defined (CONFIG_USER_ONLY)
void do_interrupt (CPUState *env)
{
@ -675,7 +989,7 @@ void do_interrupt (CPUState *env)
int excp;
excp = env->exception_index;
msr = _load_msr(env);
msr = do_load_msr(env);
#if defined (DEBUG_EXCEPTIONS)
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1)
{
@ -715,29 +1029,29 @@ void do_interrupt (CPUState *env)
* when the fault has been detected
*/
msr &= ~0xFFFF0000;
env->spr[DSISR] = 0;
env->spr[SPR_DSISR] = 0;
if ((env->error_code & 0x0f) == EXCP_DSI_TRANSLATE)
env->spr[DSISR] |= 0x40000000;
env->spr[SPR_DSISR] |= 0x40000000;
else if ((env->error_code & 0x0f) == EXCP_DSI_PROT)
env->spr[DSISR] |= 0x08000000;
env->spr[SPR_DSISR] |= 0x08000000;
else if ((env->error_code & 0x0f) == EXCP_DSI_NOTSUP) {
env->spr[DSISR] |= 0x80000000;
env->spr[SPR_DSISR] |= 0x80000000;
if (env->error_code & EXCP_DSI_DIRECT)
env->spr[DSISR] |= 0x04000000;
env->spr[SPR_DSISR] |= 0x04000000;
}
if (env->error_code & EXCP_DSI_STORE)
env->spr[DSISR] |= 0x02000000;
env->spr[SPR_DSISR] |= 0x02000000;
if ((env->error_code & 0xF) == EXCP_DSI_DABR)
env->spr[DSISR] |= 0x00400000;
env->spr[SPR_DSISR] |= 0x00400000;
if (env->error_code & EXCP_DSI_ECXW)
env->spr[DSISR] |= 0x00100000;
env->spr[SPR_DSISR] |= 0x00100000;
#if defined (DEBUG_EXCEPTIONS)
if (loglevel) {
fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
env->spr[DSISR], env->spr[DAR]);
env->spr[SPR_DSISR], env->spr[SPR_DAR]);
} else {
printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n",
env->spr[DSISR], env->spr[DAR], env->nip);
env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip);
}
#endif
goto store_next;
@ -777,7 +1091,7 @@ void do_interrupt (CPUState *env)
case EXCP_ALIGN:
/* Store exception cause */
/* Get rS/rD and rA from faulting opcode */
env->spr[DSISR] |=
env->spr[SPR_DSISR] |=
(ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
/* data location address has been stored
* when the fault has been detected
@ -858,14 +1172,14 @@ void do_interrupt (CPUState *env)
return;
store_current:
/* SRR0 is set to current instruction */
env->spr[SRR0] = (uint32_t)env->nip - 4;
env->spr[SPR_SRR0] = (uint32_t)env->nip - 4;
break;
store_next:
/* SRR0 is set to next instruction */
env->spr[SRR0] = (uint32_t)env->nip;
env->spr[SPR_SRR0] = (uint32_t)env->nip;
break;
}
env->spr[SRR1] = msr;
env->spr[SPR_SRR1] = msr;
/* reload MSR with correct bits */
msr_pow = 0;
msr_ee = 0;
@ -879,6 +1193,7 @@ void do_interrupt (CPUState *env)
msr_dr = 0;
msr_ri = 0;
msr_le = msr_ile;
do_compute_hflags(env);
/* Jump to handler */
env->nip = excp << 8;
env->exception_index = EXCP_NONE;

View File

@ -1,7 +1,7 @@
/*
* PPC emulation micro-operations for qemu.
* PowerPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -130,7 +130,7 @@
#define REG 31
#include "op_template.h"
/* PPC state maintenance operations */
/* PowerPC state maintenance operations */
/* set_Rc0 */
PPC_OP(set_Rc0)
{
@ -223,7 +223,7 @@ PPC_OP(load_srin)
PPC_OP(store_srin)
{
do_store_sr(T1 >> 28);
do_store_sr(env, ((uint32_t)T1 >> 28), T0);
RETURN();
}
@ -235,7 +235,7 @@ PPC_OP(load_sdr1)
PPC_OP(store_sdr1)
{
regs->sdr1 = T0;
do_store_sdr1(env, T0);
RETURN();
}
@ -247,13 +247,13 @@ PPC_OP(exit_tb)
/* Load/store special registers */
PPC_OP(load_cr)
{
do_load_cr();
T0 = do_load_cr(env);
RETURN();
}
PPC_OP(store_cr)
{
do_store_cr(PARAM(1));
do_store_cr(env, T0, PARAM(1));
RETURN();
}
@ -279,25 +279,25 @@ PPC_OP(load_xer_bc)
PPC_OP(load_xer)
{
do_load_xer();
T0 = do_load_xer(env);
RETURN();
}
PPC_OP(store_xer)
{
do_store_xer();
do_store_xer(env, T0);
RETURN();
}
PPC_OP(load_msr)
{
do_load_msr();
T0 = do_load_msr(env);
RETURN();
}
PPC_OP(store_msr)
{
do_store_msr();
do_store_msr(env, T0);
RETURN();
}
@ -378,9 +378,20 @@ PPC_OP(load_ibat)
T0 = regs->IBAT[PARAM(1)][PARAM(2)];
}
PPC_OP(store_ibat)
void op_store_ibatu (void)
{
do_store_ibat(PARAM(1), PARAM(2));
do_store_ibatu(env, PARAM1, T0);
RETURN();
}
void op_store_ibatl (void)
{
#if 1
env->IBAT[1][PARAM1] = T0;
#else
do_store_ibatl(env, PARAM1, T0);
#endif
RETURN();
}
PPC_OP(load_dbat)
@ -388,21 +399,32 @@ PPC_OP(load_dbat)
T0 = regs->DBAT[PARAM(1)][PARAM(2)];
}
PPC_OP(store_dbat)
void op_store_dbatu (void)
{
do_store_dbat(PARAM(1), PARAM(2));
do_store_dbatu(env, PARAM1, T0);
RETURN();
}
void op_store_dbatl (void)
{
#if 1
env->DBAT[1][PARAM1] = T0;
#else
do_store_dbatl(env, PARAM1, T0);
#endif
RETURN();
}
/* FPSCR */
PPC_OP(load_fpscr)
{
do_load_fpscr();
FT0 = do_load_fpscr(env);
RETURN();
}
PPC_OP(store_fpscr)
{
do_store_fpscr(PARAM(1));
do_store_fpscr(env, FT0, PARAM1);
RETURN();
}
@ -1362,17 +1384,13 @@ PPC_OP(check_reservation)
/* Return from interrupt */
PPC_OP(rfi)
{
regs->nip = regs->spr[SRR0] & ~0x00000003;
regs->nip = regs->spr[SPR_SRR0] & ~0x00000003;
#if 1 // TRY
T0 = regs->spr[SRR1] & ~0xFFF00000;
T0 = regs->spr[SPR_SRR1] & ~0xFFF00000;
#else
T0 = regs->spr[SRR1] & ~0xFFFF0000;
T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000;
#endif
do_store_msr();
#if defined (DEBUG_OP)
dump_rfi();
#endif
// do_tlbia();
do_store_msr(env, T0);
do_raise_exception(EXCP_RFI);
RETURN();
}
@ -1420,3 +1438,9 @@ PPC_OP(tlbie)
do_tlbie();
RETURN();
}
void op_store_pir (void)
{
env->spr[SPR_PIR] = T0 & 0x0000000FUL;
RETURN();
}

View File

@ -1,7 +1,7 @@
/*
* PPC emulation helpers for qemu.
* PowerPC emulation helpers for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -67,91 +67,6 @@ void do_raise_exception (uint32_t exception)
/*****************************************************************************/
/* Helpers for "fat" micro operations */
/* Special registers load and store */
void do_load_cr (void)
{
T0 = (env->crf[0] << 28) |
(env->crf[1] << 24) |
(env->crf[2] << 20) |
(env->crf[3] << 16) |
(env->crf[4] << 12) |
(env->crf[5] << 8) |
(env->crf[6] << 4) |
(env->crf[7] << 0);
}
void do_store_cr (uint32_t mask)
{
int i, sh;
for (i = 0, sh = 7; i < 8; i++, sh --) {
if (mask & (1 << sh))
env->crf[i] = (T0 >> (sh * 4)) & 0xF;
}
}
void do_load_xer (void)
{
T0 = (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_ca << XER_CA) |
(xer_bc << XER_BC);
}
void do_store_xer (void)
{
xer_so = (T0 >> XER_SO) & 0x01;
xer_ov = (T0 >> XER_OV) & 0x01;
xer_ca = (T0 >> XER_CA) & 0x01;
xer_bc = (T0 >> XER_BC) & 0x3f;
}
void do_load_msr (void)
{
T0 = (msr_pow << MSR_POW) |
(msr_ile << MSR_ILE) |
(msr_ee << MSR_EE) |
(msr_pr << MSR_PR) |
(msr_fp << MSR_FP) |
(msr_me << MSR_ME) |
(msr_fe0 << MSR_FE0) |
(msr_se << MSR_SE) |
(msr_be << MSR_BE) |
(msr_fe1 << MSR_FE1) |
(msr_ip << MSR_IP) |
(msr_ir << MSR_IR) |
(msr_dr << MSR_DR) |
(msr_ri << MSR_RI) |
(msr_le << MSR_LE);
}
void do_store_msr (void)
{
#if 1 // TRY
if (((T0 >> MSR_IR) & 0x01) != msr_ir ||
((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;
msr_pr = (T0 >> MSR_PR) & 0x01;
msr_fp = (T0 >> MSR_FP) & 0x01;
msr_me = (T0 >> MSR_ME) & 0x01;
msr_fe0 = (T0 >> MSR_FE0) & 0x01;
msr_se = (T0 >> MSR_SE) & 0x01;
msr_be = (T0 >> MSR_BE) & 0x01;
msr_fe1 = (T0 >> MSR_FE1) & 0x01;
msr_ip = (T0 >> MSR_IP) & 0x01;
msr_ir = (T0 >> MSR_IR) & 0x01;
msr_dr = (T0 >> MSR_DR) & 0x01;
msr_ri = (T0 >> MSR_RI) & 0x01;
msr_le = (T0 >> MSR_LE) & 0x01;
}
/* shift right arithmetic helper */
void do_sraw (void)
{
@ -175,77 +90,6 @@ void do_sraw (void)
}
/* Floating point operations helpers */
void do_load_fpscr (void)
{
/* The 32 MSB of the target fpr are undefined.
* They'll be zero...
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i;
#ifdef WORDS_BIGENDIAN
#define WORD0 0
#define WORD1 1
#else
#define WORD0 1
#define WORD1 0
#endif
u.s.u[WORD0] = 0;
u.s.u[WORD1] = 0;
for (i = 0; i < 8; i++)
u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
FT0 = u.d;
}
void do_store_fpscr (uint32_t mask)
{
/*
* We use only the 32 LSB of the incoming fpr
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i, rnd_type;
u.d = FT0;
if (mask & 0x80)
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
for (i = 1; i < 7; i++) {
if (mask & (1 << (7 - i)))
env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
}
/* TODO: update FEX & VX */
/* Set rounding mode */
switch (env->fpscr[0] & 0x3) {
case 0:
/* Best approximation (round to nearest) */
rnd_type = float_round_nearest_even;
break;
case 1:
/* Smaller magnitude (round toward zero) */
rnd_type = float_round_to_zero;
break;
case 2:
/* Round toward +infinite */
rnd_type = float_round_up;
break;
default:
case 3:
/* Round toward -infinite */
rnd_type = float_round_down;
break;
}
set_float_rounding_mode(rnd_type, &env->fp_status);
}
void do_fctiw (void)
{
union {
@ -254,7 +98,7 @@ void do_fctiw (void)
} p;
/* XXX: higher bits are not supposed to be significant.
* to make tests easier, return the same as a real PPC 750 (aka G3)
* to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
p.i = float64_to_int32(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
@ -269,7 +113,7 @@ void do_fctiwz (void)
} p;
/* XXX: higher bits are not supposed to be significant.
* to make tests easier, return the same as a real PPC 750 (aka G3)
* to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
@ -455,116 +299,3 @@ 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 */
void dump_state (void)
{
// cpu_dump_state(env, stdout, fprintf, 0);
}
void dump_rfi (void)
{
#if 0
printf("Return from interrupt => 0x%08x\n", env->nip);
// cpu_dump_state(env, stdout, fprintf, 0);
#endif
}
void dump_store_sr (int srnum)
{
#if 0
printf("%s: reg=%d 0x%08x\n", __func__, srnum, T0);
#endif
}
static void _dump_store_bat (char ID, int ul, int nr)
{
printf("Set %cBAT%d%c to 0x%08x (0x%08x)\n",
ID, nr, ul == 0 ? 'u' : 'l', T0, env->nip);
}
void dump_store_ibat (int ul, int nr)
{
_dump_store_bat('I', ul, nr);
}
void dump_store_dbat (int ul, int nr)
{
_dump_store_bat('D', ul, nr);
}
void dump_store_tb (int ul)
{
printf("Set TB%c to 0x%08x\n", ul == 0 ? 'L' : 'U', T0);
}
void dump_update_tb(uint32_t param)
{
#if 0
printf("Update TB: 0x%08x + %d => 0x%08x\n", T1, param, T0);
#endif
}

View File

@ -1,7 +1,7 @@
/*
* PPC emulation micro-operations for qemu.
* PowerPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -175,7 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void)
void OPPROTO glue(op_store_sr, REG)(void)
{
do_store_sr(REG);
do_store_sr(env, REG, T0);
RETURN();
}
#endif

File diff suppressed because it is too large Load Diff

2069
target-ppc/translate_init.c Normal file

File diff suppressed because it is too large Load Diff