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:
parent
2f636b458f
commit
3fc6c082e3
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
994
target-ppc/cpu.h
994
target-ppc/cpu.h
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
2069
target-ppc/translate_init.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user