Integrate spcflags handling code to kpx_cpu core. We can also remove

oldish EXEC_RETURN handling with a throw/catch mechanism since we
do have a dependency on extra conditions (invalidated cache) that
prevents fast execution loops.
This commit is contained in:
gbeauche 2003-11-01 15:15:31 +00:00
parent 9ce43c6cf3
commit 89d0f9ca29
6 changed files with 128 additions and 148 deletions

View File

@ -28,7 +28,6 @@
#include "macos_util.h"
#include "block-alloc.hpp"
#include "sigsegv.h"
#include "spcflags.h"
#include "cpu/ppc/ppc-cpu.hpp"
#include "cpu/ppc/ppc-operations.hpp"
@ -79,8 +78,6 @@ static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE;
* PowerPC emulator glue with special 'sheep' opcodes
**/
struct sheepshaver_exec_return { };
class sheepshaver_cpu
: public powerpc_cpu
{
@ -115,9 +112,6 @@ public:
void interrupt(uint32 entry);
void handle_interrupt();
// spcflags for interrupts handling
static uint32 spcflags;
// Lazy memory allocator (one item at a time)
void *operator new(size_t size)
{ return allocator_helper< sheepshaver_cpu, lazy_allocator >::allocate(); }
@ -128,7 +122,6 @@ public:
void operator delete[](void *p);
};
uint32 sheepshaver_cpu::spcflags = 0;
lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator;
sheepshaver_cpu::sheepshaver_cpu()
@ -189,7 +182,7 @@ void sheepshaver_cpu::execute_sheep(uint32 opcode)
break;
case 1: // EXEC_RETURN
throw sheepshaver_exec_return();
spcflags().set(SPCFLAG_CPU_EXEC_RETURN);
break;
case 2: // EXEC_NATIVE
@ -225,16 +218,7 @@ void sheepshaver_cpu::execute_sheep(uint32 opcode)
// Execution loop
void sheepshaver_cpu::execute(uint32 entry, bool enable_cache)
{
try {
powerpc_cpu::execute(entry, enable_cache);
}
catch (sheepshaver_exec_return const &) {
// Nothing, simply return
}
catch (...) {
printf("ERROR: execute() received an unknown exception!\n");
QuitEmulator();
}
powerpc_cpu::execute(entry, enable_cache);
}
// Handle MacOS interrupt

View File

@ -1,89 +0,0 @@
/*
* UAE - The Un*x Amiga Emulator
*
* MC68000 emulation
*
* Copyright 1995 Bernd Schmidt
*/
#ifndef SPCFLAGS_H
#define SPCFLAGS_H
typedef uint32 spcflags_t;
enum {
SPCFLAG_STOP = 0x01,
SPCFLAG_INT = 0x02,
SPCFLAG_DOINT = 0x04,
SPCFLAG_ENTER_MON = 0x08,
#if USE_JIT
SPCFLAG_JIT_END_COMPILE = 0x40,
SPCFLAG_JIT_EXEC_RETURN = 0x80,
#else
SPCFLAG_JIT_END_COMPILE = 0,
SPCFLAG_JIT_EXEC_RETURN = 0,
#endif
SPCFLAG_ALL = SPCFLAG_STOP
| SPCFLAG_INT
| SPCFLAG_DOINT
| SPCFLAG_ENTER_MON
| SPCFLAG_JIT_END_COMPILE
| SPCFLAG_JIT_EXEC_RETURN
,
SPCFLAG_ALL_BUT_EXEC_RETURN = SPCFLAG_ALL & ~SPCFLAG_JIT_EXEC_RETURN
};
#define SPCFLAGS_TEST(m) \
((sheepshaver_cpu::spcflags & (m)) != 0)
/* Macro only used in m68k_reset() */
#define SPCFLAGS_INIT(m) do { \
sheepshaver_cpu::spcflags = (m); \
} while (0)
#if !(ENABLE_EXCLUSIVE_SPCFLAGS)
#define SPCFLAGS_SET(m) do { \
sheepshaver_cpu::spcflags |= (m); \
} while (0)
#define SPCFLAGS_CLEAR(m) do { \
sheepshaver_cpu::spcflags &= ~(m); \
} while (0)
#elif defined(__i386__) && defined(X86_ASSEMBLY)
#define HAVE_HARDWARE_LOCKS
#define SPCFLAGS_SET(m) do { \
__asm__ __volatile__("lock\n\torl %1,%0" : "=m" (sheepshaver_cpu::spcflags) : "i" ((m))); \
} while (0)
#define SPCFLAGS_CLEAR(m) do { \
__asm__ __volatile__("lock\n\tandl %1,%0" : "=m" (sheepshaver_cpu::spcflags) : "i" (~(m))); \
} while (0)
#else
#undef HAVE_HARDWARE_LOCKS
#include "main.h"
extern B2_mutex *spcflags_lock;
#define SPCFLAGS_SET(m) do { \
B2_lock_mutex(spcflags_lock); \
sheepshaver_cpu::spcflags |= (m); \
B2_unlock_mutex(spcflags_lock); \
} while (0)
#define SPCFLAGS_CLEAR(m) do { \
B2_lock_mutex(spcflags_lock); \
sheepshaver_cpu::spcflags &= ~(m); \
B2_unlock_mutex(spcflags_lock); \
} while (0)
#endif
#endif /* SPCFLAGS_H */

