mirror of
https://git.proxmox.com/git/qemu
synced 2025-08-15 21:13:50 +00:00
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)
|
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)
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
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
|
* 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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -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
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