mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-27 02:49:42 +00:00
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:
parent
9ce43c6cf3
commit
89d0f9ca29
@ -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
|
||||
|
@ -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 */
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
62
SheepShaver/src/kpx_cpu/src/cpu/spcflags.hpp
Normal file
62
SheepShaver/src/kpx_cpu/src/cpu/spcflags.hpp
Normal 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 */
|
Loading…
Reference in New Issue
Block a user