diff options
Diffstat (limited to 'src/emu/cpu/mips/mips3drc.c')
-rw-r--r-- | src/emu/cpu/mips/mips3drc.c | 1297 |
1 files changed, 1297 insertions, 0 deletions
diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c new file mode 100644 index 00000000000..d10378f3e95 --- /dev/null +++ b/src/emu/cpu/mips/mips3drc.c @@ -0,0 +1,1297 @@ +/*************************************************************************** + + mips3drc.c + x86 Dynamic recompiler for MIPS III/IV emulator. + Written by Aaron Giles + + Philosophy: this is intended to be a very basic implementation of a + dynamic compiler in order to keep things simple. There are certainly + more optimizations that could be added but for now, we keep it + strictly to NOP stripping and LUI optimizations. + +***************************************************************************/ + +#include <stddef.h> +#include "cpuintrf.h" +#include "debugger.h" +#include "mips3com.h" +#include "mips3fe.h" +#include "cpu/x86log.h" +#include "cpu/drcfe.h" + +extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op); + + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define LOG_CODE (0) +#define SINGLE_INSTRUCTION_MODE (0) + +#ifdef MAME_DEBUG +#define COMPARE_AGAINST_C (0) +#else +#define COMPARE_AGAINST_C (0) +#endif + + + +/*************************************************************************** + CONFIGURATION +***************************************************************************/ + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 + +/* hack when running comparison against the C core */ +#if COMPARE_AGAINST_C +#undef MIPS3_COUNT_READ_CYCLES +#undef MIPS3_CAUSE_READ_CYCLES +#define MIPS3_COUNT_READ_CYCLES 0 +#define MIPS3_CAUSE_READ_CYCLES 0 +#endif + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define SR mips3.core->cpr[0][COP0_Status] +#define IS_FR0 (!(SR & SR_FR)) +#define IS_FR1 (SR & SR_FR) + + + +/*************************************************************************** + STRUCTURES & TYPEDEFS +***************************************************************************/ + +/* fast RAM info */ +typedef struct _fast_ram_info fast_ram_info; +struct _fast_ram_info +{ + offs_t start; + offs_t end; + UINT8 readonly; + void * base; +}; + + +/* hotspot info */ +typedef struct _hotspot_info hotspot_info; +struct _hotspot_info +{ + offs_t pc; + UINT32 opcode; + UINT32 cycles; +}; + + +/* opaque drc-specific info */ +typedef struct _mips3drc_data mips3drc_data; + + +/* MIPS3 registers */ +typedef struct _mips3_regs mips3_regs; +struct _mips3_regs +{ + /* core state */ + UINT8 * cache; /* base of the cache */ + mips3_state * core; /* pointer to the core MIPS3 state */ + drcfe_state * drcfe; /* pointer to the DRC front-end state */ + drc_core * drc; /* pointer to the DRC core */ + mips3drc_data * drcdata; /* pointer to the DRC-specific data */ + UINT32 drcoptions; /* configurable DRC options */ + + /* internal stuff */ + UINT32 nextpc; + UINT8 cache_dirty; + + /* fast RAM */ + UINT32 fastram_select; + fast_ram_info fastram[MIPS3_MAX_FASTRAM]; + + /* hotspots */ + UINT32 hotspot_select; + hotspot_info hotspot[MIPS3_MAX_HOTSPOTS]; + + /* code logging */ + x86log_context *log; + +#if COMPARE_AGAINST_C + /* memory state */ + UINT8 access_size; + UINT8 access_type; + offs_t access_addr; + UINT64 access_data; + UINT64 access_mask; + memory_handlers orighandler; +#endif +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void mips3drc_init(void); +static void mips3drc_exit(void); + +#if COMPARE_AGAINST_C +static void execute_c_version(void); +static void compare_c_version(void); +static void mips3c_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int)); +static void mips3c_reset(void); +#endif + + + +/*************************************************************************** + PRIVATE GLOBAL VARIABLES +***************************************************************************/ + +static mips3_regs mips3; + + + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + mips3_init - initialize the processor +-------------------------------------------------*/ + +static void mips3_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int)) +{ + drcfe_config feconfig = + { + COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ + COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ + COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ + mips3fe_describe /* callback to describe a single instruction */ + }; + + /* allocate a cache and memory for the core data in a single block */ + mips3.core = osd_alloc_executable(CACHE_SIZE + sizeof(*mips3.core)); + if (mips3.core == NULL) + fatalerror("Unable to allocate cache of size %d\n", CACHE_SIZE); + mips3.cache = (UINT8 *)(mips3.core + 1); + + /* initialize the core */ + mips3com_init(mips3.core, flavor, bigendian, index, clock, config, irqcallback); +#if COMPARE_AGAINST_C + mips3c_init(flavor, bigendian, index, clock, config, irqcallback); +#endif + + /* initialize the DRC to use the cache */ + mips3drc_init(); + if (Machine->debug_mode || SINGLE_INSTRUCTION_MODE) + feconfig.max_sequence = 1; + mips3.drcfe = drcfe_init(&feconfig, mips3.core); + + /* start up code logging */ + if (LOG_CODE) + mips3.log = x86log_create_context("mips3drc.asm"); +} + + +/*------------------------------------------------- + mips3_reset - reset the processor +-------------------------------------------------*/ + +static void mips3_reset(void) +{ + /* reset the common code and flush the cache */ + mips3com_reset(mips3.core); + drc_cache_reset(mips3.drc); + +#if COMPARE_AGAINST_C + mips3c_reset(); +#endif +} + + +/*------------------------------------------------- + mips3_execute - execute the CPU for the + specified number of cycles +-------------------------------------------------*/ + +static int mips3_execute(int cycles) +{ + /* reset the cache if dirty */ + if (mips3.cache_dirty) + drc_cache_reset(mips3.drc); + mips3.cache_dirty = FALSE; + + /* execute */ + mips3.core->icount = cycles; + drc_execute(mips3.drc); + return cycles - mips3.core->icount; +} + + +/*------------------------------------------------- + mips3_exit - cleanup from execution +-------------------------------------------------*/ + +static void mips3_exit(void) +{ + /* clean up code logging */ + if (LOG_CODE) + x86log_free_context(mips3.log); + + /* clean up the DRC */ + mips3drc_exit(); + drcfe_exit(mips3.drcfe); + drc_exit(mips3.drc); + + /* free the cache */ + osd_free_executable(mips3.core, CACHE_SIZE + sizeof(*mips3.core)); +} + + +/*------------------------------------------------- + mips3_get_context - return a copy of the + current context +-------------------------------------------------*/ + +static void mips3_get_context(void *dst) +{ + if (dst != NULL) + *(mips3_regs *)dst = mips3; +} + + +/*------------------------------------------------- + mips3_set_context - copy the current context + into the global state +-------------------------------------------------*/ + +static void mips3_set_context(void *src) +{ + if (src != NULL) + mips3 = *(mips3_regs *)src; +} + + +/*------------------------------------------------- + mips3_translate - perform virtual-to-physical + address translation +-------------------------------------------------*/ + +static int mips3_translate(int space, offs_t *address) +{ + return mips3com_translate_address(mips3.core, space, address); +} + + +/*------------------------------------------------- + mips3_dasm - disassemble an instruction +-------------------------------------------------*/ + +#ifdef MAME_DEBUG +static offs_t mips3_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) +{ + return mips3com_dasm(mips3.core, buffer, pc, oprom, opram); +} +#endif /* MAME_DEBUG */ + + + + +/*************************************************************************** + COMMON UTILITIES +***************************************************************************/ + +/*------------------------------------------------- + fastram_ptr - return a pointer to the base of + memory containing the given address, if it + is within a fast RAM range; returns 0 + otherwise +-------------------------------------------------*/ + +#ifdef PTR64 +static void *fastram_ptr(offs_t addr, int size, int iswrite) +{ + int ramnum; + + /* only direct maps are supported */ + if (addr < 0x80000000 || addr >= 0xc0000000) + return NULL; + addr &= 0x1fffffff; + + /* adjust address for endianness */ + if (mips3.core->bigendian) + { + if (size == 1) + addr ^= 3; + else if (size == 2) + addr ^= 2; + } + + /* search for fastram */ + for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) + if (mips3.fastram[ramnum].base != NULL && (!iswrite || !mips3.fastram[ramnum].readonly) && + addr >= mips3.fastram[ramnum].start && addr <= mips3.fastram[ramnum].end) + { + return (UINT8 *)mips3.fastram[ramnum].base + (addr - mips3.fastram[ramnum].start); + } + + return NULL; +} +#endif + + + +/*************************************************************************** + CODE LOGGING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + log_add_disasm_comment - add a comment + including disassembly of a MIPS instruction +-------------------------------------------------*/ + +static void log_add_disasm_comment(x86log_context *log, x86code *base, UINT32 pc, UINT32 op) +{ +#if (LOG_CODE) + { + char buffer[100]; + dasmmips3(buffer, pc, op); + x86log_add_comment(log, base, "%08X: %s", pc, buffer); + } +#endif +} + + +#ifdef PTR64 + +/*------------------------------------------------- + desc_flags_to_string - generate a string + representing the instruction description + flags +-------------------------------------------------*/ + +static const char *desc_flags_to_string(UINT32 flags) +{ + static char tempbuf[30]; + char *dest = tempbuf; + + /* branches */ + if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH) + *dest++ = 'U'; + else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH) + *dest++ = 'C'; + else + *dest++ = '.'; + + /* intrablock branches */ + *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.'; + + /* branch targets */ + *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.'; + + /* delay slots */ + *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.'; + + /* exceptions */ + if (flags & OPFLAG_WILL_CAUSE_EXCEPTION) + *dest++ = 'E'; + else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION) + *dest++ = 'e'; + else + *dest++ = '.'; + + /* read/write */ + if (flags & OPFLAG_READS_MEMORY) + *dest++ = 'R'; + else if (flags & OPFLAG_WRITES_MEMORY) + *dest++ = 'W'; + else + *dest++ = '.'; + + /* TLB validation */ + *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.'; + + /* TLB modification */ + *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.'; + + /* redispatch */ + *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.'; + return tempbuf; +} + + +/*------------------------------------------------- + log_register_list - log a list of GPR registers +-------------------------------------------------*/ + +static void log_register_list(x86log_context *log, const char *string, UINT64 gprmask, UINT64 fprmask) +{ + int count = 0; + int regnum; + + /* skip if nothing */ + if ((gprmask & ~1) == 0 && fprmask == 0) + return; + + x86log_printf(log, "[%s:", string); + + for (regnum = 1; regnum < 32; regnum++) + if (gprmask & ((UINT64)1 << regnum)) + x86log_printf(log, "%sr%d", (count++ == 0) ? "" : ",", regnum); + if (gprmask & ((UINT64)1 << REG_LO)) + x86log_printf(log, "%slo", (count++ == 0) ? "" : ","); + if (gprmask & ((UINT64)1 << REG_HI)) + x86log_printf(log, "%shi", (count++ == 0) ? "" : ","); + + for (regnum = 0; regnum < 32; regnum++) + if (fprmask & ((UINT64)1 << regnum)) + x86log_printf(log, "%sfpr%d", (count++ == 0) ? "" : ",", regnum); + if (fprmask & REGFLAG_FCC) + x86log_printf(log, "%sfcc", (count++ == 0) ? "" : ","); + x86log_printf(log, "] "); +} + + +/*------------------------------------------------- + log_opcode_desc - log a list of descriptions +-------------------------------------------------*/ + +static void log_opcode_desc(x86log_context *log, const opcode_desc *desclist, int indent) +{ + /* open the file, creating it if necessary */ + if (indent == 0) + x86log_printf(log, "\nDescriptor list @ %08X\n", desclist->pc); + + /* output each descriptor */ + for ( ; desclist != NULL; desclist = desclist->next) + { + char buffer[100]; + + /* disassemle the current instruction and output it to the log */ +#if LOG_CODE + dasmmips3(buffer, desclist->pc, *desclist->opptr.l); +#else + strcpy(buffer, "???"); +#endif + x86log_printf(log, "%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, desc_flags_to_string(desclist->flags), buffer); + + /* output register states */ + log_register_list(log, "use", desclist->gpr.used, desclist->fpr.used); + log_register_list(log, "mod", desclist->gpr.modified, desclist->fpr.modified); + log_register_list(log, "lrd", desclist->gpr.liveread, desclist->fpr.liveread); + log_register_list(log, "lwr", desclist->gpr.livewrite, desclist->fpr.livewrite); + x86log_printf(log, "\n"); + + /* if we have a delay slot, output it recursively */ + if (desclist->delay != NULL) + log_opcode_desc(log, desclist->delay, indent + 1); + + /* at the end of a sequence add a dividing line */ + if (desclist->flags & OPFLAG_END_SEQUENCE) + x86log_printf(log, "-----\n"); + } +} +#endif + + + +/*************************************************************************** + RECOMPILER CORE +***************************************************************************/ + +#ifdef PTR64 +#include "mdrc64.c" +#else +#include "mdrcold.c" +#endif + + + +/*************************************************************************** + GENERIC GET/SET INFO +***************************************************************************/ + +static void mips3_set_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are set as 64-bit signed integers --- */ + case CPUINFO_INT_MIPS3_DRC_OPTIONS: mips3.drcoptions = info->i; break; + + case CPUINFO_INT_MIPS3_FASTRAM_SELECT: if (info->i >= 0 && info->i < MIPS3_MAX_FASTRAM) mips3.fastram_select = info->i; mips3.cache_dirty = TRUE; break; + case CPUINFO_INT_MIPS3_FASTRAM_START: mips3.fastram[mips3.fastram_select].start = info->i; mips3.cache_dirty = TRUE; break; + case CPUINFO_INT_MIPS3_FASTRAM_END: mips3.fastram[mips3.fastram_select].end = info->i; mips3.cache_dirty = TRUE; break; + case CPUINFO_INT_MIPS3_FASTRAM_READONLY: mips3.fastram[mips3.fastram_select].readonly = info->i; mips3.cache_dirty = TRUE; break; + + case CPUINFO_INT_MIPS3_HOTSPOT_SELECT: if (info->i >= 0 && info->i < MIPS3_MAX_HOTSPOTS) mips3.hotspot_select = info->i; mips3.cache_dirty = TRUE; break; + case CPUINFO_INT_MIPS3_HOTSPOT_PC: mips3.hotspot[mips3.hotspot_select].pc = info->i; mips3.cache_dirty = TRUE; break; + case CPUINFO_INT_MIPS3_HOTSPOT_OPCODE: mips3.hotspot[mips3.hotspot_select].opcode = info->i; mips3.cache_dirty = TRUE; break; + case CPUINFO_INT_MIPS3_HOTSPOT_CYCLES: mips3.hotspot[mips3.hotspot_select].cycles = info->i; mips3.cache_dirty = TRUE; break; + + /* --- the following bits of info are set as pointers to data or functions --- */ + case CPUINFO_PTR_MIPS3_FASTRAM_BASE: mips3.fastram[mips3.fastram_select].base = info->p; break; + + /* --- everything else is handled generically --- */ + default: mips3com_set_info(mips3.core, state, info); break; + } +} + + +void mips3_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(mips3); break; + case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_SET_INFO: info->setinfo = mips3_set_info; break; + case CPUINFO_PTR_GET_CONTEXT: info->getcontext = mips3_get_context; break; + case CPUINFO_PTR_SET_CONTEXT: info->setcontext = mips3_set_context; break; + case CPUINFO_PTR_INIT: /* provided per-CPU */ break; + case CPUINFO_PTR_RESET: info->reset = mips3_reset; break; + case CPUINFO_PTR_EXIT: info->exit = mips3_exit; break; + case CPUINFO_PTR_EXECUTE: info->execute = mips3_execute; break; +#ifdef MAME_DEBUG + case CPUINFO_PTR_DISASSEMBLE: info->disassemble = mips3_dasm; break; +#endif /* MAME_DEBUG */ + case CPUINFO_PTR_TRANSLATE: info->translate = mips3_translate; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; + + /* --- everything else is handled generically --- */ + default: mips3com_get_info(mips3.core, state, info); break; + } +} + + + +/*************************************************************************** + R4600 VARIANTS +***************************************************************************/ + +#if (HAS_R4600) +static void r4600be_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R4600, TRUE, index, clock, config, irqcallback); +} + +static void r4600le_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R4600, FALSE, index, clock, config, irqcallback); +} + +void r4600be_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r4600be_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "R4600 (big)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} + +void r4600le_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r4600le_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "R4600 (little)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} +#endif + + + +/*************************************************************************** + R4650 VARIANTS +***************************************************************************/ + +#if (HAS_R4650) +static void r4650be_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R4650, TRUE, index, clock, config, irqcallback); +} + +static void r4650le_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R4650, FALSE, index, clock, config, irqcallback); +} + +void r4650be_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r4650be_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "IDT R4650 (big)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} + +void r4650le_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r4650le_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "IDT R4650 (little)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} +#endif + + + +/*************************************************************************** + R4700 VARIANTS +***************************************************************************/ + +#if (HAS_R4700) +static void r4700be_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R4700, TRUE, index, clock, config, irqcallback); +} + +static void r4700le_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R4700, FALSE, index, clock, config, irqcallback); +} + +void r4700be_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r4700be_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "R4700 (big)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} + + +void r4700le_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r4700le_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "R4700 (little)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} +#endif + + + +/*************************************************************************** + R5000 VARIANTS +***************************************************************************/ + +#if (HAS_R5000) +static void r5000be_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R5000, TRUE, index, clock, config, irqcallback); +} + +static void r5000le_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_R5000, FALSE, index, clock, config, irqcallback); +} + +void r5000be_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r5000be_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "R5000 (big)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} + +void r5000le_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = r5000le_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "R5000 (little)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} +#endif + + + +/*************************************************************************** + QED5271 VARIANTS +***************************************************************************/ + +#if (HAS_QED5271) +static void qed5271be_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_QED5271, TRUE, index, clock, config, irqcallback); +} + +static void qed5271le_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_QED5271, FALSE, index, clock, config, irqcallback); +} + +void qed5271be_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = qed5271be_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "QED5271 (big)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} + +void qed5271le_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = qed5271le_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "QED5271 (little)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} +#endif + + + +/*************************************************************************** + RM7000 VARIANTS +***************************************************************************/ + +#if (HAS_RM7000) +static void rm7000be_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_RM7000, TRUE, index, clock, config, irqcallback); +} + +static void rm7000le_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + mips3_init(MIPS3_TYPE_RM7000, FALSE, index, clock, config, irqcallback); +} + +void rm7000be_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = rm7000be_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "RM7000 (big)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} + +void rm7000le_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_LE; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = rm7000le_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "RM7000 (little)"); break; + + /* --- everything else is handled generically --- */ + default: mips3_get_info(state, info); break; + } +} +#endif + + + +/*************************************************************************** + DISASSEMBLERS +***************************************************************************/ + +#if !defined(MAME_DEBUG) && (LOG_CODE) +#include "mips3dsm.c" +#endif + + + +/*************************************************************************** + C CORE FOR COMPARISON +***************************************************************************/ + +#if COMPARE_AGAINST_C + +static UINT8 dummy_read_byte_32le(offs_t offs) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 1; + mips3.access_size = 1; + mips3.access_addr = offs; + mips3.access_mask = 0; + mips3.access_data = program_read_byte_32le(offs); + } + else + { + assert(mips3.access_type == 1); + assert(mips3.access_size == 1); + assert(mips3.access_addr == offs); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + } + return mips3.access_data; +} + +static UINT16 dummy_read_word_32le(offs_t offs) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 1; + mips3.access_size = 2; + mips3.access_addr = offs; + mips3.access_mask = 0; + mips3.access_data = program_read_word_32le(offs); + } + else + { + assert(mips3.access_type == 1); + assert(mips3.access_size == 2); + assert(mips3.access_addr == offs); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + } + return mips3.access_data; +} + +static UINT32 dummy_read_dword_32le(offs_t offs) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 1; + mips3.access_size = 4; + mips3.access_addr = offs; + mips3.access_mask = 0; + mips3.access_data = program_read_dword_32le(offs); + } + else + { + assert(mips3.access_type == 1); + assert(mips3.access_size == 4); + assert(mips3.access_addr == offs); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + } + return mips3.access_data; +} + +static UINT32 dummy_read_masked_32le(offs_t offs, UINT32 mask) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 1; + mips3.access_size = 4; + mips3.access_addr = offs; + mips3.access_mask = mask; + mips3.access_data = program_read_masked_32le(offs, mask); + } + else + { + assert(mips3.access_type == 1); + assert(mips3.access_size == 4); + assert(mips3.access_addr == offs); + assert(mips3.access_mask == mask); + mips3.access_type = 0; + } + return mips3.access_data; +} + +static UINT64 dummy_read_qword_32le(offs_t offs) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 1; + mips3.access_size = 8; + mips3.access_addr = offs; + mips3.access_mask = 0; + mips3.access_data = (*mips3.orighandler.readdouble)(offs); + } + else + { + assert(mips3.access_type == 1); + assert(mips3.access_size == 8); + assert(mips3.access_addr == offs); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + } + return mips3.access_data; +} + +static UINT64 dummy_read_qword_masked_32le(offs_t offs, UINT64 mask) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 1; + mips3.access_size = 8; + mips3.access_addr = offs; + mips3.access_mask = mask; + mips3.access_data = (*mips3.orighandler.readdouble_masked)(offs, mask); + } + else + { + assert(mips3.access_type == 1); + assert(mips3.access_size == 8); + assert(mips3.access_addr == offs); + assert(mips3.access_mask == mask); + mips3.access_type = 0; + } + return mips3.access_data; +} + +static void dummy_write_byte_32le(offs_t offs, UINT8 data) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 2; + mips3.access_size = 1; + mips3.access_addr = offs; + mips3.access_data = data; + mips3.access_mask = 0; + } + else + { + assert(mips3.access_type == 2); + assert(mips3.access_size == 1); + assert(mips3.access_addr == offs); + assert(mips3.access_data == data); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + program_write_byte_32le(offs, data); + } +} + +static void dummy_write_word_32le(offs_t offs, UINT16 data) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 2; + mips3.access_size = 2; + mips3.access_addr = offs; + mips3.access_data = data; + mips3.access_mask = 0; + } + else + { + assert(mips3.access_type == 2); + assert(mips3.access_size == 2); + assert(mips3.access_addr == offs); + assert(mips3.access_data == data); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + program_write_word_32le(offs, data); + } +} + +static void dummy_write_dword_32le(offs_t offs, UINT32 data) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 2; + mips3.access_size = 4; + mips3.access_addr = offs; + mips3.access_data = data; + mips3.access_mask = 0; + } + else + { + assert(mips3.access_type == 2); + assert(mips3.access_size == 4); + assert(mips3.access_addr == offs); + assert(mips3.access_data == data); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + program_write_dword_32le(offs, data); + } +} + +static void dummy_write_masked_32le(offs_t offs, UINT32 data, UINT32 mask) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 2; + mips3.access_size = 4; + mips3.access_addr = offs; + mips3.access_data = data; + mips3.access_mask = mask; + } + else + { + assert(mips3.access_type == 2); + assert(mips3.access_size == 4); + assert(mips3.access_addr == offs); + assert(mips3.access_data == data); + assert(mips3.access_mask == mask); + mips3.access_type = 0; + program_write_masked_32le(offs, data, mask); + } +} + +static void dummy_write_qword_32le(offs_t offs, UINT64 data) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 2; + mips3.access_size = 8; + mips3.access_addr = offs; + mips3.access_data = data; + mips3.access_mask = 0; + } + else + { + assert(mips3.access_type == 2); + assert(mips3.access_size == 8); + assert(mips3.access_addr == offs); + assert(mips3.access_data == data); + assert(mips3.access_mask == 0); + mips3.access_type = 0; + (*mips3.orighandler.writedouble)(offs, data); + } +} + +static void dummy_write_qword_masked_32le(offs_t offs, UINT64 data, UINT64 mask) +{ + if (mips3.access_type == 0) + { + mips3.access_type = 2; + mips3.access_size = 8; + mips3.access_addr = offs; + mips3.access_data = data; + mips3.access_mask = mask; + } + else + { + assert(mips3.access_type == 2); + assert(mips3.access_size == 8); + assert(mips3.access_addr == offs); + assert(mips3.access_data == data); + assert(mips3.access_mask == mask); + mips3.access_type = 0; + (*mips3.orighandler.writedouble_masked)(offs, data, mask); + } +} + +static const memory_handlers override_memory = +{ + dummy_read_byte_32le, + dummy_read_word_32le, + dummy_read_dword_32le, + dummy_read_masked_32le, + dummy_read_qword_32le, + dummy_read_qword_masked_32le, + + dummy_write_byte_32le, + dummy_write_word_32le, + dummy_write_dword_32le, + dummy_write_masked_32le, + dummy_write_qword_32le, + dummy_write_qword_masked_32le +}; + +#undef SR + +#define mips3 c_mips3 +#define mips3_regs c_mips3_regs + +#define mips3_get_context c_mips3_get_context +#define mips3_set_context c_mips3_set_context +#define mips3_reset c_mips3_reset +#define mips3_translate c_mips3_translate +#define mips3_dasm c_mips3_dasm +#define mips3_execute c_mips3_execute +#define mips3_set_info c_mips3_set_info +#define mips3_get_info c_mips3_get_info + +#define r4600be_init c_r4600be_init +#define r4600le_init c_r4600le_init +#define r4600be_get_info c_r4600be_get_info +#define r4600le_get_info c_r4600le_get_info + +#define r4650be_init c_r4650be_init +#define r4650le_init c_r4650le_init +#define r4650be_get_info c_r4650be_get_info +#define r4650le_get_info c_r4650le_get_info + +#define r4700be_init c_r4700be_init +#define r4700le_init c_r4700le_init +#define r4700be_get_info c_r4700be_get_info +#define r4700le_get_info c_r4700le_get_info + +#define r5000be_init c_r5000be_init +#define r5000le_init c_r5000le_init +#define r5000be_get_info c_r5000be_get_info +#define r5000le_get_info c_r5000le_get_info + +#define qed5271be_init c_qed5271be_init +#define qed5271le_init c_qed5271le_init +#define qed5271be_get_info c_qed5271be_get_info +#define qed5271le_get_info c_qed5271le_get_info + +#define rm7000be_init c_rm7000be_init +#define rm7000le_init c_rm7000le_init +#define rm7000be_get_info c_rm7000be_get_info +#define rm7000le_get_info c_rm7000le_get_info + +#include "mips3.c" + +#undef mips3 + +static void mips3c_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int)) +{ + mips3com_init(&c_mips3.core, flavor, bigendian, index, clock, config, irqcallback); + mips3.orighandler = mips3.core->memory; + mips3.core->memory = override_memory; + c_mips3.core.memory = override_memory; +} + +static void mips3c_reset(void) +{ + c_mips3_reset(); +} + +static void execute_c_version(void) +{ + int save_debug_mode = Machine->debug_mode; + int i; + + assert(mips3.access_type == 0); + + c_mips3.core.cpr[0][COP0_Cause] = (c_mips3.core.cpr[0][COP0_Cause] & ~0xfc00) | (mips3.core->cpr[0][COP0_Cause] & 0xfc00); + check_irqs(); + + assert(c_mips3.core.pc == mips3.core->pc); + assert(c_mips3.core.r[REG_HI] == mips3.core->r[REG_HI]); + assert(c_mips3.core.r[REG_LO] == mips3.core->r[REG_LO]); + for (i = 0; i < 32; i++) + { + assert(c_mips3.core.r[i] == mips3.core->r[i]); + assert(c_mips3.core.cpr[0][i] == mips3.core->cpr[0][i]); + assert(c_mips3.core.ccr[0][i] == mips3.core->ccr[0][i]); + assert(c_mips3.core.cpr[1][i] == mips3.core->cpr[1][i]); + assert(c_mips3.core.ccr[1][i] == mips3.core->ccr[1][i]); + } + for (i = 0; i < 8; i++) + assert(c_mips3.core.cf[1][i] == mips3.core->cf[1][i]); + assert(c_mips3.core.count_zero_time == mips3.core->count_zero_time); + + mips3.access_type = 0; + + Machine->debug_mode = 0; + c_mips3_execute(0); + Machine->debug_mode = save_debug_mode; +} + +static void compare_c_version(void) +{ +} + +#endif |