From cdf71ef0edfa8924b1cd0303e3c1764cfcc7086a Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 13 Sep 2014 20:23:29 +0300 Subject: [PATCH] QEMU PPC memory bank update, cleanup. --- debug.cpp | 40 ++-- include/memory.h | 1 + include/uae/ppc.h | 22 ++- main.cpp | 6 +- memory.cpp | 33 ++++ ppc/ppc.cpp | 470 ++++++++++++++++++++++++++++------------------ 6 files changed, 363 insertions(+), 209 deletions(-) diff --git a/debug.cpp b/debug.cpp index 17ba80f6..610cfd45 100644 --- 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 diff --git a/include/memory.h b/include/memory.h index 695279a6..14c37e6f 100644 --- a/include/memory.h +++ b/include/memory.h @@ -106,6 +106,7 @@ typedef struct { uae_u32 allocated; } addrbank; +#define MEMORY_MIN_SUBBANK 1024 struct addrbank_sub { addrbank *bank; diff --git a/include/uae/ppc.h b/include/uae/ppc.h index 404ad8e5..bbca1cd8 100644 --- a/include/uae/ppc.h +++ b/include/uae/ppc.h @@ -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 */ diff --git a/main.cpp b/main.cpp index 4f84ea93..48919724 100644 --- 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 diff --git a/memory.cpp b/memory.cpp index 678e6807..f2ec4ed3 100644 --- a/memory.cpp +++ b/memory.cpp @@ -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 diff --git a/ppc/ppc.cpp b/ppc/ppc.cpp index 2f50065d..b6290456 100644 --- a/ppc/ppc.cpp +++ b/ppc/ppc.cpp @@ -13,7 +13,12 @@ #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 @@ -25,11 +30,12 @@ #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 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 } -- 2.47.3