diff --git a/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp b/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp index dac61656..eca62ad8 100644 --- a/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp +++ b/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp @@ -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 diff --git a/SheepShaver/src/kpx_cpu/spcflags.h b/SheepShaver/src/kpx_cpu/spcflags.h deleted file mode 100644 index a047aaea..00000000 --- a/SheepShaver/src/kpx_cpu/spcflags.h +++ /dev/null @@ -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 */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp index 6dcb6383..b4addc2c 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.cpp @@ -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 } diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp index ef2cb6b5..9ad89a33 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp @@ -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 } diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp index 55c8c2f3..4d206be8 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-registers.hpp @@ -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; diff --git a/SheepShaver/src/kpx_cpu/src/cpu/spcflags.hpp b/SheepShaver/src/kpx_cpu/src/cpu/spcflags.hpp new file mode 100644 index 00000000..5b73c639 --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/spcflags.hpp @@ -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 */