From 9fddaa0c0cabb610947146a79b4a9a38b0a216e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 21 May 2004 12:59:32 +0000 Subject: [PATCH] PowerPC merge: real time TB and decrementer - faster and simpler exception handling (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@841 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 5 +- cpu-exec.c | 20 +++- exec.c | 2 + hw/ppc.c | 175 +++++++++++++++++++++++++++++ hw/ppc_prep.c | 7 +- linux-user/main.c | 50 ++++++++- monitor.c | 24 +++- target-ppc/cpu.h | 35 +++--- target-ppc/exec.h | 8 +- target-ppc/helper.c | 54 +-------- target-ppc/op.c | 103 +++++++----------- target-ppc/op_helper.c | 50 ++++----- target-ppc/op_mem.h | 9 +- target-ppc/translate.c | 242 ++++++++++++++++++++--------------------- 14 files changed, 475 insertions(+), 309 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 69b6e7c365..bb6e74a3fd 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -627,14 +627,15 @@ void cpu_single_step(CPUState *env, int enabled); if no page found. */ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr); -#define CPU_LOG_TB_OUT_ASM (1 << 0) -#define CPU_LOG_TB_IN_ASM (1 << 1) +#define CPU_LOG_TB_OUT_ASM (1 << 0) +#define CPU_LOG_TB_IN_ASM (1 << 1) #define CPU_LOG_TB_OP (1 << 2) #define CPU_LOG_TB_OP_OPT (1 << 3) #define CPU_LOG_INT (1 << 4) #define CPU_LOG_EXEC (1 << 5) #define CPU_LOG_PCALL (1 << 6) #define CPU_LOG_IOPORT (1 << 7) +#define CPU_LOG_TB_CPU (1 << 8) /* define log items */ typedef struct CPULogItem { diff --git a/cpu-exec.c b/cpu-exec.c index 12e848b134..58468859dc 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -241,11 +241,25 @@ int cpu_exec(CPUState *env1) #endif } #elif defined(TARGET_PPC) +#if 0 + if ((interrupt_request & CPU_INTERRUPT_RESET)) { + cpu_ppc_reset(env); + } +#endif + if (msr_ee != 0) { if ((interrupt_request & CPU_INTERRUPT_HARD)) { - do_queue_exception(EXCP_EXTERNAL); - if (check_exception_state(env)) + /* Raise it */ + env->exception_index = EXCP_EXTERNAL; + env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { + /* Raise it */ + env->exception_index = EXCP_DECR; + env->error_code = 0; + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; + } } #endif if (interrupt_request & CPU_INTERRUPT_EXITTB) { @@ -757,7 +771,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - do_queue_exception_err(env->exception_index, env->error_code); + do_raise_exception_err(env->exception_index, env->error_code); } else { /* activate soft MMU for this block */ cpu_resume_from_signal(env, puc); diff --git a/exec.c b/exec.c index b484dc6d5d..695779ab25 100644 --- a/exec.c +++ b/exec.c @@ -1132,6 +1132,8 @@ CPULogItem cpu_log_items[] = { "show interrupts/exceptions in short format" }, { CPU_LOG_EXEC, "exec", "show trace before each executed TB (lots of logs)" }, + { CPU_LOG_TB_CPU, "cpu", + "show CPU state before bloc translation" }, #ifdef TARGET_I386 { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, diff --git a/hw/ppc.c b/hw/ppc.c index 7cba03b360..3858952a57 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -28,6 +28,181 @@ void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +/*****************************************************************************/ +/* PPC time base and decrementer emulation */ +//#define DEBUG_TB + +struct ppc_tb_t { + /* Time base management */ + int64_t tb_offset; /* Compensation */ + uint32_t tb_freq; /* TB frequency */ + /* Decrementer management */ + uint64_t decr_next; /* Tick for next decr interrupt */ + struct QEMUTimer *decr_timer; +}; + +static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) +{ + /* TB time in tb periods */ + return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, + tb_env->tb_freq, ticks_per_sec); +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env); +#ifdef DEBUG_TB + { + static int last_time; + int now; + now = time(NULL); + if (last_time != now) { + last_time = now; + printf("%s: tb=0x%016lx %d %08lx\n", + __func__, tb, now, tb_env->tb_offset); + } + } +#endif + + return tb & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env); +#ifdef DEBUG_TB + printf("%s: tb=0x%016lx\n", __func__, tb); +#endif + return tb >> 32; +} + +static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) +{ + tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) + - qemu_get_clock(vm_clock); +#ifdef DEBUG_TB + printf("%s: tb=0x%016lx offset=%08x\n", __func__, value); +#endif +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + + cpu_ppc_store_tb(tb_env, + ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + + cpu_ppc_store_tb(tb_env, + ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint32_t decr; + + decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock), + tb_env->tb_freq, ticks_per_sec); +#ifdef DEBUG_TB + printf("%s: 0x%08x\n", __func__, decr); +#endif + + return decr; +} + +/* When decrementer expires, + * all we need to do is generate or queue a CPU exception + */ +static inline void cpu_ppc_decr_excp (CPUState *env) +{ + /* Raise it */ +#ifdef DEBUG_TB + printf("raise decrementer exception\n"); +#endif + cpu_interrupt(env, CPU_INTERRUPT_TIMER); +} + +static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, + uint32_t value, int is_excp) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t now, next; + +#ifdef DEBUG_TB + printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value); +#endif + now = qemu_get_clock(vm_clock); + next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); + if (is_excp) + next += tb_env->decr_next - now; + if (next == now) + next++; + tb_env->decr_next = next; + /* Adjust timer */ + qemu_mod_timer(tb_env->decr_timer, next); + /* If we set a negative value and the decrementer was positive, + * raise an exception. + */ + if ((value & 0x80000000) && !(decr & 0x80000000)) + cpu_ppc_decr_excp(env); +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); +} + +static void cpu_ppc_decr_cb (void *opaque) +{ + _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); +} + +/* Set up (once) timebase frequency (in Hz) */ +ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) +{ + ppc_tb_t *tb_env; + + tb_env = qemu_mallocz(sizeof(ppc_tb_t)); + if (tb_env == NULL) + return NULL; + env->tb_env = tb_env; + if (tb_env->tb_freq == 0 || 1) { + tb_env->tb_freq = freq; + /* Create new timer */ + tb_env->decr_timer = + qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); + /* There is a bug in 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee, + * it's not ready to handle it... + */ + _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); + } + + return tb_env; +} + +#if 0 +/*****************************************************************************/ +/* Handle system reset (for now, just stop emulation) */ +void cpu_ppc_reset (CPUState *env) +{ + printf("Reset asked... Stop emulation\n"); + abort(); +} +#endif + +/*****************************************************************************/ void ppc_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index f64649cf5a..05783992b8 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -24,6 +24,9 @@ #include "vl.h" #include "m48t59.h" +/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */ +ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); + //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO @@ -663,7 +666,6 @@ static void VGA_printf (uint8_t *s) static void VGA_init (void) { /* Basic VGA init, inspired by plex86 VGAbios */ - printf("Init VGA...\n"); #if 1 /* switch to color mode and enable CPU access 480 lines */ PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); @@ -725,7 +727,6 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, * if a decrementer exception is pending when it enables msr_ee, * it's not ready to handle it... */ - env->decr = 0xFFFFFFFF; p = phys_ram_base + kernel_addr; #if !defined (USE_OPEN_FIRMWARE) /* Let's register the whole memory available only in supervisor mode */ @@ -948,6 +949,8 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, } } + cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); + /* init basic PC hardware */ vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0); diff --git a/linux-user/main.c b/linux-user/main.c index c0759bfefc..2275b01f97 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -504,6 +504,49 @@ void cpu_loop (CPUSPARCState *env) #endif #ifdef TARGET_PPC + +static inline uint64_t cpu_ppc_get_tb (CPUState *env) +{ + /* TO FIX */ + return 0; +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) +{ + /* TO FIX */ +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + /* TO FIX */ + return -1; +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + /* TO FIX */ +} + void cpu_loop(CPUPPCState *env) { target_siginfo_t info; @@ -812,7 +855,7 @@ void cpu_loop(CPUPPCState *env) abort(); case EXCP_MTMSR: /* We reloaded the msr, just go on */ - if (msr_pr) { + if (msr_pr == 0) { fprintf(stderr, "Tried to go into supervisor mode !\n"); if (loglevel) fprintf(logfile, "Tried to go into supervisor mode !\n"); @@ -842,12 +885,7 @@ void cpu_loop(CPUPPCState *env) } abort(); } - if (trapnr < EXCP_PPC_MAX) - env->exceptions &= ~(1 << trapnr); process_pending_signals(env); - if (env->exceptions != 0) { - check_exception_state(env); - } } } #endif diff --git a/monitor.c b/monitor.c index f5ab04336b..ab1c842bcd 100644 --- a/monitor.c +++ b/monitor.c @@ -589,6 +589,24 @@ static int monitor_get_xer (struct MonitorDef *md) (cpu_single_env->xer[XER_CA] << XER_CA) | (cpu_single_env->xer[XER_BC] << XER_BC); } + +uint32_t cpu_ppc_load_decr (CPUState *env); +static int monitor_get_decr (struct MonitorDef *md) +{ + return cpu_ppc_load_decr(cpu_single_env); +} + +uint32_t cpu_ppc_load_tbu (CPUState *env); +static int monitor_get_tbu (struct MonitorDef *md) +{ + return cpu_ppc_load_tbu(cpu_single_env); +} + +uint32_t cpu_ppc_load_tbl (CPUState *env); +static int monitor_get_tbl (struct MonitorDef *md) +{ + return cpu_ppc_load_tbl(cpu_single_env); +} #endif static MonitorDef monitor_defs[] = { @@ -651,12 +669,12 @@ static MonitorDef monitor_defs[] = { { "nip|pc", offsetof(CPUState, nip) }, { "lr", offsetof(CPUState, lr) }, { "ctr", offsetof(CPUState, ctr) }, - { "decr", offsetof(CPUState, decr) }, + { "decr", 0, &monitor_get_decr, }, { "ccr", 0, &monitor_get_ccr, }, { "msr", 0, &monitor_get_msr, }, { "xer", 0, &monitor_get_xer, }, - { "tbu", offsetof(CPUState, tb[0]) }, - { "tbl", offsetof(CPUState, tb[1]) }, + { "tbu", 0, &monitor_get_tbu, }, + { "tbl", 0, &monitor_get_tbl, }, { "sdr1", offsetof(CPUState, sdr1) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e6cb0946d7..bd430aff59 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -78,6 +78,8 @@ enum { #define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) +typedef struct ppc_tb_t ppc_tb_t; + /* Supervisor mode registers */ /* Machine state register */ #define MSR_POW 18 @@ -134,10 +136,6 @@ typedef struct CPUPPCState { /* special purpose registers */ uint32_t lr; uint32_t ctr; - /* Time base */ - uint32_t tb[2]; - /* decrementer */ - uint32_t decr; /* BATs */ uint32_t DBAT[2][8]; uint32_t IBAT[2][8]; @@ -154,13 +152,6 @@ typedef struct CPUPPCState { int error_code; int access_type; /* when a memory exception occurs, the access type is stored here */ -#if 0 /* TODO */ - uint32_t pending_exceptions; /* For external & decr exception, - * that can be delayed */ -#else - uint32_t exceptions; /* exception queue */ - uint32_t errors[32]; -#endif int user_mode_only; /* user mode only simulation */ struct TranslationBlock *current_tb; /* currently executing TB */ /* soft mmu support */ @@ -178,8 +169,13 @@ typedef struct CPUPPCState { /* ice debug support */ uint32_t breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; - int brkstate; - int singlestep_enabled; + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ + + /* Time base and decrementer */ + ppc_tb_t *tb_env; + + /* Power management */ + int power_mode; /* user data */ void *opaque; @@ -206,10 +202,15 @@ void _store_xer (CPUPPCState *env, uint32_t value); uint32_t _load_msr (CPUPPCState *env); void _store_msr (CPUPPCState *env, uint32_t value); -void PPC_init_hw (uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device, - const unsigned char *initrd_file); +/* Time-base and decrementer management */ +#ifndef NO_CPU_IO_DEFS +uint32_t cpu_ppc_load_tbl (CPUPPCState *env); +uint32_t cpu_ppc_load_tbu (CPUPPCState *env); +void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); +void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); +uint32_t cpu_ppc_load_decr (CPUPPCState *env); +void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); +#endif #define TARGET_PAGE_BITS 12 #include "cpu-all.h" diff --git a/target-ppc/exec.h b/target-ppc/exec.h index f4d20a8ad1..edb73ef056 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -119,12 +119,8 @@ static inline uint32_t rotl (uint32_t i, int n) #endif /* !defined(CONFIG_USER_ONLY) */ -int check_exception_state (CPUState *env); - -void do_queue_exception_err (uint32_t exception, int error_code); -void do_queue_exception (uint32_t exception); -void do_process_exceptions (void); -void do_check_exception_state (void); +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); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 09c0eebbee..e8b776b075 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -27,49 +27,10 @@ //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -extern FILE *logfile, *stdout, *stderr; -void exit (int); +extern FILE *stdout, *stderr; void abort (void); -void cpu_loop_exit(void) -{ - longjmp(env->jmp_env, 1); -} - -void do_process_exceptions (void) -{ - cpu_loop_exit(); -} - -int check_exception_state (CPUState *env) -{ - int i; - - /* Process PPC exceptions */ - for (i = 1; i < EXCP_PPC_MAX; i++) { - if (env->exceptions & (1 << i)) { - switch (i) { - case EXCP_EXTERNAL: - case EXCP_DECR: - if (msr_ee == 0) - return 0; - break; - case EXCP_PROGRAM: - if (env->errors[EXCP_PROGRAM] == EXCP_FP && - msr_fe0 == 0 && msr_fe1 == 0) - return 0; - break; - default: - break; - } - env->exception_index = i; - env->error_code = env->errors[i]; - return 1; - } - } - - return 0; -} +/*****************************************************************************/ /*****************************************************************************/ /* PPC MMU emulation */ @@ -500,8 +461,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) cpu_restore_state(tb, env, pc, NULL); } } - do_queue_exception_err(env->exception_index, env->error_code); - do_process_exceptions(); + do_raise_exception_err(env->exception_index, env->error_code); } { unsigned long tlb_addrr, tlb_addrw; @@ -701,9 +661,6 @@ void do_interrupt (CPUState *env) uint32_t msr; int excp = env->exception_index; - /* Dequeue PPC exceptions */ - if (excp < EXCP_PPC_MAX) - env->exceptions &= ~(1 << excp); msr = _load_msr(env); #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) @@ -812,7 +769,7 @@ void do_interrupt (CPUState *env) } #endif /* Requeue it */ - do_queue_exception(EXCP_EXTERNAL); + do_raise_exception(EXCP_EXTERNAL); return; } goto store_next; @@ -864,7 +821,7 @@ void do_interrupt (CPUState *env) case EXCP_DECR: if (msr_ee == 0) { /* Requeue it */ - do_queue_exception(EXCP_DECR); + do_raise_exception(EXCP_DECR); return; } goto store_next; @@ -937,4 +894,5 @@ void do_interrupt (CPUState *env) T0 = 0; #endif #endif + env->exception_index = -1; } diff --git a/target-ppc/op.c b/target-ppc/op.c index de7e247355..38eae7f74a 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -208,32 +208,28 @@ PPC_OP(set_T2) } /* Generate exceptions */ -PPC_OP(queue_exception_err) +PPC_OP(raise_exception_err) { - do_queue_exception_err(PARAM(1), PARAM(2)); + do_raise_exception_err(PARAM(1), PARAM(2)); } -PPC_OP(queue_exception) +PPC_OP(raise_exception) { - do_queue_exception(PARAM(1)); + do_raise_exception(PARAM(1)); } -PPC_OP(process_exceptions) +PPC_OP(update_nip) { env->nip = PARAM(1); - if (env->exceptions != 0) { - do_check_exception_state(); - } } PPC_OP(debug) { env->nip = PARAM(1); - env->brkstate = 1; #if defined (DEBUG_OP) dump_state(); #endif - do_queue_exception(EXCP_DEBUG); + do_raise_exception(EXCP_DEBUG); RETURN(); } @@ -364,58 +360,38 @@ PPC_OP(store_ctr) RETURN(); } -/* Update time base */ -PPC_OP(update_tb) +PPC_OP(load_tbl) { - T0 = regs->tb[0]; - T1 = T0; - T0 += PARAM(1); -#if defined (DEBUG_OP) - dump_update_tb(PARAM(1)); -#endif - if (T0 < T1) { - T1 = regs->tb[1] + 1; - regs->tb[1] = T1; + T0 = cpu_ppc_load_tbl(regs); + RETURN(); +} + +PPC_OP(load_tbu) +{ + T0 = cpu_ppc_load_tbu(regs); + RETURN(); +} + +PPC_OP(store_tbl) +{ + cpu_ppc_store_tbl(regs, T0); + RETURN(); +} + +PPC_OP(store_tbu) +{ + cpu_ppc_store_tbu(regs, T0); + RETURN(); +} + +PPC_OP(load_decr) +{ + T0 = cpu_ppc_load_decr(regs); } - regs->tb[0] = T0; - RETURN(); -} - -PPC_OP(load_tb) -{ - T0 = regs->tb[PARAM(1)]; - RETURN(); -} - -PPC_OP(store_tb) -{ - regs->tb[PARAM(1)] = T0; -#if defined (DEBUG_OP) - dump_store_tb(PARAM(1)); -#endif - RETURN(); -} - -/* Update decrementer */ -PPC_OP(update_decr) -{ - T0 = regs->decr; - T1 = T0; - T0 -= PARAM(1); - regs->decr = T0; - if (PARAM(1) > T1) { - do_queue_exception(EXCP_DECR); - } - RETURN(); -} PPC_OP(store_decr) { - T1 = regs->decr; - regs->decr = T0; - if (Ts0 < 0 && Ts1 > 0) { - do_queue_exception(EXCP_DECR); - } + cpu_ppc_store_decr(regs, T0); RETURN(); } @@ -1471,17 +1447,14 @@ PPC_OP(fneg) /* Return from interrupt */ PPC_OP(rfi) { + regs->nip = regs->spr[SRR0] & ~0x00000003; T0 = regs->spr[SRR1] & ~0xFFFF0000; do_store_msr(); - do_tlbia(); #if defined (DEBUG_OP) dump_rfi(); #endif - regs->nip = regs->spr[SRR0] & ~0x00000003; - do_queue_exception(EXCP_RFI); - if (env->exceptions != 0) { - do_check_exception_state(); - } + // do_tlbia(); + do_raise_exception(EXCP_RFI); RETURN(); } @@ -1493,7 +1466,7 @@ PPC_OP(tw) (Ts0 == Ts1 && (PARAM(1) & 0x04)) || (T0 < T1 && (PARAM(1) & 0x02)) || (T0 > T1 && (PARAM(1) & 0x01))) - do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); RETURN(); } @@ -1504,7 +1477,7 @@ PPC_OP(twi) (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) || (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) || (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01))) - do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index ae3d254d9f..3ddda1e335 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -31,31 +31,38 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void do_queue_exception_err (uint32_t exception, int error_code) +void cpu_loop_exit(void) { - /* Queue real PPC exceptions */ - if (exception < EXCP_PPC_MAX) { - env->exceptions |= 1 << exception; - env->errors[exception] = error_code; - } else { - /* Preserve compatibility with qemu core */ - env->exceptions |= 1; - env->exception_index = exception; - env->error_code = error_code; - } + longjmp(env->jmp_env, 1); } -void do_queue_exception (uint32_t exception) +void do_raise_exception_err (uint32_t exception, int error_code) { - do_queue_exception_err(exception, 0); +#if 0 + printf("Raise exception %3x code : %d\n", exception, error_code); +#endif + switch (exception) { + case EXCP_EXTERNAL: + case EXCP_DECR: + printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n"); + if (msr_ee == 0) + return; + break; + case EXCP_PROGRAM: + if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) + return; + break; + default: + break; } - -void do_check_exception_state (void) -{ - if ((env->exceptions & 1) == 1 || check_exception_state(env)) { - env->exceptions &= ~1; + env->exception_index = exception; + env->error_code = error_code; cpu_loop_exit(); } + +void do_raise_exception (uint32_t exception) +{ + do_raise_exception_err(exception, 0); } /*****************************************************************************/ @@ -125,13 +132,6 @@ void do_store_msr (void) /* Flush all tlb when changing translation mode or privilege level */ do_tlbia(); } -#if 0 - if ((T0 >> MSR_IP) & 0x01) { - printf("Halting CPU. Stop emulation\n"); - do_queue_exception(EXCP_HLT); - cpu_loop_exit(); - } -#endif msr_pow = (T0 >> MSR_POW) & 0x03; msr_ile = (T0 >> MSR_ILE) & 0x01; msr_ee = (T0 >> MSR_EE) & 0x01; diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 52f55c91b2..b5d10cecb8 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -97,8 +97,7 @@ PPC_OP(glue(lswx, MEMSUFFIX)) if (T1 > 0) { if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { - do_queue_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); - do_process_exceptions(); + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } else { glue(do_lsw, MEMSUFFIX)(PARAM(1)); } @@ -138,8 +137,7 @@ PPC_LDF_OP(fs, ldfl); PPC_OP(glue(lwarx, MEMSUFFIX)) { if (T0 & 0x03) { - do_queue_exception(EXCP_ALIGN); - do_process_exceptions(); + do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ldl, MEMSUFFIX)((void *)T0); regs->reserve = T0; @@ -151,8 +149,7 @@ PPC_OP(glue(lwarx, MEMSUFFIX)) PPC_OP(glue(stwcx, MEMSUFFIX)) { if (T0 & 0x03) { - do_queue_exception(EXCP_ALIGN); - do_process_exceptions(); + do_raise_exception(EXCP_ALIGN); } else { if (regs->reserve != T0) { env->crf[0] = xer_ov; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 009097302e..021cc7413f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -30,6 +30,7 @@ //#define DO_SINGLE_STEP //#define DO_STEP_FLUSH //#define DEBUG_DISAS +//#define PPC_DEBUG_DISAS enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, @@ -135,10 +136,6 @@ typedef struct DisasContext { uint32_t nip; uint32_t opcode; uint32_t exception; - /* Time base offset */ - uint32_t tb_offset; - /* Decrementer offset */ - uint32_t decr_offset; /* Execution mode */ #if !defined(CONFIG_USER_ONLY) int supervisor; @@ -156,21 +153,26 @@ typedef struct opc_handler_t { void (*handler)(DisasContext *ctx); } opc_handler_t; -#define RET_EXCP(excp, error) \ +#define RET_EXCP(ctx, excp, error) \ do { \ - gen_op_queue_exception_err(excp, error); \ - ctx->exception = excp; \ - return; \ + if ((ctx)->exception == EXCP_NONE) { \ + gen_op_update_nip((ctx)->nip); \ + } \ + gen_op_raise_exception_err((excp), (error)); \ + ctx->exception = (excp); \ } while (0) -#define RET_INVAL() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) +#define RET_INVAL(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) -#define RET_PRIVOPC() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) +#define RET_PRIVOPC(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) -#define RET_PRIVREG() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) +#define RET_PRIVREG(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) + +#define RET_MTMSR(ctx) \ +RET_EXCP((ctx), EXCP_MTMSR, 0) #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ static void gen_##name (DisasContext *ctx); \ @@ -312,29 +314,26 @@ GEN_OPCODE_MARK(start); /* Invalid instruction */ GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) { - RET_INVAL(); + RET_INVAL(ctx); } /* Special opcode to stop emulation */ GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) { - gen_op_queue_exception(EXCP_HLT); - ctx->exception = EXCP_HLT; + RET_EXCP(ctx, EXCP_HLT, 0); } /* Special opcode to call open-firmware */ GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON) { - gen_op_queue_exception(EXCP_OFCALL); - ctx->exception = EXCP_OFCALL; + RET_EXCP(ctx, EXCP_OFCALL, 0); } /* Special opcode to call RTAS */ GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON) { printf("RTAS entry point !\n"); - gen_op_queue_exception(EXCP_RTASCALL); - ctx->exception = EXCP_RTASCALL; + RET_EXCP(ctx, EXCP_RTASCALL, 0); } static opc_handler_t invalid_handler = { @@ -1010,7 +1009,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1025,7 +1025,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1086,7 +1087,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1100,7 +1102,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1236,7 +1239,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) nr = nb / 4; if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + return; } if (ra == 0) { gen_op_set_T0(0); @@ -1376,7 +1380,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1391,7 +1396,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1448,7 +1454,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1462,7 +1469,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1502,7 +1510,7 @@ GEN_STFS(fs, 0x14); /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { - RET_INVAL(); + RET_INVAL(ctx); } /*** Branch ***/ @@ -1512,9 +1520,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { uint32_t li = s_ext24(LI(ctx->opcode)), target; - gen_op_update_tb(ctx->tb_offset); - gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions(ctx->nip - 4); if (AA(ctx->opcode) == 0) target = ctx->nip + li - 4; else @@ -1538,10 +1543,6 @@ static inline void gen_bcond(DisasContext *ctx, int type) uint32_t mask; uint32_t li; - gen_op_update_tb(ctx->tb_offset); - gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions(ctx->nip - 4); - if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { @@ -1683,14 +1684,15 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else /* Restore CPU state */ if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } gen_op_rfi(); - ctx->exception = EXCP_RFI; + RET_EXCP(ctx, EXCP_RFI, 0); #endif } @@ -1698,11 +1700,10 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) - gen_op_queue_exception(EXCP_SYSCALL_USER); + RET_EXCP(ctx, EXCP_SYSCALL_USER, 0); #else - gen_op_queue_exception(EXCP_SYSCALL); + RET_EXCP(ctx, EXCP_SYSCALL, 0); #endif - ctx->exception = EXCP_SYSCALL; } /*** Trap ***/ @@ -1770,10 +1771,11 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_msr(); gen_op_store_T0_gpr(rD(ctx->opcode)); @@ -1792,11 +1794,11 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) #endif { case -1: - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); - break; + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + return; case 0: - RET_PRIVREG(); - break; + RET_PRIVREG(ctx); + return; default: break; } @@ -1910,19 +1912,13 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) gen_op_load_sdr1(); break; case V_TBL: - gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; - /* TBL is still in T0 */ + gen_op_load_tbl(); break; case V_TBU: - gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; - gen_op_load_tb(1); + gen_op_load_tbu(); break; case DECR: - gen_op_update_decr(ctx->decr_offset); - ctx->decr_offset = 0; - /* decr is still in T0 */ + gen_op_load_decr(); break; default: gen_op_load_spr(sprn); @@ -1939,18 +1935,16 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) /* We need to update the time base before reading it */ switch (sprn) { case V_TBL: - gen_op_update_tb(ctx->tb_offset); /* TBL is still in T0 */ + gen_op_load_tbl(); break; case V_TBU: - gen_op_update_tb(ctx->tb_offset); - gen_op_load_tb(1); + gen_op_load_tbu(); break; default: - RET_INVAL(); - break; + RET_INVAL(ctx); + return; } - ctx->tb_offset = 0; gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -1965,15 +1959,16 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - ctx->exception = EXCP_MTMSR; + RET_MTMSR(ctx); #endif } @@ -1995,10 +1990,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) #endif { case -1: - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); break; case 0: - RET_PRIVREG(); + RET_PRIVREG(ctx); break; default: break; @@ -2147,16 +2142,13 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) gen_op_tlbia(); break; case O_TBL: - gen_op_store_tb(0); - ctx->tb_offset = 0; + gen_op_store_tbl(); break; case O_TBU: - gen_op_store_tb(1); - ctx->tb_offset = 0; + gen_op_store_tbu(); break; case DECR: gen_op_store_decr(); - ctx->decr_offset = 0; break; default: gen_op_store_spr(sprn); @@ -2186,10 +2178,11 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); @@ -2274,10 +2267,11 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT) GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_sr(SR(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); @@ -2288,10 +2282,11 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_load_srin(); @@ -2303,14 +2298,18 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_sr(SR(ctx->opcode)); +#if 0 gen_op_tlbia(); + RET_MTMSR(ctx); +#endif #endif } @@ -2318,10 +2317,11 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); @@ -2336,10 +2336,13 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + if (loglevel) + fprintf(logfile, "%s: ! supervisor\n", __func__); + RET_PRIVOPC(ctx); + return; } gen_op_tlbia(); #endif @@ -2349,10 +2352,11 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_tlbie(); @@ -2363,10 +2367,11 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } /* This has no effect: it should ensure that all previous * tlbie have completed @@ -2916,7 +2921,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } fprintf(f, " ] "); - fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); + fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env)); for (i = 0; i < 16; i++) { if ((i & 3) == 0) fprintf(f, "FPR%02d:", i); @@ -2924,8 +2930,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) if ((i & 3) == 3) fprintf(f, "\n"); } - fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", - env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", + env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env)); fprintf(f, "reservation 0x%08x\n", env->reserve); fflush(f); } @@ -2952,7 +2958,6 @@ CPUPPCState *cpu_ppc_init(void) // env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ // env->spr[PVR] = 0x00070100; /* IBM 750FX */ #endif - env->decr = 0xFFFFFFFF; if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) return NULL; init_spr_rights(env->spr[PVR]); @@ -2976,14 +2981,13 @@ void cpu_ppc_close(CPUPPCState *env) } /*****************************************************************************/ -void raise_exception_err (int exception_index, int error_code); int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, int dialect); int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { - DisasContext ctx; + DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; uint32_t pc_start; uint16_t *gen_opc_end; @@ -2994,8 +2998,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; ctx.nip = pc_start; - ctx.tb_offset = 0; - ctx.decr_offset = 0; ctx.tb = tb; ctx.exception = EXCP_NONE; #if defined(CONFIG_USER_ONLY) @@ -3023,26 +3025,22 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_instr_start[lj] = 1; } } -#if defined DEBUG_DISAS - if (loglevel > 0) { +#if defined PPC_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "nip=%08x super=%d ir=%d\n", ctx.nip, 1 - msr_pr, msr_ir); } #endif ctx.opcode = ldl_code((void *)ctx.nip); -#if defined DEBUG_DISAS - if (loglevel > 0) { +#if defined PPC_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode)); } #endif ctx.nip += 4; - ctx.tb_offset++; - /* Check decrementer exception */ - if (++ctx.decr_offset == env->decr + 1) - ctx.exception = EXCP_DECR; table = ppc_opcodes; handler = table[opc1(ctx.opcode)]; if (is_indirect_opcode(handler)) { @@ -3098,26 +3096,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, (ctx.nip & 0xFC) != 0x04) && ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && ctx.exception != EXCP_TRAP)) { -#if !defined(CONFIG_USER_ONLY) - gen_op_queue_exception(EXCP_TRACE); -#endif - if (ctx.exception == EXCP_NONE) { - ctx.exception = EXCP_TRACE; - } + RET_EXCP(ctxp, EXCP_TRACE, 0); } /* if we reach a page boundary, stop generation */ if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { - if (ctx.exception == EXCP_NONE) { - gen_op_b((long)ctx.tb, ctx.nip); - ctx.exception = EXCP_BRANCH; + RET_EXCP(ctxp, EXCP_BRANCH, 0); } } - } - /* In case of branch, this has already been done *BEFORE* the branch */ - if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) { - gen_op_update_tb(ctx.tb_offset); - gen_op_update_decr(ctx.decr_offset); - gen_op_process_exceptions(ctx.nip); + if (ctx.exception == EXCP_NONE) { + gen_op_b((unsigned long)ctx.tb, ctx.nip); + } else if (ctx.exception != EXCP_BRANCH) { + gen_op_set_T0(0); } #if 1 /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump @@ -3144,15 +3133,16 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS - if (loglevel > 0) { + if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); cpu_ppc_dump_state(env, logfile, 0); + } + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); -#if defined(CONFIG_USER_ONLY) disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); -#endif fprintf(logfile, "\n"); - + } + if (loglevel & CPU_LOG_TB_OP) { fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n");