View File

@ -208,14 +208,8 @@ void powerpc_cpu::initialize()
init_registers();
init_decode_cache();
// Init interrupts state
#if PPC_CHECK_INTERRUPTS
pending_interrupts = INTERRUPT_NONE;
#endif
// Init cache range invalidate recorder
cache_range.start = cache_range.end = 0;
invalidated_cache = false;
// Init syscalls handler
execute_do_syscall = NULL;
@ -281,6 +275,40 @@ void powerpc_cpu::fake_dump_registers(uint32)
dump_registers();
}
bool powerpc_cpu::check_spcflags()
{
#if PPC_CHECK_INTERRUPTS
if (spcflags().test(SPCFLAG_CPU_HANDLE_INTERRUPT)) {
spcflags().clear(SPCFLAG_CPU_HANDLE_INTERRUPT);
handle_interrupt();
}
if (spcflags().test(SPCFLAG_CPU_TRIGGER_INTERRUPT)) {
spcflags().clear(SPCFLAG_CPU_TRIGGER_INTERRUPT);
spcflags().set(SPCFLAG_CPU_HANDLE_INTERRUPT);
}
#endif
if (spcflags().test(SPCFLAG_CPU_EXEC_RETURN)) {
spcflags().clear(SPCFLAG_CPU_EXEC_RETURN);
return false;
}
if (spcflags().test(SPCFLAG_CPU_ENTER_MON)) {
spcflags().clear(SPCFLAG_CPU_ENTER_MON);
#if ENABLE_MON
// Start up mon in real-mode
char *arg[] = {
"mon",
#ifdef SHEEPSHAVER
"-m",
#endif
"-r",
NULL
};
mon(sizeof(arg)/sizeof(arg[0]) - 1, arg);
#endif
}
return true;
}
void powerpc_cpu::execute(uint32 entry, bool enable_cache)
{
pc() = entry;
@ -341,7 +369,6 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache)
decode_cache_p += bi->size;
// Execute all cached blocks
invalidated_cache = false;
for (;;) {
#ifdef PPC_LAZY_PC_UPDATE
pc() = bi->end_pc;
@ -367,9 +394,18 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache)
di += 4;
}
#endif
check_pending_interrupts();
if (!spcflags().empty()) {
if (!check_spcflags())
return;
if (invalidated_cache || ((bi->pc != pc()) && ((bi = block_cache.find(pc())) == NULL)))
// Force redecoding if cache was invalidated
if (spcflags().test(SPCFLAG_JIT_EXEC_RETURN)) {
spcflags().clear(SPCFLAG_JIT_EXEC_RETURN);
break;
}
}
if ((bi->pc != pc()) && ((bi = block_cache.find(pc())) == NULL))
break;
}
}
@ -393,7 +429,8 @@ void powerpc_cpu::execute(uint32 entry, bool enable_cache)
if (dump_state)
dump_registers();
#endif
check_pending_interrupts();
if (!spcflags().empty() && !check_spcflags())
return;
}
}
@ -440,7 +477,7 @@ void powerpc_cpu::invalidate_cache()
block_cache.clear();
block_cache.initialize();
decode_cache_p = decode_cache;
invalidated_cache = true;
spcflags().set(SPCFLAG_JIT_EXEC_RETURN);
#endif
}

