]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
QEMU PPC memory bank update, cleanup.
authorToni Wilen <twilen@winuae.net>
Sat, 13 Sep 2014 17:23:29 +0000 (20:23 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 13 Sep 2014 17:23:29 +0000 (20:23 +0300)
debug.cpp
include/memory.h
include/uae/ppc.h
main.cpp
memory.cpp
ppc/ppc.cpp

index 17ba80f6fe6ca40ec721a7b746581bb0ca71957e..610cfd453952d51db96de78c0d30df5a1df72ef9 100644 (file)
--- a/debug.cpp
+++ b/debug.cpp
@@ -2966,7 +2966,7 @@ static void memory_map_dump_3(UaeMemoryMap *map, int log)
                                        a1 = get_sub_bank(&daddr);
                                        name = a1->name;
                                        for (;;) {
-                                               bankoffset2++;
+                                               bankoffset2 += MEMORY_MIN_SUBBANK;
                                                if (bankoffset2 >= 65536)
                                                        break;
                                                daddr = (j << 16) | bankoffset2;
@@ -2996,7 +2996,7 @@ static void memory_map_dump_3(UaeMemoryMap *map, int log)
                                        mirrored, mirrored ? size_out / mirrored : size_out, size_ext, name);
 #endif
                                tmp[0] = 0;
-                               if (a1->flags == ABFLAG_ROM && mirrored) {
+                               if ((a1->flags & ABFLAG_ROM) && mirrored) {
                                        TCHAR *p = txt + _tcslen (txt);
                                        uae_u32 crc = get_crc32 (a1->xlateaddr((j << 16) | bankoffset), (size * 1024) / mirrored);
                                        struct romdata *rd = getromdatabycrc (crc);
@@ -3008,24 +3008,26 @@ static void memory_map_dump_3(UaeMemoryMap *map, int log)
                                        }
                                }
 
-                               for (int m = 0; m < mirrored2; m++) {
-                                       UaeMemoryRegion *r = &map->regions[map->num_regions];
-                                       r->start = (j << 16) + bankoffset + region_size * m;
-                                       r->size = region_size;
-                                       r->flags = 0;
-                                       r->memory = NULL;
-                                       r->memory = dump_xlate((j << 16) | bankoffset);
-                                       if (r->memory)
-                                               r->flags |= UAE_MEMORY_REGION_RAM;
-                                       /* just to make it easier to spot in debugger */
-                                       r->alias = 0xffffffff;
-                                       if (m >= 0) {
-                                               r->alias = j << 16;
-                                               r->flags |= UAE_MEMORY_REGION_ALIAS | UAE_MEMORY_REGION_MIRROR;
+                               if (a1 != &dummy_bank) {
+                                       for (int m = 0; m < mirrored2; m++) {
+                                               UaeMemoryRegion *r = &map->regions[map->num_regions];
+                                               r->start = (j << 16) + bankoffset + region_size * m;
+                                               r->size = region_size;
+                                               r->flags = 0;
+                                               r->memory = NULL;
+                                               r->memory = dump_xlate((j << 16) | bankoffset);
+                                               if (r->memory)
+                                                       r->flags |= UAE_MEMORY_REGION_RAM;
+                                               /* just to make it easier to spot in debugger */
+                                               r->alias = 0xffffffff;
+                                               if (m >= 0) {
+                                                       r->alias = j << 16;
+                                                       r->flags |= UAE_MEMORY_REGION_ALIAS | UAE_MEMORY_REGION_MIRROR;
+                                               }
+                                               _stprintf(r->name, _T("%s"), name);
+                                               _stprintf(r->rom_name, _T("%s"), tmp);
+                                               map->num_regions += 1;
                                        }
-                                       _stprintf(r->name, _T("%s"), name);
-                                       _stprintf(r->rom_name, _T("%s"), tmp);
-                                       map->num_regions += 1;
                                }
 
 #if 1
index 695279a606112a20364ec4d790c6418e53dee70d..14c37e6f224e853564b058b3e9cc1b6fcd896820 100644 (file)
@@ -106,6 +106,7 @@ typedef struct {
        uae_u32 allocated;
 } addrbank;
 
+#define MEMORY_MIN_SUBBANK 1024
 struct addrbank_sub
 {
        addrbank *bank;
index 404ad8e506ed12256d07cd7880a52e15c23c8847..bbca1cd8b42b3c7f876338dbaabbb71b1236b5b5 100644 (file)
@@ -38,6 +38,7 @@ void uae_ppc_emulate(void);
 void uae_ppc_reset(bool hardreset);
 void uae_ppc_hsync_handler(void);
 void uae_ppc_wakeup(void);
+void ppc_map_banks(uae_u32, uae_u32, const TCHAR*, void*, bool);
 
 void uae_ppc_execute_quick(int linetype);
 void uae_ppc_spinlock_reset(void);
@@ -93,8 +94,9 @@ typedef struct PPCMemoryRegion {
     uint32_t alias;
 } PPCMemoryRegion;
 
-bool PPCCALL ppc_cpu_init(uint32_t pvr);
-bool PPCCALL ppc_cpu_init_with_model(const char *model);
+void PPCCALL ppc_cpu_version(int *major, int *minor, int *revision);
+bool PPCCALL ppc_cpu_init(const char *model, uint32_t hid1);
+bool PPCCALL ppc_cpu_init_pvr(uint32_t pvr);
 void PPCCALL ppc_cpu_free(void);
 void PPCCALL ppc_cpu_stop(void);
 void PPCCALL ppc_cpu_atomic_raise_ext_exception(void);
@@ -106,7 +108,14 @@ void PPCCALL ppc_cpu_run_single(int count);
 uint64_t PPCCALL ppc_cpu_get_dec(void);
 void PPCCALL ppc_cpu_do_dec(int value);
 void PPCCALL ppc_cpu_pause(int pause);
+void PPCCALL ppc_cpu_reset(void);
 
+#define PPC_CPU_STATE_RUNNING 1
+#define PPC_CPU_STATE_PAUSED 2
+
+//int PPCCALL ppc_cpu_get_state();
+bool PPCCALL ppc_cpu_check_state(int state);
+void PPCCALL ppc_cpu_set_state(int state);
 /* Other PPC defines */
 
 #define PPC_IMPLEMENTATION_AUTO 0
@@ -114,9 +123,10 @@ void PPCCALL ppc_cpu_pause(int pause);
 #define PPC_IMPLEMENTATION_PEARPC 2
 #define PPC_IMPLEMENTATION_QEMU 3
 
-#define PPC_STATE_STOP 0
-#define PPC_STATE_ACTIVE 1
-#define PPC_STATE_SLEEP 2
-#define PPC_STATE_CRASH 3
+#define PPC_STATE_INACTIVE 0
+#define PPC_STATE_STOP 1
+#define PPC_STATE_ACTIVE 2
+#define PPC_STATE_SLEEP 3
+#define PPC_STATE_CRASH 4
 
 #endif /* UAE_PPC_H */
index 4f84ea93944be0c3af5eccfc1133eb048f7ef504..489197243d57a01d60e20ce21dfd0077bd8c5a39 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -886,6 +886,9 @@ void reset_all_systems (void)
 {
        init_eventtab ();
 
+#ifdef WITH_PPC
+       uae_ppc_reset(false);
+#endif
 #ifdef PICASSO96
        picasso_reset ();
 #endif
@@ -924,9 +927,6 @@ void reset_all_systems (void)
        native2amiga_reset ();
        dongle_reset ();
        sampler_init ();
-#ifdef WITH_PPC
-       uae_ppc_reset(false);
-#endif
 }
 
 /* Okay, this stuff looks strange, but it is here to encourage people who
index 678e68075c4725405a09b6ca299c53cf247ccd68..f2ec4ed3e5012d303f8f0a2dd25a705054770e43 100644 (file)
@@ -35,6 +35,7 @@
 #include "debug.h"
 #include "gfxboard.h"
 #include "cpuboard.h"
+#include "uae/ppc.h"
 
 bool canbang;
 int candirect = -1;
@@ -2592,17 +2593,49 @@ static void map_banks2 (addrbank *bank, int start, int size, int realsize, int q
        fill_ce_banks ();
 }
 
+#ifdef WITH_PPC
+static void ppc_generate_map_banks(addrbank *bank, int start, int size)
+{
+       uae_u32 bankaddr = start << 16;
+       uae_u32 banksize = size << 16;
+       if (bank->sub_banks) {
+               uae_u32 subbankaddr = bankaddr;
+               addrbank *ab = NULL;
+               for (int i = 0; i <= 65536; i += MEMORY_MIN_SUBBANK) {
+                       uae_u32 addr = bankaddr + i;
+                       addrbank *ab2 = get_sub_bank(&addr);
+                       if (ab2 != ab && ab != NULL) {
+                               ppc_map_banks(subbankaddr, (bankaddr + i) - subbankaddr, ab->name, ab->baseaddr, ab == &dummy_bank);
+                               subbankaddr = bankaddr + i;
+                       }
+                       ab = ab2;
+               }
+       } else {
+               ppc_map_banks(bankaddr, banksize, bank->name, bank->baseaddr, bank == &dummy_bank);
+       }
+}
+#endif
+
 void map_banks (addrbank *bank, int start, int size, int realsize)
 {
        map_banks2 (bank, start, size, realsize, 0);
+#ifdef WITH_PPC
+       ppc_generate_map_banks(bank, start, size);
+#endif
 }
 void map_banks_quick (addrbank *bank, int start, int size, int realsize)
 {
        map_banks2 (bank, start, size, realsize, 1);
+#ifdef WITH_PPC
+       ppc_generate_map_banks(bank, start, size);
+#endif
 }
 void map_banks_nojitdirect (addrbank *bank, int start, int size, int realsize)
 {
        map_banks2 (bank, start, size, realsize, -1);
+#ifdef WITH_PPC
+       ppc_generate_map_banks(bank, start, size);
+#endif
 }
 
 #ifdef SAVESTATE
index 2f50065d6eef0b27a4963e586484142f8484caa9..b629045686cf9518aa332dda41fbb6eaba37e42e 100644 (file)
 
 #include "uae/ppc.h"
 
-#define PPC_SYNC_WRITE 0
+/* The qemu-uae major version must match this */
+#define QEMU_UAE_VERSION_MAJOR 1
+
+/* The qemu-uae minor version must be at least this */
+#define QEMU_UAE_VERSION_MINOR 2
+
 #define PPC_ACCESS_LOG 0
 
 #define PPC_DEBUG_ADDR_FROM 0x000000
 #include "pearpc/cpu/cpu_generic/ppc_cpu.h"
 #endif
 
-#define TRACE(format, ...) write_log(_T("PPC: ---------------- ") format, ## __VA_ARGS__)
-
+#define TRACE(format, ...) write_log(_T("PPC: ") format, ## __VA_ARGS__)
 
 #ifdef _WIN32
-static volatile unsigned int ppc_spinlock, spinlock_cnt;
+#define CRITICAL_SECTION_SPIN_COUNT 5000
+static CRITICAL_SECTION ppc_cs;
+static bool ppc_cs_initialized;
 #else
 #include <glib.h>
 static GMutex mutex;
@@ -38,14 +44,7 @@ static GMutex mutex;
 void uae_ppc_spinlock_get(void)
 {
 #ifdef _WIN32
-       int sp = spinlock_cnt;
-       if (sp != 0 && sp != 1)
-               write_log(_T("uae_ppc_spinlock_get invalid %d\n"),  sp);
-
-       while (InterlockedExchange (&ppc_spinlock, 1));
-       if (spinlock_cnt)
-               write_log(_T("uae_ppc_spinlock_get %d!\n"), spinlock_cnt);
-       spinlock_cnt = 1;
+       EnterCriticalSection(&ppc_cs);
 #else
        g_mutex_lock(&mutex);
 #endif
@@ -53,17 +52,21 @@ void uae_ppc_spinlock_get(void)
 void uae_ppc_spinlock_release(void)
 {
 #ifdef _WIN32
-       if (--spinlock_cnt)
-               write_log(_T("uae_ppc_spinlock_release %d!\n"), spinlock_cnt);
-       InterlockedExchange(&ppc_spinlock, 0);
+       LeaveCriticalSection(&ppc_cs);
 #else
        g_mutex_unlock(&mutex);
 #endif
 }
-void uae_ppc_spinlock_reset(void)
+
+static void uae_ppc_spinlock_create(void)
 {
-       spinlock_cnt = 0;
-       uae_ppc_spinlock_get();
+#ifdef _WIN32
+       if (ppc_cs_initialized)
+               DeleteCriticalSection(&ppc_cs);
+       InitializeCriticalSectionAndSpinCount(&ppc_cs, CRITICAL_SECTION_SPIN_COUNT);
+#else
+#endif
+       ppc_cs_initialized = true;
 }
 
 volatile int ppc_state;
@@ -71,9 +74,6 @@ static volatile bool ppc_thread_running;
 int ppc_cycle_count;
 static volatile bool ppc_access;
 static volatile int ppc_cpu_lock_state;
-static bool ppc_main_thread;
-static bool ppc_io_pipe;
-static bool ppc_use_spinlock;
 static bool ppc_init_done;
 static bool ppc_cpu_init_done;
 static int ppc_implementation;
@@ -86,8 +86,6 @@ static int ppc_implementation;
 
 /* Dummy PPC implementation */
 
-static bool PPCCALL dummy_ppc_cpu_init(uint32_t pvr) { return false; }
-static bool PPCCALL dummy_ppc_cpu_init_with_model(const char *model) { return false; }
 static void PPCCALL dummy_ppc_cpu_free(void) { }
 static void PPCCALL dummy_ppc_cpu_stop(void) { }
 static void PPCCALL dummy_ppc_cpu_atomic_raise_ext_exception(void) { }
@@ -96,8 +94,15 @@ static void PPCCALL dummy_ppc_cpu_map_memory(PPCMemoryRegion *regions, int count
 static void PPCCALL dummy_ppc_cpu_set_pc(int cpu, uint32_t value) { }
 static void PPCCALL dummy_ppc_cpu_run_continuous(void) { }
 static void PPCCALL dummy_ppc_cpu_run_single(int count) { }
-static uint64_t PPCCALL dummy_ppc_cpu_get_dec(void) { return 0; }
-static void PPCCALL dummy_ppc_cpu_do_dec(int value) { }
+//static uint64_t PPCCALL dummy_ppc_cpu_get_dec(void) { return 0; }
+//static void PPCCALL dummy_ppc_cpu_do_dec(int value) { }
+
+static void PPCCALL dummy_ppc_cpu_version(int *major, int *minor, int *revision)
+{
+    *major = QEMU_UAE_VERSION_MAJOR;
+    *minor = QEMU_UAE_VERSION_MINOR;
+    *revision = 0;
+}
 
 static void PPCCALL dummy_ppc_cpu_pause(int pause)
 {
@@ -105,8 +110,9 @@ static void PPCCALL dummy_ppc_cpu_pause(int pause)
 
 /* Functions typedefs for PPC implementation */
 
-typedef bool (PPCCALL *ppc_cpu_init_function)(uint32_t pvr);
-typedef bool (PPCCALL *ppc_cpu_init_with_model_function)(const char *model);
+typedef void (PPCCALL *ppc_cpu_version_function)(int *major, int *minor, int *revision);
+typedef bool (PPCCALL *ppc_cpu_init_function)(const char *model, uint32_t hid1);
+typedef bool (PPCCALL *ppc_cpu_init_pvr_function)(uint32_t pvr);
 typedef void (PPCCALL *ppc_cpu_free_function)(void);
 typedef void (PPCCALL *ppc_cpu_stop_function)(void);
 typedef void (PPCCALL *ppc_cpu_atomic_raise_ext_exception_function)(void);
@@ -118,43 +124,52 @@ typedef void (PPCCALL *ppc_cpu_run_single_function)(int count);
 typedef uint64_t (PPCCALL *ppc_cpu_get_dec_function)(void);
 typedef void (PPCCALL *ppc_cpu_do_dec_function)(int value);
 typedef void (PPCCALL *ppc_cpu_pause_function)(int pause);
+typedef bool (PPCCALL *ppc_cpu_check_state_function)(int state);
+typedef void (PPCCALL *ppc_cpu_set_state_function)(int state);
+typedef void (PPCCALL *ppc_cpu_reset_function)(void);
 
 /* Function pointers to active PPC implementation */
 
-static ppc_cpu_init_function g_ppc_cpu_init;
-static ppc_cpu_init_with_model_function g_ppc_cpu_init_with_model;
-static ppc_cpu_free_function g_ppc_cpu_free;
-static ppc_cpu_stop_function g_ppc_cpu_stop;
-static ppc_cpu_atomic_raise_ext_exception_function g_ppc_cpu_atomic_raise_ext_exception;
-static ppc_cpu_atomic_cancel_ext_exception_function g_ppc_cpu_atomic_cancel_ext_exception;
-static ppc_cpu_map_memory_function g_ppc_cpu_map_memory;
-static ppc_cpu_set_pc_function g_ppc_cpu_set_pc;
-static ppc_cpu_run_continuous_function g_ppc_cpu_run_continuous;
-static ppc_cpu_run_single_function g_ppc_cpu_run_single;
-static ppc_cpu_get_dec_function g_ppc_cpu_get_dec;
-static ppc_cpu_do_dec_function g_ppc_cpu_do_dec;
-static ppc_cpu_pause_function g_ppc_cpu_pause;
+static struct {
+       /* Common */
+       ppc_cpu_atomic_raise_ext_exception_function atomic_raise_ext_exception;
+       ppc_cpu_atomic_cancel_ext_exception_function atomic_cancel_ext_exception;
+       ppc_cpu_run_continuous_function run_continuous;
+
+       /* PearPC */
+       ppc_cpu_init_pvr_function init_pvr;
+       ppc_cpu_pause_function pause;
+       ppc_cpu_free_function free;
+       ppc_cpu_stop_function stop;
+       ppc_cpu_set_pc_function set_pc;
+       ppc_cpu_run_single_function run_single;
+       ppc_cpu_get_dec_function get_dec;
+       ppc_cpu_do_dec_function do_dec;
+
+       /* QEMU */
+       ppc_cpu_version_function version;
+       ppc_cpu_init_function init;
+       ppc_cpu_map_memory_function map_memory;
+       ppc_cpu_check_state_function check_state;
+       ppc_cpu_set_state_function set_state;
+       ppc_cpu_reset_function reset;
+} impl;
 
 static void load_dummy_implementation()
 {
        write_log(_T("PPC: Loading dummy implementation\n"));
-       g_ppc_cpu_init = dummy_ppc_cpu_init;
-       g_ppc_cpu_init_with_model = dummy_ppc_cpu_init_with_model;
-       g_ppc_cpu_free = dummy_ppc_cpu_free;
-       g_ppc_cpu_stop = dummy_ppc_cpu_stop;
-       g_ppc_cpu_atomic_raise_ext_exception = dummy_ppc_cpu_atomic_raise_ext_exception;
-       g_ppc_cpu_atomic_cancel_ext_exception = dummy_ppc_cpu_atomic_cancel_ext_exception;
-       g_ppc_cpu_map_memory = dummy_ppc_cpu_map_memory;
-       g_ppc_cpu_set_pc = dummy_ppc_cpu_set_pc;
-       g_ppc_cpu_run_continuous = dummy_ppc_cpu_run_continuous;
-       g_ppc_cpu_run_single = dummy_ppc_cpu_run_single;
-       g_ppc_cpu_get_dec = dummy_ppc_cpu_get_dec;
-       g_ppc_cpu_do_dec = dummy_ppc_cpu_do_dec;
-       g_ppc_cpu_pause = dummy_ppc_cpu_pause;
+       memset(&impl, 0, sizeof(impl));
+       impl.free = dummy_ppc_cpu_free;
+       impl.stop = dummy_ppc_cpu_stop;
+       impl.atomic_raise_ext_exception = dummy_ppc_cpu_atomic_raise_ext_exception;
+       impl.atomic_cancel_ext_exception = dummy_ppc_cpu_atomic_cancel_ext_exception;
+       impl.map_memory = dummy_ppc_cpu_map_memory;
+       impl.set_pc = dummy_ppc_cpu_set_pc;
+       impl.run_continuous = dummy_ppc_cpu_run_continuous;
+       impl.run_single = dummy_ppc_cpu_run_single;
+       impl.pause = dummy_ppc_cpu_pause;
 }
 
-#ifdef WITH_QEMU_CPU
-
 static void uae_patch_library_ppc(UAE_DLHANDLE handle)
 {
        void *ptr;
@@ -178,9 +193,10 @@ static void uae_patch_library_ppc(UAE_DLHANDLE handle)
 
 static bool load_qemu_implementation()
 {
+#ifdef WITH_QEMU_CPU
        write_log(_T("PPC: Loading QEmu implementation\n"));
-       // FIXME: replace with a callback to get the qemu path (so it can be
-       // implemented separately by WinUAE and FS-UAE.
+       memset(&impl, 0, sizeof(impl));
+
        UAE_DLHANDLE handle = uae_dlopen(_T("qemu-uae.dll"));
        if (!handle) {
                gui_message(_T("PPC: Error loading qemu-uae library\n"));
@@ -188,78 +204,104 @@ static bool load_qemu_implementation()
        }
        write_log(_T("PPC: Loaded qemu-uae library at %p\n"), handle);
 
-       /* get function pointers */
-
-       g_ppc_cpu_init = (ppc_cpu_init_function) uae_dlsym(handle, "ppc_cpu_init");
-       g_ppc_cpu_init_with_model = (ppc_cpu_init_with_model_function) uae_dlsym(handle, "ppc_cpu_init_with_model");
-       g_ppc_cpu_free = (ppc_cpu_free_function) uae_dlsym(handle, "ppc_cpu_free");
-       g_ppc_cpu_stop = (ppc_cpu_stop_function) uae_dlsym(handle, "ppc_cpu_stop");
-       g_ppc_cpu_atomic_raise_ext_exception = (ppc_cpu_atomic_raise_ext_exception_function) uae_dlsym(handle, "ppc_cpu_atomic_raise_ext_exception");
-       g_ppc_cpu_atomic_cancel_ext_exception = (ppc_cpu_atomic_cancel_ext_exception_function) uae_dlsym(handle, "ppc_cpu_atomic_cancel_ext_exception");
-       g_ppc_cpu_map_memory = (ppc_cpu_map_memory_function) uae_dlsym(handle, "ppc_cpu_map_memory");
-       g_ppc_cpu_set_pc = (ppc_cpu_set_pc_function) uae_dlsym(handle, "ppc_cpu_set_pc");
-       g_ppc_cpu_run_continuous = (ppc_cpu_run_continuous_function) uae_dlsym(handle, "ppc_cpu_run_continuous");
-       g_ppc_cpu_run_single = (ppc_cpu_run_single_function) uae_dlsym(handle, "ppc_cpu_run_single");
-       g_ppc_cpu_get_dec = (ppc_cpu_get_dec_function) uae_dlsym(handle, "ppc_cpu_get_dec");
-       g_ppc_cpu_do_dec = (ppc_cpu_do_dec_function) uae_dlsym(handle, "ppc_cpu_do_dec");
-       g_ppc_cpu_pause = (ppc_cpu_pause_function) uae_dlsym(handle, "ppc_cpu_pause");
+       /* Retrieve function pointers from library */
+
+       impl.version = (ppc_cpu_version_function) uae_dlsym(handle, "ppc_cpu_version");
+       //impl.init = (ppc_cpu_init_function) uae_dlsym(handle, "ppc_cpu_init");
+       impl.init = (ppc_cpu_init_function) uae_dlsym(handle, "ppc_cpu_init");
+       //impl.free = (ppc_cpu_free_function) uae_dlsym(handle, "ppc_cpu_free");
+       //impl.stop = (ppc_cpu_stop_function) uae_dlsym(handle, "ppc_cpu_stop");
+       impl.atomic_raise_ext_exception = (ppc_cpu_atomic_raise_ext_exception_function) uae_dlsym(handle, "ppc_cpu_atomic_raise_ext_exception");
+       impl.atomic_cancel_ext_exception = (ppc_cpu_atomic_cancel_ext_exception_function) uae_dlsym(handle, "ppc_cpu_atomic_cancel_ext_exception");
+       impl.map_memory = (ppc_cpu_map_memory_function) uae_dlsym(handle, "ppc_cpu_map_memory");
+       //impl.set_pc = (ppc_cpu_set_pc_function) uae_dlsym(handle, "ppc_cpu_set_pc");
+       impl.run_continuous = (ppc_cpu_run_continuous_function) uae_dlsym(handle, "ppc_cpu_run_continuous");
+       //impl.run_single = (ppc_cpu_run_single_function) uae_dlsym(handle, "ppc_cpu_run_single");
+       //impl.get_dec = (ppc_cpu_get_dec_function) uae_dlsym(handle, "ppc_cpu_get_dec");
+       //impl.do_dec = (ppc_cpu_do_dec_function) uae_dlsym(handle, "ppc_cpu_do_dec");
+       //impl.pause = (ppc_cpu_pause_function) uae_dlsym(handle, "ppc_cpu_pause");
+       impl.check_state = (ppc_cpu_check_state_function) uae_dlsym(handle, "ppc_cpu_check_state");
+       impl.set_state = (ppc_cpu_set_state_function) uae_dlsym(handle, "ppc_cpu_set_state");
+       impl.reset = (ppc_cpu_reset_function) uae_dlsym(handle, "ppc_cpu_reset");
+
+       /* Check major version (=) and minor version (>=) */
+
+       int major = 0, minor = 0, revision = 0;
+       if (impl.version) {
+               impl.version(&major, &minor, &revision);
+       }
+       if (major != QEMU_UAE_VERSION_MAJOR) {
+               gui_message(_T("PPC: Wanted qemu-uae version %d.x (got %d.x)\n"),
+                       QEMU_UAE_VERSION_MAJOR, major);
+               return false;
+       }
+       if (minor < QEMU_UAE_VERSION_MINOR) {
+               gui_message(_T("PPC: Wanted qemu-uae version >= %d.%d (got %d.%d)\n"),
+                       QEMU_UAE_VERSION_MAJOR, QEMU_UAE_VERSION_MINOR,
+                       major, minor);
+               return false;
+       }
 
-#if 0
-       /* register callback functions */
-#endif
+        // FIXME: not needed, handled internally by uae_dlopen_plugin
+        // uae_dlopen_patch_common(handle);
 
         uae_patch_library_common(handle);
         uae_patch_library_ppc(handle);
         return true;
-}
-
+#else
+       return false;
 #endif
-
-#ifdef WITH_PEARPC_CPU
+}
 
 static bool load_pearpc_implementation()
 {
+#ifdef WITH_PEARPC_CPU
        write_log(_T("PPC: Loading PearPC implementation\n"));
-       g_ppc_cpu_init = ppc_cpu_init;
-       g_ppc_cpu_init_with_model = NULL;
-       g_ppc_cpu_free = ppc_cpu_free;
-       g_ppc_cpu_stop = ppc_cpu_stop;
-       g_ppc_cpu_atomic_raise_ext_exception = ppc_cpu_atomic_raise_ext_exception;
-       g_ppc_cpu_atomic_cancel_ext_exception = ppc_cpu_atomic_cancel_ext_exception;
-
-       g_ppc_cpu_map_memory = dummy_ppc_cpu_map_memory;
-
-       g_ppc_cpu_set_pc = ppc_cpu_set_pc;
-       g_ppc_cpu_run_continuous = ppc_cpu_run_continuous;
-       g_ppc_cpu_run_single = ppc_cpu_run_single;
-       g_ppc_cpu_get_dec = ppc_cpu_get_dec;
-       g_ppc_cpu_do_dec = ppc_cpu_do_dec;
+       memset(&impl, 0, sizeof(impl));
+
+       impl.init_pvr = ppc_cpu_init;
+       impl.free = ppc_cpu_free;
+       impl.stop = ppc_cpu_stop;
+       impl.atomic_raise_ext_exception = ppc_cpu_atomic_raise_ext_exception;
+       impl.atomic_cancel_ext_exception = ppc_cpu_atomic_cancel_ext_exception;
+       impl.set_pc = ppc_cpu_set_pc;
+       impl.run_continuous = ppc_cpu_run_continuous;
+       impl.run_single = ppc_cpu_run_single;
+       impl.get_dec = ppc_cpu_get_dec;
+       impl.do_dec = ppc_cpu_do_dec;
        return true;
-}
-
+#else
+       return false;
 #endif
+}
 
 static void load_ppc_implementation()
 {
        int impl = currprefs.ppc_implementation;
-#ifdef WITH_QEMU_CPU
        if (impl == PPC_IMPLEMENTATION_AUTO || impl == PPC_IMPLEMENTATION_QEMU) {
                if (load_qemu_implementation()) {
                        ppc_implementation = PPC_IMPLEMENTATION_QEMU;
                        return;
                }
        }
-#endif
-#ifdef WITH_PEARPC_CPU
        if (impl == PPC_IMPLEMENTATION_AUTO || impl == PPC_IMPLEMENTATION_PEARPC) {
                if (load_pearpc_implementation()) {
                        ppc_implementation = PPC_IMPLEMENTATION_PEARPC;
                        return;
                }
        }
-#endif
        load_dummy_implementation();
-       ppc_implementation = 0;
+       ppc_implementation = PPC_IMPLEMENTATION_DUMMY;
+}
+
+static bool using_qemu()
+{
+       return ppc_implementation == PPC_IMPLEMENTATION_QEMU;
+}
+
+static bool using_pearpc()
+{
+       return ppc_implementation == PPC_IMPLEMENTATION_PEARPC;
 }
 
 static void initialize()
@@ -268,13 +310,22 @@ static void initialize()
        if (initialized) {
                return;
        }
+
        initialized = true;
+
        load_ppc_implementation();
+
+       uae_ppc_spinlock_create();
+       /* Grab the lock for the first time. This lock will be released
+        * by the UAE emulation thread when the PPC CPU can do I/O. */
+       uae_ppc_spinlock_get();
 }
 
 static void map_banks(void)
 {
-       /*
+       if (impl.map_memory == NULL)
+               return;
+/*
         * Use NULL to get callbacks to uae_ppc_io_mem_read/write. Use real
         * memory address for direct access to RAM banks (looks like this
         * is needed by JIT, or at least more work is needed on QEmu Side
@@ -293,21 +344,54 @@ static void map_banks(void)
                regions[i].alias = r->alias;
                regions[i].memory = r->memory;
        }
-       g_ppc_cpu_map_memory(regions, map.num_regions);
+       impl.map_memory(regions, map.num_regions);
        for (int i = 0; i < map.num_regions; i++) {
                free((void*)regions[i].name);
        }
 }
 
-static void cpu_init()
+static void set_and_wait_for_state(int state, int unlock)
+{
+       if (using_qemu()) {
+               impl.set_state(state);
+               while (!impl.check_state(state)) {
+                       if (unlock) {
+                               uae_ppc_spinlock_release();
+                       }
+                       sleep_millis(1);
+                       if (unlock) {
+                               uae_ppc_spinlock_get();
+                       }
+               }
+       }
+}
+
+void ppc_map_banks(uae_u32 start, uae_u32 size, const TCHAR *name, void *addr, bool remove)
+{
+       if (ppc_state == PPC_STATE_INACTIVE)
+               return;
+       PPCMemoryRegion r;
+       r.start = start;
+       r.size = size;
+       r.name = ua(name);
+       r.alias = remove ? 0xffffffff : 0;
+       r.memory = addr;
+       impl.map_memory(&r, -1);
+       free((void*)r.name);
+}
+
+static void cpu_init(void)
 {
        const TCHAR *model;
+       uint32_t hid1;
 
-       /* Setting default CPU model based on accelerator board */
+       /* Set default CPU model based on accelerator board */
        if (currprefs.cpuboard_type == BOARD_BLIZZARDPPC) {
                model = _T("603ev");
+               hid1 = 0xc0000000; // 4x
        } else {
                model = _T("604e");
+               hid1 = 0xa0000000; // 4x
        }
 
         /* Override PPC CPU model. See qemu/target-ppc/cpu-models.c for
@@ -319,11 +403,11 @@ static void cpu_init()
        }
 #endif
 
-       if (g_ppc_cpu_init_with_model) {
+       if (impl.init) {
                char *models = ua(model);
-               g_ppc_cpu_init_with_model(models);
+               impl.init(models, hid1);
                free(models);
-       } else {
+       } else if (impl.init_pvr) {
                uint32_t pvr = 0;
                if (_tcsicmp(model, _T("603ev")) == 0) {
                        pvr = BLIZZPPC_PVR;
@@ -336,37 +420,48 @@ static void cpu_init()
                        write_log(_T("PPC: Unrecognized model \"%s\", using PVR 0x%08x\n"), model, pvr);
                }
                write_log(_T("PPC: Calling ppc_cpu_init with PVR 0x%08x\n"), pvr);
-               g_ppc_cpu_init(pvr);
+               impl.init_pvr(pvr);
        }
-
-       /* Map memory and I/O banks (for QEmu PPC implementation) */
-       map_banks();
 }
 
 static void uae_ppc_cpu_reset(void)
 {
        TRACE(_T("uae_ppc_cpu_reset\n"));
+       
        initialize();
+
        if (!ppc_cpu_init_done) {
                write_log(_T("PPC: Hard reset\n"));
                cpu_init();
                ppc_cpu_init_done = true;
        }
-       write_log(_T("PPC: Init\n"));
-       g_ppc_cpu_set_pc(0, 0xfff00100);
-       ppc_cycle_count = 2000;
-       ppc_state = PPC_STATE_ACTIVE;
+
+       /* Map memory and I/O banks (for QEmu PPC implementation) */
+       map_banks();
+
+       if (using_qemu()) {
+               impl.reset();
+       } else if (using_pearpc()) {
+               write_log(_T("PPC: Init\n"));
+               impl.set_pc(0, 0xfff00100);
+               ppc_cycle_count = 2000;
+       }
+
        ppc_cpu_lock_state = 0;
+       ppc_state = PPC_STATE_ACTIVE;
 }
 
 static void *ppc_thread(void *v)
 {
        uae_ppc_cpu_reset();
-       g_ppc_cpu_run_continuous();
-       if (ppc_state == PPC_STATE_ACTIVE || ppc_state == PPC_STATE_SLEEP)
-               ppc_state = PPC_STATE_STOP;
-       write_log(_T("ppc_cpu_run() exited.\n"));
-       ppc_thread_running = false;
+       impl.run_continuous();
+
+       if (using_pearpc()) {
+               if (ppc_state == PPC_STATE_ACTIVE || ppc_state == PPC_STATE_SLEEP)
+                       ppc_state = PPC_STATE_STOP;
+               write_log(_T("ppc_cpu_run() exited.\n"));
+               ppc_thread_running = false;
+       }
        return NULL;
 }
 
@@ -386,14 +481,11 @@ void uae_ppc_execute_quick(int linetype)
 
 void uae_ppc_emulate(void)
 {
-       if (ppc_implementation == PPC_IMPLEMENTATION_QEMU)
-               return;
-
-       ppc_interrupt(intlev());
-
-       //TRACE(_T("uae_ppc_emulate\n"));
-       if (ppc_state == PPC_STATE_ACTIVE || ppc_state == PPC_STATE_SLEEP)
-               g_ppc_cpu_run_single(10);
+       if (using_pearpc()) {
+               ppc_interrupt(intlev());
+               if (ppc_state == PPC_STATE_ACTIVE || ppc_state == PPC_STATE_SLEEP)
+                       impl.run_single(10);
+       }
 }
 
 bool uae_ppc_direct_physical_memory_handle(uint32_t addr, uint8_t *&ptr)
@@ -406,19 +498,17 @@ bool uae_ppc_direct_physical_memory_handle(uint32_t addr, uint8_t *&ptr)
 
 STATIC_INLINE bool spinlock_pre(uaecptr addr)
 {
-       if (ppc_use_spinlock) {
-               addrbank *ab = &get_mem_bank(addr);
-               if ((ab->flags & ABFLAG_THREADSAFE) == 0) {
-                       uae_ppc_spinlock_get();
-                       return true;
-               }
+       addrbank *ab = &get_mem_bank(addr);
+       if ((ab->flags & ABFLAG_THREADSAFE) == 0) {
+               uae_ppc_spinlock_get();
+               return true;
        }
        return false;
 }
 
 STATIC_INLINE void spinlock_post(bool locked)
 {
-       if (ppc_use_spinlock && locked)
+       if (locked)
                uae_ppc_spinlock_release();
 }
 
@@ -429,7 +519,7 @@ bool UAECALL uae_ppc_io_mem_write(uint32_t addr, uint32_t data, int size)
        while (ppc_thread_running && ppc_cpu_lock_state < 0 && ppc_state);
 
 #if PPC_ACCESS_LOG > 0
-       if (!ppc_io_pipe && !valid_address(addr, size)) {
+       if (!valid_address(addr, size)) {
                if (addr >= PPC_DEBUG_ADDR_FROM && addr < PPC_DEBUG_ADDR_TO)
                        write_log(_T("PPC io write %08x = %08x %d\n"), addr, data, size);
        }
@@ -448,13 +538,11 @@ bool UAECALL uae_ppc_io_mem_write(uint32_t addr, uint32_t data, int size)
                put_byte(addr, data);
                break;
        }
-       if (ppc_use_spinlock) {
-               if (addr == 0xdff09c || addr == 0xdff09a) {
-                       int lev = intlev();
-                       ppc_interrupt(lev);
-               }
-               spinlock_post(locked);
+       if (addr == 0xdff09c || addr == 0xdff09a) {
+               int lev = intlev();
+               ppc_interrupt(lev);
        }
+       spinlock_post(locked);
 
 #if PPC_ACCESS_LOG > 2
        write_log(_T("PPC mem write %08x = %08x %d\n"), addr, data, size);
@@ -499,7 +587,7 @@ bool UAECALL uae_ppc_io_mem_read(uint32_t addr, uint32_t *data, int size)
        spinlock_post(locked);
 
 #if PPC_ACCESS_LOG > 0
-       if (!ppc_io_pipe && !valid_address(addr, size)) {
+       if (!valid_address(addr, size)) {
                if (addr >= PPC_DEBUG_ADDR_FROM && addr < PPC_DEBUG_ADDR_TO && addr != 0xdff006)
                        write_log(_T("PPC io read %08x=%08x %d\n"), addr, v, size);
        }
@@ -549,53 +637,59 @@ bool UAECALL uae_ppc_io_mem_read64(uint32_t addr, uint64_t *data)
 
 void uae_ppc_cpu_stop(void)
 {
-       TRACE(_T("uae_ppc_cpu_stop\n"));
-       if (ppc_thread_running && ppc_state) {
-               write_log(_T("Stopping PPC.\n"));
-               uae_ppc_wakeup();
-               g_ppc_cpu_stop();
-               while (ppc_state != PPC_STATE_STOP && ppc_state != PPC_STATE_CRASH) {
-                       uae_ppc_wakeup();
-                       if (ppc_use_spinlock) {
+       if (ppc_state == PPC_STATE_INACTIVE)
+               return;
+       TRACE(_T("uae_ppc_cpu_stop %d %d\n"), ppc_thread_running, ppc_state);
+       if (using_qemu()) {
+               write_log(_T("PPC: Stopping...\n"));
+               set_and_wait_for_state(PPC_CPU_STATE_PAUSED, 1);
+               write_log(_T("PPC: Stopped\n"));
+       } else if (using_pearpc()) {
+               if (ppc_thread_running && ppc_state) {
+                       write_log(_T("PPC: Stopping...\n"));
+                       impl.stop();
+                       while (ppc_state != PPC_STATE_STOP && ppc_state != PPC_STATE_CRASH) {
+                               uae_ppc_wakeup();
                                uae_ppc_spinlock_release();
                                uae_ppc_spinlock_get();
                        }
+                       write_log(_T("PPC: Stopped\n"));
                }
-               ppc_state = PPC_STATE_STOP;
-               write_log(_T("PPC stopped.\n"));
        }
+       ppc_state = PPC_STATE_INACTIVE;
 }
 
 void uae_ppc_cpu_reboot(void)
 {
        TRACE(_T("uae_ppc_cpu_reboot\n"));
 
-       uae_ppc_spinlock_reset();
-       ppc_io_pipe = false;
-       ppc_use_spinlock = true;
+       initialize();
 
-       if (ppc_main_thread) {
-               uae_ppc_cpu_reset();
-       } else {
+       if (!ppc_thread_running) {
                write_log(_T("Starting PPC thread.\n"));
-               if (!ppc_thread_running) {
-                       ppc_thread_running = true;
-                       ppc_main_thread = false;
-                       uae_start_thread(_T("ppc"), ppc_thread, NULL, NULL);
-               }
+               ppc_thread_running = true;
+               uae_start_thread(_T("ppc"), ppc_thread, NULL, NULL);
+       } else if (using_qemu()) {
+               write_log(_T("PPC: Thread already running, resetting\n"));
+               uae_ppc_cpu_reset();
+               set_and_wait_for_state(PPC_CPU_STATE_RUNNING, 1);
        }
 }
 
 void uae_ppc_reset(bool hardreset)
 {
        TRACE(_T("uae_ppc_reset hardreset=%d\n"), hardreset);
-       uae_ppc_cpu_stop();
-       ppc_main_thread = false;
-       if (hardreset) {
-               if (ppc_init_done)
-                       g_ppc_cpu_free();
-               ppc_init_done = false;
+       if (using_qemu()) {
+           set_and_wait_for_state(PPC_CPU_STATE_PAUSED, 1);
+       } else if (using_pearpc()) {
+               uae_ppc_cpu_stop();
+               if (hardreset) {
+                       if (ppc_init_done)
+                               impl.free();
+                       ppc_init_done = false;
+               }
        }
+       ppc_state = PPC_STATE_INACTIVE;
 }
 
 void uae_ppc_cpu_lock(void)
@@ -629,10 +723,10 @@ void uae_ppc_interrupt(bool active)
 {
        //TRACE(_T("uae_ppc_interrupt\n"));
        if (active) {
-               g_ppc_cpu_atomic_raise_ext_exception();
+               impl.atomic_raise_ext_exception();
                uae_ppc_wakeup();
        } else {
-               g_ppc_cpu_atomic_cancel_ext_exception();
+               impl.atomic_cancel_ext_exception();
        }
 }
 
@@ -652,23 +746,37 @@ void uae_ppc_crash(void)
 {
        TRACE(_T("uae_ppc_crash\n"));
        ppc_state = PPC_STATE_CRASH;
-       g_ppc_cpu_stop();
+       if (impl.stop) {
+               impl.stop();
+       }
 }
 
 void uae_ppc_hsync_handler(void)
 {
-       if (ppc_state != PPC_STATE_SLEEP)
-               return;
-       if (g_ppc_cpu_get_dec() == 0) {
-               uae_ppc_wakeup();
-       } else {
-               g_ppc_cpu_do_dec(ppc_cycle_count);
+       if (using_pearpc()) {
+               if (ppc_state != PPC_STATE_SLEEP)
+                       return;
+               if (impl.get_dec() == 0) {
+                       uae_ppc_wakeup();
+               } else {
+                       impl.do_dec(ppc_cycle_count);
+               }
        }
 }
 
 void uae_ppc_pause(int pause)
 {
-       if (g_ppc_cpu_pause) {
-               g_ppc_cpu_pause(pause);
+       // FIXME: assert(uae_is_emulation_thread())
+       if (using_qemu()) {
+               if (pause) {
+                       set_and_wait_for_state(PPC_CPU_STATE_PAUSED, 1);
+               } else {
+                       set_and_wait_for_state(PPC_CPU_STATE_RUNNING, 1);
+               }
        }
+#if 0
+       else if (impl.pause) {
+               impl.pause(pause);
+       }
+#endif
 }