mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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
This commit is contained in:
@@ -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 {
|
||||
|
||||
+17
-3
@@ -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);
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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,
|
||||
|
||||
+5
-2
@@ -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);
|
||||
|
||||
+44
-6
@@ -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
|
||||
|
||||
@@ -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]) },
|
||||
|
||||
+18
-17
@@ -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"
|
||||
|
||||
+2
-6
@@ -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);
|
||||
|
||||
+6
-48
@@ -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;
|
||||
}
|
||||
|
||||
+38
-65
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+25
-25
@@ -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;
|
||||
|
||||
+3
-6
@@ -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;
|
||||
|
||||
+116
-126
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user