View File

@ -39,6 +39,8 @@ class powerpc_cpu
protected:
powerpc_spcflags & spcflags() { return regs.spcflags; }
powerpc_spcflags const & spcflags() const { return regs.spcflags; }
powerpc_cr_register & cr() { return regs.cr; }
powerpc_cr_register const & cr() const { return regs.cr; }
powerpc_xer_register & xer() { return regs.xer; }
@ -143,7 +145,7 @@ protected:
struct instr_info_t {
char name[8]; // Mnemonic
execute_fn execute; // Semantic routine for this instruction
execute_fn execute_rc; // variant to record computed value
execute_fn decode; // Specialized instruction decoder
uint16 format; // Instruction format (XO-form, D-form, etc.)
uint16 opcode; // Primary opcode
uint16 xo; // Extended opcode
@ -191,6 +193,9 @@ private:
// Convert 8-bit field mask (e.g. mtcrf) to bit mask
uint32 field2mask[256];
// Check special CPU flags
bool check_spcflags();
public:
// Initialization & finalization
@ -227,17 +232,6 @@ public:
void execute();
// Interrupts handling
protected:
enum {
INTERRUPT_NONE = 0,
INTERRUPT_TRIGGER = 1,
INTERRUPT_HANDLE = 2
};
#if PPC_CHECK_INTERRUPTS
int pending_interrupts;
#endif
public:
void check_pending_interrupts();
void trigger_interrupt();
virtual void handle_interrupt() { }
@ -255,7 +249,6 @@ public:
void invalidate_cache_range(uintptr start, uintptr end);
private:
struct { uintptr start, end; } cache_range;
bool invalidated_cache;
protected:
@ -363,23 +356,7 @@ private:
inline void powerpc_cpu::trigger_interrupt()
{
#if PPC_CHECK_INTERRUPTS
pending_interrupts |= INTERRUPT_TRIGGER;
#endif
}
inline void powerpc_cpu::check_pending_interrupts()
{
#if PPC_CHECK_INTERRUPTS
if (pending_interrupts) {
if (pending_interrupts & INTERRUPT_HANDLE) {
pending_interrupts &= ~INTERRUPT_HANDLE;
handle_interrupt();
}
if (pending_interrupts & INTERRUPT_TRIGGER) {
pending_interrupts &= ~INTERRUPT_TRIGGER;
pending_interrupts |= INTERRUPT_HANDLE;
}
}
spcflags().set(SPCFLAG_CPU_TRIGGER_INTERRUPT);
#endif
}

View File

@ -336,6 +336,14 @@ powerpc_xer_register::set(uint32 xer)
}
/**
* Special CPU flags
**/
#include "cpu/spcflags.hpp"
typedef basic_spcflags powerpc_spcflags;
/**
* VEA Register Set
**/
@ -366,6 +374,7 @@ struct powerpc_registers
uint32 ctr; // Count Register (SPR 9)
uint32 pc; // Program Counter
uint32 tbl, tbu; // Time Base
powerpc_spcflags spcflags; // Special CPU flags
static uint32 reserve_valid;
static uint32 reserve_addr;
static uint32 reserve_data;

View File

@ -0,0 +1,62 @@
/*
* spcflags.hpp - CPU special flags
*
* Kheperix (C) 2003 Gwenole Beauchesne
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SPCFLAGS_H
#define SPCFLAGS_H
/**
* Basic special flags
**/
enum {
SPCFLAG_CPU_EXEC_RETURN = 1 << 0, // Return from emulation loop
SPCFLAG_CPU_TRIGGER_INTERRUPT = 1 << 1, // Trigger user interrupt
SPCFLAG_CPU_HANDLE_INTERRUPT = 1 << 2, // Call user interrupt handler
SPCFLAG_CPU_ENTER_MON = 1 << 3, // Enter cxmon
SPCFLAG_JIT_EXEC_RETURN = 1 << 4, // Return from compiled code
};
class basic_spcflags
{
uint32 mask;
public:
basic_spcflags()
: mask(0)
{ }
bool empty() const
{ return (mask == 0); }
bool test(uint32 v) const
{ return (mask & v); }
void init(uint32 v)
{ mask = v; }
void set(uint32 v)
{ mask |= v; }
void clear(uint32 v)
{ mask &= ~v; }
};
#endif /* SPCFLAGS_H */