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) ifeq ($(TARGET_ARCH), ppc)
op.o: op.c op_template.h op_mem.h op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h op_helper.o: op_helper_mem.h
translate.o: translate.c translate_init.c
endif endif
ifeq ($(TARGET_ARCH), mips) 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 */ /* nip, msr, ccr, lnk, ctr, xer, mq */
registers[96] = tswapl(env->nip); registers[96] = tswapl(env->nip);
registers[97] = tswapl(_load_msr(env)); registers[97] = tswapl(do_load_msr(env));
tmp = 0; tmp = 0;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
tmp |= env->crf[i] << (32 - ((i + 1) * 4)); tmp |= env->crf[i] << (32 - ((i + 1) * 4));
registers[98] = tswapl(tmp); registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr); registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr); registers[100] = tswapl(env->ctr);
registers[101] = tswapl(_load_xer(env)); registers[101] = tswapl(do_load_xer(env));
registers[102] = 0; registers[102] = 0;
return 103 * 4; 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 */ /* nip, msr, ccr, lnk, ctr, xer, mq */
env->nip = tswapl(registers[96]); env->nip = tswapl(registers[96]);
_store_msr(env, tswapl(registers[97])); do_store_msr(env, tswapl(registers[97]));
registers[98] = tswapl(registers[98]); registers[98] = tswapl(registers[98]);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]); env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]); env->ctr = tswapl(registers[100]);
_store_xer(env, tswapl(registers[101])); do_store_xer(env, tswapl(registers[101]));
} }
#elif defined (TARGET_SPARC) #elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) 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; int ret, linux_boot, i;
unsigned long bios_offset; unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size; uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus; PCIBus *pci_bus;
const char *arch_name; 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; initrd_size = 0;
} }
/* Register CPU as a 74x/75x */ /* 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 */ /* Set time-base frequency to 10 Mhz */
cpu_ppc_tb_init(cpu_single_env, 10UL * 1000UL * 1000UL); 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; int ret, linux_boot, i, nb_nics1;
unsigned long bios_offset; unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size; uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus; PCIBus *pci_bus;
sysctrl = qemu_mallocz(sizeof(sysctrl_t)); 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 */ /* 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 */ /* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); 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; info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info); queue_signal(info.si_signo, &info);
case EXCP_DSI: 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) { if (loglevel) {
fprintf(logfile, "Invalid data memory access: 0x%08x\n", fprintf(logfile, "Invalid data memory access: 0x%08x\n",
env->spr[DAR]); env->spr[SPR_DAR]);
} }
switch (env->error_code & 0xF) { switch (env->error_code & 0xF) {
case EXCP_DSI_TRANSLATE: case EXCP_DSI_TRANSLATE:
@ -1243,7 +1244,25 @@ int main(int argc, char **argv)
} }
#elif defined(TARGET_PPC) #elif defined(TARGET_PPC)
{ {
ppc_def_t *def;
int i; 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++) { for (i = 0; i < 32; i++) {
if (i != 12 && i != 6 && i != 13) if (i != 12 && i != 6 && i != 13)
env->msr[i] = (regs->msr >> i) & 1; 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception); 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_sraw(void);
void do_fctiw (void); void do_fctiw (void);
@ -143,20 +134,9 @@ void do_fcmpo (void);
void do_check_reservation (void); void do_check_reservation (void);
void do_icbi (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_tlbia (void);
void do_tlbie (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) 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -26,7 +26,7 @@
//#define ACCURATE_TLB_FLUSH //#define ACCURATE_TLB_FLUSH
/*****************************************************************************/ /*****************************************************************************/
/* PPC MMU emulation */ /* PowerPC MMU emulation */
/* Perform BAT hit & translation */ /* Perform BAT hit & translation */
static int get_bat (CPUState *env, uint32_t *real, int *prot, 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) if (rw)
error_code |= EXCP_DSI_STORE; error_code |= EXCP_DSI_STORE;
/* Store fault address */ /* Store fault address */
env->spr[DAR] = address; env->spr[SPR_DAR] = address;
} }
#if 0 #if 0
printf("%s: set exception to %d %02x\n", 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; 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) | return (xer_so << XER_SO) |
(xer_ov << XER_OV) | (xer_ov << XER_OV) |
(xer_ca << XER_CA) | (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_so = (value >> XER_SO) & 0x01;
xer_ov = (value >> XER_OV) & 0x01; xer_ov = (value >> XER_OV) & 0x01;
xer_ca = (value >> XER_CA) & 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_ile << MSR_ILE) |
(msr_ee << MSR_EE) | (msr_ee << MSR_EE) |
(msr_pr << MSR_PR) | (msr_pr << MSR_PR) |
@ -621,41 +835,141 @@ uint32_t _load_msr (CPUState *env)
(msr_se << MSR_SE) | (msr_se << MSR_SE) |
(msr_be << MSR_BE) | (msr_be << MSR_BE) |
(msr_fe1 << MSR_FE1) | (msr_fe1 << MSR_FE1) |
(msr_al << MSR_AL) |
(msr_ip << MSR_IP) | (msr_ip << MSR_IP) |
(msr_ir << MSR_IR) | (msr_ir << MSR_IR) |
(msr_dr << MSR_DR) | (msr_dr << MSR_DR) |
(msr_pe << MSR_PE) |
(msr_px << MSR_PX) |
(msr_ri << MSR_RI) | (msr_ri << MSR_RI) |
(msr_le << MSR_LE); (msr_le << MSR_LE);
} }
void _store_msr (CPUState *env, uint32_t value) void do_compute_hflags (CPUPPCState *env)
{ {
#ifdef ACCURATE_TLB_FLUSH /* Compute current hflags */
if (((value >> MSR_IR) & 0x01) != msr_ir || env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
((value >> MSR_DR) & 0x01) != msr_dr) (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
{ (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) |
/* Flush all tlb when changing translation mode or privilege level */ (msr_se << MSR_SE) | (msr_be << MSR_BE);
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 */
} }
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) #if defined (CONFIG_USER_ONLY)
void do_interrupt (CPUState *env) void do_interrupt (CPUState *env)
{ {
@ -675,7 +989,7 @@ void do_interrupt (CPUState *env)
int excp; int excp;
excp = env->exception_index; excp = env->exception_index;
msr = _load_msr(env); msr = do_load_msr(env);
#if defined (DEBUG_EXCEPTIONS) #if defined (DEBUG_EXCEPTIONS)
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) 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 * when the fault has been detected
*/ */
msr &= ~0xFFFF0000; msr &= ~0xFFFF0000;
env->spr[DSISR] = 0; env->spr[SPR_DSISR] = 0;
if ((env->error_code & 0x0f) == EXCP_DSI_TRANSLATE) 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) 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) { 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) if (env->error_code & EXCP_DSI_DIRECT)
env->spr[DSISR] |= 0x04000000; env->spr[SPR_DSISR] |= 0x04000000;
} }
if (env->error_code & EXCP_DSI_STORE) if (env->error_code & EXCP_DSI_STORE)
env->spr[DSISR] |= 0x02000000; env->spr[SPR_DSISR] |= 0x02000000;
if ((env->error_code & 0xF) == EXCP_DSI_DABR) if ((env->error_code & 0xF) == EXCP_DSI_DABR)
env->spr[DSISR] |= 0x00400000; env->spr[SPR_DSISR] |= 0x00400000;
if (env->error_code & EXCP_DSI_ECXW) if (env->error_code & EXCP_DSI_ECXW)
env->spr[DSISR] |= 0x00100000; env->spr[SPR_DSISR] |= 0x00100000;
#if defined (DEBUG_EXCEPTIONS) #if defined (DEBUG_EXCEPTIONS)
if (loglevel) { if (loglevel) {
fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", 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 { } else {
printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", 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 #endif
goto store_next; goto store_next;
@ -777,7 +1091,7 @@ void do_interrupt (CPUState *env)
case EXCP_ALIGN: case EXCP_ALIGN:
/* Store exception cause */ /* Store exception cause */
/* Get rS/rD and rA from faulting opcode */ /* Get rS/rD and rA from faulting opcode */
env->spr[DSISR] |= env->spr[SPR_DSISR] |=
(ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
/* data location address has been stored /* data location address has been stored
* when the fault has been detected * when the fault has been detected
@ -858,14 +1172,14 @@ void do_interrupt (CPUState *env)
return; return;
store_current: store_current:
/* SRR0 is set to current instruction */ /* SRR0 is set to current instruction */
env->spr[SRR0] = (uint32_t)env->nip - 4; env->spr[SPR_SRR0] = (uint32_t)env->nip - 4;
break; break;
store_next: store_next:
/* SRR0 is set to next instruction */ /* SRR0 is set to next instruction */
env->spr[SRR0] = (uint32_t)env->nip; env->spr[SPR_SRR0] = (uint32_t)env->nip;
break; break;
} }
env->spr[SRR1] = msr; env->spr[SPR_SRR1] = msr;
/* reload MSR with correct bits */ /* reload MSR with correct bits */
msr_pow = 0; msr_pow = 0;
msr_ee = 0; msr_ee = 0;
@ -879,6 +1193,7 @@ void do_interrupt (CPUState *env)
msr_dr = 0; msr_dr = 0;
msr_ri = 0; msr_ri = 0;
msr_le = msr_ile; msr_le = msr_ile;
do_compute_hflags(env);
/* Jump to handler */ /* Jump to handler */
env->nip = excp << 8; env->nip = excp << 8;
env->exception_index = EXCP_NONE; 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -130,7 +130,7 @@
#define REG 31 #define REG 31
#include "op_template.h" #include "op_template.h"
/* PPC state maintenance operations */ /* PowerPC state maintenance operations */
/* set_Rc0 */ /* set_Rc0 */
PPC_OP(set_Rc0) PPC_OP(set_Rc0)
{ {
@ -223,7 +223,7 @@ PPC_OP(load_srin)
PPC_OP(store_srin) PPC_OP(store_srin)
{ {
do_store_sr(T1 >> 28); do_store_sr(env, ((uint32_t)T1 >> 28), T0);
RETURN(); RETURN();
} }
@ -235,7 +235,7 @@ PPC_OP(load_sdr1)
PPC_OP(store_sdr1) PPC_OP(store_sdr1)
{ {
regs->sdr1 = T0; do_store_sdr1(env, T0);
RETURN(); RETURN();
} }
@ -247,13 +247,13 @@ PPC_OP(exit_tb)
/* Load/store special registers */ /* Load/store special registers */
PPC_OP(load_cr) PPC_OP(load_cr)
{ {
do_load_cr(); T0 = do_load_cr(env);
RETURN(); RETURN();
} }
PPC_OP(store_cr) PPC_OP(store_cr)
{ {
do_store_cr(PARAM(1)); do_store_cr(env, T0, PARAM(1));
RETURN(); RETURN();
} }
@ -279,25 +279,25 @@ PPC_OP(load_xer_bc)
PPC_OP(load_xer) PPC_OP(load_xer)
{ {
do_load_xer(); T0 = do_load_xer(env);
RETURN(); RETURN();
} }
PPC_OP(store_xer) PPC_OP(store_xer)
{ {
do_store_xer(); do_store_xer(env, T0);
RETURN(); RETURN();
} }
PPC_OP(load_msr) PPC_OP(load_msr)
{ {
do_load_msr(); T0 = do_load_msr(env);
RETURN(); RETURN();
} }
PPC_OP(store_msr) PPC_OP(store_msr)
{ {
do_store_msr(); do_store_msr(env, T0);
RETURN(); RETURN();
} }
@ -378,9 +378,20 @@ PPC_OP(load_ibat)
T0 = regs->IBAT[PARAM(1)][PARAM(2)]; 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) PPC_OP(load_dbat)
@ -388,21 +399,32 @@ PPC_OP(load_dbat)
T0 = regs->DBAT[PARAM(1)][PARAM(2)]; 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 */ /* FPSCR */
PPC_OP(load_fpscr) PPC_OP(load_fpscr)
{ {
do_load_fpscr(); FT0 = do_load_fpscr(env);
RETURN(); RETURN();
} }
PPC_OP(store_fpscr) PPC_OP(store_fpscr)
{ {
do_store_fpscr(PARAM(1)); do_store_fpscr(env, FT0, PARAM1);
RETURN(); RETURN();
} }
@ -1362,17 +1384,13 @@ PPC_OP(check_reservation)
/* Return from interrupt */ /* Return from interrupt */
PPC_OP(rfi) PPC_OP(rfi)
{ {
regs->nip = regs->spr[SRR0] & ~0x00000003; regs->nip = regs->spr[SPR_SRR0] & ~0x00000003;
#if 1 // TRY #if 1 // TRY
T0 = regs->spr[SRR1] & ~0xFFF00000; T0 = regs->spr[SPR_SRR1] & ~0xFFF00000;
#else #else
T0 = regs->spr[SRR1] & ~0xFFFF0000; T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000;
#endif #endif
do_store_msr(); do_store_msr(env, T0);
#if defined (DEBUG_OP)
dump_rfi();
#endif
// do_tlbia();
do_raise_exception(EXCP_RFI); do_raise_exception(EXCP_RFI);
RETURN(); RETURN();
} }
@ -1420,3 +1438,9 @@ PPC_OP(tlbie)
do_tlbie(); do_tlbie();
RETURN(); 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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 */ /* 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 */ /* shift right arithmetic helper */
void do_sraw (void) void do_sraw (void)
{ {
@ -175,77 +90,6 @@ void do_sraw (void)
} }
/* Floating point operations helpers */ /* 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) void do_fctiw (void)
{ {
union { union {
@ -254,7 +98,7 @@ void do_fctiw (void)
} p; } p;
/* XXX: higher bits are not supposed to be significant. /* 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 = float64_to_int32(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32; p.i |= 0xFFF80000ULL << 32;
@ -269,7 +113,7 @@ void do_fctiwz (void)
} p; } p;
/* XXX: higher bits are not supposed to be significant. /* 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 = float64_to_int32_round_to_zero(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32; p.i |= 0xFFF80000ULL << 32;
@ -455,116 +299,3 @@ void do_tlbie (void)
tlb_flush_page(env, T0); 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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) void OPPROTO glue(op_store_sr, REG)(void)
{ {
do_store_sr(REG); do_store_sr(env, REG, T0);
RETURN(); RETURN();
} }
#endif #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