/*************************************************************************** rspdrc.c Universal machine language-based Nintendo/SGI RSP emulator. Written by Harmony of the MESS team. Copyright the MESS team. Released for general non-commercial use under the MAME license Visit http://mamedev.org for licensing and usage restrictions. **************************************************************************** Future improvements/changes: * Confer with Aaron Giles about adding a memory hash-based caching system and static recompilation for maximum overhead minimization ***************************************************************************/ #include "emu.h" #include "debugger.h" #include "profiler.h" #include "rsp.h" #include "rspdiv.h" #include "rspfe.h" #include "cpu/drcfe.h" #include "cpu/drcuml.h" #include "cpu/drcumlsh.h" using namespace uml; CPU_DISASSEMBLE( rsp ); extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); #ifdef USE_RSPDRC /*************************************************************************** DEBUGGING ***************************************************************************/ #define FORCE_C_BACKEND (0) #define LOG_UML (0) #define LOG_NATIVE (0) #define SINGLE_INSTRUCTION_MODE (0) /*************************************************************************** CONSTANTS ***************************************************************************/ /* map variables */ #define MAPVAR_PC M0 #define MAPVAR_CYCLES M1 /* 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 /* exit codes */ #define EXECUTE_OUT_OF_CYCLES 0 #define EXECUTE_MISSING_CODE 1 #define EXECUTE_UNMAPPED_CODE 2 #define EXECUTE_RESET_CACHE 3 /*************************************************************************** MACROS ***************************************************************************/ #define R32(reg) rsp->impstate->regmap[reg] /*************************************************************************** STRUCTURES & TYPEDEFS ***************************************************************************/ /* fast RAM info */ typedef struct _fast_ram_info fast_ram_info; struct _fast_ram_info { offs_t start; /* start of the RAM block */ offs_t end; /* end of the RAM block */ UINT8 readonly; /* TRUE if read-only */ void * base; /* base in memory where the RAM lives */ }; /* internal compiler state */ typedef struct _compiler_state compiler_state; struct _compiler_state { UINT32 cycles; /* accumulated cycles */ UINT8 checkints; /* need to check interrupts before next instruction */ UINT8 checksoftints; /* need to check software interrupts before next instruction */ code_label labelnum; /* index for local labels */ }; struct _rspimp_state { /* core state */ drc_cache * cache; /* pointer to the DRC code cache */ drcuml_state * drcuml; /* DRC UML generator state */ rsp_frontend * drcfe; /* pointer to the DRC front-end state */ UINT32 drcoptions; /* configurable DRC options */ /* internal stuff */ UINT8 cache_dirty; /* true if we need to flush the cache */ UINT32 jmpdest; /* destination jump target */ /* parameters for subroutines */ UINT64 numcycles; /* return value from gettotalcycles */ const char * format; /* format string for print_debug */ UINT32 arg0; /* print_debug argument 1 */ UINT32 arg1; /* print_debug argument 2 */ UINT32 arg2; /* print_debug argument 3 */ UINT32 arg3; /* print_debug argument 4 */ UINT32 vres[8]; /* used for temporary vector results */ /* register mappings */ parameter regmap[32]; /* parameter to register mappings for all 32 integer registers */ /* subroutines */ code_handle * entry; /* entry point */ code_handle * nocode; /* nocode exception handler */ code_handle * out_of_cycles; /* out of cycles exception handler */ code_handle * read8; /* read byte */ code_handle * write8; /* write byte */ code_handle * read16; /* read half */ code_handle * write16; /* write half */ code_handle * read32; /* read word */ code_handle * write32; /* write word */ }; /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ static void code_flush_cache(rsp_state *rsp); static void code_compile_block(rsp_state *rsp, offs_t pc); static void cfunc_unimplemented(void *param); static void cfunc_set_cop0_reg(void *param); static void cfunc_get_cop0_reg(void *param); static void cfunc_mfc2(void *param); static void cfunc_cfc2(void *param); static void cfunc_mtc2(void *param); static void cfunc_ctc2(void *param); //static void cfunc_swc2(void *param); //static void cfunc_lwc2(void *param); static void cfunc_sp_set_status_cb(void *param); static void cfunc_rsp_lbv(void *param); static void cfunc_rsp_lsv(void *param); static void cfunc_rsp_llv(void *param); static void cfunc_rsp_ldv(void *param); static void cfunc_rsp_lqv(void *param); static void cfunc_rsp_lrv(void *param); static void cfunc_rsp_lpv(void *param); static void cfunc_rsp_luv(void *param); static void cfunc_rsp_lhv(void *param); static void cfunc_rsp_lfv(void *param); static void cfunc_rsp_lwv(void *param); static void cfunc_rsp_ltv(void *param); static void cfunc_rsp_sbv(void *param); static void cfunc_rsp_ssv(void *param); static void cfunc_rsp_slv(void *param); static void cfunc_rsp_sdv(void *param); static void cfunc_rsp_sqv(void *param); static void cfunc_rsp_srv(void *param); static void cfunc_rsp_spv(void *param); static void cfunc_rsp_suv(void *param); static void cfunc_rsp_shv(void *param); static void cfunc_rsp_sfv(void *param); static void cfunc_rsp_swv(void *param); static void cfunc_rsp_stv(void *param); static void static_generate_entry_point(rsp_state *rsp); static void static_generate_nocode_handler(rsp_state *rsp); static void static_generate_out_of_cycles(rsp_state *rsp); static void static_generate_memory_accessor(rsp_state *rsp, int size, int iswrite, const char *name, code_handle *&handleptr); static int generate_lwc2(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static int generate_swc2(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static void generate_update_cycles(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, parameter param, int allow_exception); static void generate_checksum_block(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); static void generate_sequence_instruction(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static void generate_delay_slot_and_branch(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg); static int generate_opcode(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static int generate_special(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static int generate_regimm(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static int generate_cop0(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static int generate_cop2(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); static void log_add_disasm_comment(rsp_state *rsp, drcuml_block *block, UINT32 pc, UINT32 op); /*************************************************************************** HELPFUL DEFINES ***************************************************************************/ #define VDREG ((op >> 6) & 0x1f) #define VS1REG ((op >> 11) & 0x1f) #define VS2REG ((op >> 16) & 0x1f) #define EL ((op >> 21) & 0xf) #define VREG_B(reg, offset) rsp->v[(reg)].b[BYTE4_XOR_BE(offset)] #define VREG_S(reg, offset) rsp->v[(reg)].s[(offset)^1] #define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) #define ACCUM(x) rsp->accum[x].q #define ACCUM_H(x) rsp->accum[((x))].w[3] #define ACCUM_M(x) rsp->accum[((x))].w[2] #define ACCUM_L(x) rsp->accum[((x))].w[1] #define CARRY_FLAG(x) ((rsp->flag[0] & (1 << (x))) ? 1 : 0) #define CLEAR_CARRY_FLAGS() { rsp->flag[0] &= ~0xff; } #define SET_CARRY_FLAG(x) { rsp->flag[0] |= (1 << (x)); } #define CLEAR_CARRY_FLAG(x) { rsp->flag[0] &= ~(1 << (x)); } #define COMPARE_FLAG(x) ((rsp->flag[1] & (1 << (x))) ? 1 : 0) #define CLEAR_COMPARE_FLAGS() { rsp->flag[1] &= ~0xff; } #define SET_COMPARE_FLAG(x) { rsp->flag[1] |= (1 << (x)); } #define CLEAR_COMPARE_FLAG(x) { rsp->flag[1] &= ~(1 << (x)); } #define ZERO_FLAG(x) ((rsp->flag[0] & (0x100 << (x))) ? 1 : 0) #define CLEAR_ZERO_FLAGS() { rsp->flag[0] &= ~0xff00; } #define SET_ZERO_FLAG(x) { rsp->flag[0] |= (0x100 << (x)); } #define CLEAR_ZERO_FLAG(x) { rsp->flag[0] &= ~(0x100 << (x)); } INLINE rsp_state *get_safe_token(device_t *device) { assert(device != NULL); assert(device->type() == RSP); return *(rsp_state **)downcast(device)->token(); } /*************************************************************************** INLINE FUNCTIONS ***************************************************************************/ /*------------------------------------------------- epc - compute the exception PC from a descriptor -------------------------------------------------*/ INLINE UINT32 epc(const opcode_desc *desc) { return ((desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc) | 0x1000; } /*------------------------------------------------- alloc_handle - allocate a handle if not already allocated -------------------------------------------------*/ INLINE void alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) { if (*handleptr == NULL) *handleptr = drcuml->handle_alloc(name); } /*------------------------------------------------- load_fast_iregs - load any fast integer registers -------------------------------------------------*/ INLINE void load_fast_iregs(rsp_state *rsp, drcuml_block *block) { int regnum; for (regnum = 0; regnum < ARRAY_LENGTH(rsp->impstate->regmap); regnum++) if (rsp->impstate->regmap[regnum].is_int_register()) UML_MOV(block, ireg(rsp->impstate->regmap[regnum].ireg() - REG_I0), mem(&rsp->r[regnum])); } /*------------------------------------------------- save_fast_iregs - save any fast integer registers -------------------------------------------------*/ INLINE void save_fast_iregs(rsp_state *rsp, drcuml_block *block) { int regnum; for (regnum = 0; regnum < ARRAY_LENGTH(rsp->impstate->regmap); regnum++) if (rsp->impstate->regmap[regnum].is_int_register()) UML_MOV(block, mem(&rsp->r[regnum]), ireg(rsp->impstate->regmap[regnum].ireg() - REG_I0)); } /*************************************************************************** CORE CALLBACKS ***************************************************************************/ INLINE UINT8 READ8(rsp_state *rsp, UINT32 address) { UINT8 ret; address = 0x04000000 | (address & 0xfff); ret = rsp->program->read_byte(address); //printf("%04xr%02x\n",address & 0x1fff, ret); return ret; } static void cfunc_read8(void *param) { rsp_state *rsp = (rsp_state *)param; rsp->impstate->arg0 = READ8(rsp, rsp->impstate->arg0); } INLINE UINT16 READ16(rsp_state *rsp, UINT32 address) { UINT16 ret; address = 0x04000000 | (address & 0xfff); ret = rsp->program->read_byte(address+0) << 8; ret |= rsp->program->read_byte(address+1) << 0; //printf("%04xr%04x\n",address & 0x1fff, ret); return ret; } static void cfunc_read16(void *param) { rsp_state *rsp = (rsp_state *)param; rsp->impstate->arg0 = READ16(rsp, rsp->impstate->arg0); } INLINE UINT32 READ32(rsp_state *rsp, UINT32 address) { UINT32 ret; address = 0x04000000 | (address & 0xfff); ret = rsp->program->read_byte(address+0) << 24; ret |= rsp->program->read_byte(address+1) << 16; ret |= rsp->program->read_byte(address+2) << 8; ret |= rsp->program->read_byte(address+3) << 0; //printf("%04xr%08x\n",address & 0x1fff, ret); return ret; } static void cfunc_read32(void *param) { rsp_state *rsp = (rsp_state *)param; rsp->impstate->arg0 = READ32(rsp, rsp->impstate->arg0); } INLINE void WRITE8(rsp_state *rsp, UINT32 address, UINT8 data) { address = 0x04000000 | (address & 0xfff); //printf("%04x:%02x\n",address & 0x1fff, data); rsp->program->write_byte(address, data); } static void cfunc_write8(void *param) { rsp_state *rsp = (rsp_state *)param; WRITE8(rsp, rsp->impstate->arg0, (UINT8)rsp->impstate->arg1); } INLINE void WRITE16(rsp_state *rsp, UINT32 address, UINT16 data) { address = 0x04000000 | (address & 0xfff); //printf("%04x:%04x\n",address & 0x1fff, data); rsp->program->write_byte(address + 0, (data >> 8) & 0xff); rsp->program->write_byte(address + 1, (data >> 0) & 0xff); } static void cfunc_write16(void *param) { rsp_state *rsp = (rsp_state *)param; WRITE16(rsp, rsp->impstate->arg0, (UINT16)rsp->impstate->arg1); } INLINE void WRITE32(rsp_state *rsp, UINT32 address, UINT32 data) { address = 0x04000000 | (address & 0xfff); //printf("%04x:%08x\n",address & 0x1fff, data); rsp->program->write_byte(address + 0, (data >> 24) & 0xff); rsp->program->write_byte(address + 1, (data >> 16) & 0xff); rsp->program->write_byte(address + 2, (data >> 8) & 0xff); rsp->program->write_byte(address + 3, (data >> 0) & 0xff); } static void cfunc_write32(void *param) { rsp_state *rsp = (rsp_state *)param; WRITE32(rsp, rsp->impstate->arg0, rsp->impstate->arg1); } /*****************************************************************************/ /*------------------------------------------------- rspdrc_set_options - configure DRC options -------------------------------------------------*/ void rspdrc_set_options(device_t *device, UINT32 options) { rsp_state *rsp = get_safe_token(device); rsp->impstate->drcoptions = options; } /*------------------------------------------------- cfunc_printf_debug - generic printf for debugging -------------------------------------------------*/ #ifdef UNUSED_CODE static void cfunc_printf_debug(void *param) { rsp_state *rsp = (rsp_state *)param; switch(rsp->impstate->arg2) { case 0: // WRITE8 printf("%04x:%02x\n", rsp->impstate->arg0 & 0x0fff, (UINT8)rsp->impstate->arg1); break; case 1: // WRITE16 printf("%04x:%04x\n", rsp->impstate->arg0 & 0x0fff, (UINT16)rsp->impstate->arg1); break; case 2: // WRITE32 printf("%04x:%08x\n", rsp->impstate->arg0 & 0x0fff, rsp->impstate->arg1); break; case 3: // READ8 printf("%04xr%02x\n", rsp->impstate->arg0 & 0x0fff, (UINT8)rsp->impstate->arg1); break; case 4: // READ16 printf("%04xr%04x\n", rsp->impstate->arg0 & 0x0fff, (UINT16)rsp->impstate->arg1); break; case 5: // READ32 printf("%04xr%08x\n", rsp->impstate->arg0 & 0x0fff, rsp->impstate->arg1); break; default: // ??? printf("%08x %08x\n", rsp->impstate->arg0 & 0x0fff, rsp->impstate->arg1); break; } } #endif static void cfunc_get_cop0_reg(void *param) { rsp_state *rsp = (rsp_state*)param; int reg = rsp->impstate->arg0; int dest = rsp->impstate->arg1; if (reg >= 0 && reg < 8) { if(dest) { rsp->r[dest] = (rsp->config->sp_reg_r)(rsp->device, reg, 0x00000000); } } else if (reg >= 8 && reg < 16) { if(dest) { rsp->r[dest] = (rsp->config->dp_reg_r)(rsp->device, reg - 8, 0x00000000); } } else { fatalerror("RSP: cfunc_get_cop0_reg: %d", reg); } } static void cfunc_set_cop0_reg(void *param) { rsp_state *rsp = (rsp_state*)param; int reg = rsp->impstate->arg0; UINT32 data = rsp->impstate->arg1; if (reg >= 0 && reg < 8) { (rsp->config->sp_reg_w)(rsp->device, reg, data, 0x00000000); } else if (reg >= 8 && reg < 16) { (rsp->config->dp_reg_w)(rsp->device, reg - 8, data, 0x00000000); } else { fatalerror("RSP: set_cop0_reg: %d, %08X\n", reg, data); } } static void cfunc_unimplemented_opcode(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; if ((rsp->device->machine->debug_flags & DEBUG_FLAG_ENABLED) != 0) { char string[200]; rsp_dasm_one(string, rsp->ppc, op); mame_printf_debug("%08X: %s\n", rsp->ppc, string); } fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", op >> 26, op, rsp->ppc); } static void unimplemented_opcode(rsp_state *rsp, UINT32 op) { if ((rsp->device->machine->debug_flags & DEBUG_FLAG_ENABLED) != 0) { char string[200]; rsp_dasm_one(string, rsp->ppc, op); mame_printf_debug("%08X: %s\n", rsp->ppc, string); } fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", op >> 26, op, rsp->ppc); } /*****************************************************************************/ /* Legacy. Going forward, this will be transitioned into unrolled opcode decodes. */ static const int vector_elements_1[16][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, // none { 0, 1, 2, 3, 4, 5, 6 ,7 }, // ??? { 1, 3, 5, 7, 0, 2, 4, 6 }, // 0q { 0, 2, 4, 6, 1, 3, 5, 7 }, // 1q { 1, 2, 3, 5, 6, 7, 0, 4 }, // 0h { 0, 2, 3, 4, 6, 7, 1, 5 }, // 1h { 0, 1, 3, 4, 5, 7, 2, 6 }, // 2h { 0, 1, 2, 4, 5, 6, 3, 7 }, // 3h { 1, 2, 3, 4, 5, 6, 7, 0 }, // 0 { 0, 2, 3, 4, 5, 6, 7, 1 }, // 1 { 0, 1, 3, 4, 5, 6, 7, 2 }, // 2 { 0, 1, 2, 4, 5, 6, 7, 3 }, // 3 { 0, 1, 2, 3, 5, 6, 7, 4 }, // 4 { 0, 1, 2, 3, 4, 6, 7, 5 }, // 5 { 0, 1, 2, 3, 4, 5, 7, 6 }, // 6 { 0, 1, 2, 3, 4, 5, 6, 7 }, // 7 }; /* Legacy. Going forward, this will be transitioned into unrolled opcode decodes. */ static const int vector_elements_2[16][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, // none { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 }; static void rspcom_init(rsp_state *rsp, legacy_cpu_device *device, device_irq_callback irqcallback) { int regIdx = 0; int accumIdx; memset(rsp, 0, sizeof(*rsp)); rsp->config = (const rsp_config *)device->baseconfig().static_config(); rsp->irq_callback = irqcallback; rsp->device = device; rsp->program = device->space(AS_PROGRAM); rsp->direct = &rsp->program->direct(); #if 1 // Inaccurate. RSP registers power on to a random state... for(regIdx = 0; regIdx < 32; regIdx++ ) { rsp->r[regIdx] = 0; rsp->v[regIdx].d[0] = 0; rsp->v[regIdx].d[1] = 0; } rsp->flag[0] = 0; rsp->flag[1] = 0; rsp->flag[2] = 0; rsp->flag[3] = 0; rsp->square_root_res = 0; rsp->square_root_high = 0; rsp->reciprocal_res = 0; rsp->reciprocal_high = 0; #endif // ...except for the accumulators. for(accumIdx = 0; accumIdx < 8; accumIdx++ ) { rsp->accum[accumIdx].q = 0; } rsp->sr = RSP_STATUS_HALT; rsp->step_count = 0; } static CPU_INIT( rsp ) { rsp_state *rsp; drc_cache *cache; UINT32 flags = 0; int regnum; //int elnum; /* allocate enough space for the cache and the core */ cache = auto_alloc(device->machine, drc_cache(CACHE_SIZE + sizeof(*rsp))); /* allocate the core memory */ *(rsp_state **)device->token() = rsp = (rsp_state *)cache->alloc_near(sizeof(*rsp)); memset(rsp, 0, sizeof(*rsp)); rspcom_init(rsp, device, irqcallback); /* allocate the implementation-specific state from the full cache */ rsp->impstate = (rspimp_state *)cache->alloc_near(sizeof(*rsp->impstate)); memset(rsp->impstate, 0, sizeof(*rsp->impstate)); rsp->impstate->cache = cache; /* initialize the UML generator */ if (FORCE_C_BACKEND) { flags |= DRCUML_OPTION_USE_C; } if (LOG_UML) { flags |= DRCUML_OPTION_LOG_UML; } if (LOG_NATIVE) { flags |= DRCUML_OPTION_LOG_NATIVE; } rsp->impstate->drcuml = auto_alloc(device->machine, drcuml_state(*device, *cache, flags, 8, 32, 2)); /* add symbols for our stuff */ rsp->impstate->drcuml->symbol_add(&rsp->pc, sizeof(rsp->pc), "pc"); rsp->impstate->drcuml->symbol_add(&rsp->icount, sizeof(rsp->icount), "icount"); for (regnum = 0; regnum < 32; regnum++) { char buf[10]; sprintf(buf, "r%d", regnum); rsp->impstate->drcuml->symbol_add(&rsp->r[regnum], sizeof(rsp->r[regnum]), buf); } rsp->impstate->drcuml->symbol_add(&rsp->impstate->arg0, sizeof(rsp->impstate->arg0), "arg0"); rsp->impstate->drcuml->symbol_add(&rsp->impstate->arg1, sizeof(rsp->impstate->arg1), "arg1"); rsp->impstate->drcuml->symbol_add(&rsp->impstate->arg2, sizeof(rsp->impstate->arg2), "arg2"); rsp->impstate->drcuml->symbol_add(&rsp->impstate->arg3, sizeof(rsp->impstate->arg3), "arg3"); rsp->impstate->drcuml->symbol_add(&rsp->impstate->numcycles, sizeof(rsp->impstate->numcycles), "numcycles"); /* initialize the front-end helper */ rsp->impstate->drcfe = auto_alloc(device->machine, rsp_frontend(*rsp, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); /* compute the register parameters */ for (regnum = 0; regnum < 32; regnum++) rsp->impstate->regmap[regnum] = (regnum == 0) ? parameter(0) : parameter::make_memory(&rsp->r[regnum]); /* drcbe_info beinfo; rsp->impstate->drcuml->get_backend_info(beinfo); if (beinfo.direct_iregs > 2) { rsp->impstate->regmap[30] = I2; } if (beinfo.direct_iregs > 3) { rsp->impstate->regmap[31] = I3; } if (beinfo.direct_iregs > 4) { rsp->impstate->regmap[2] = I4; } if (beinfo.direct_iregs > 5) { rsp->impstate->regmap[3] = I5; } if (beinfo.direct_iregs > 6) { rsp->impstate->regmap[4] = I6; } */ /* mark the cache dirty so it is updated on next execute */ rsp->impstate->cache_dirty = TRUE; } static CPU_EXIT( rsp ) { rsp_state *rsp = get_safe_token(device); /* clean up the DRC */ auto_free(device->machine, rsp->impstate->drcfe); auto_free(device->machine, rsp->impstate->drcuml); auto_free(device->machine, rsp->impstate->cache); } static CPU_RESET( rsp ) { rsp_state *rsp = get_safe_token(device); rsp->nextpc = ~0; } static void cfunc_rsp_lbv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | // -------------------------------------------------- // // Load 1 byte to vector byte index ea = (base) ? rsp->r[base] + offset : offset; VREG_B(dest, index) = READ8(rsp, ea); } static void cfunc_rsp_lsv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | // -------------------------------------------------- // // Loads 2 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 2) : (offset * 2); int end = index + 2; for (int i = index; i < end; i++) { VREG_B(dest, i) = READ8(rsp, ea); ea++; } } static void cfunc_rsp_llv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | // -------------------------------------------------- // // Loads 4 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 4) : (offset * 4); int end = index + 4; for (int i = index; i < end; i++) { VREG_B(dest, i) = READ8(rsp, ea); ea++; } } static void cfunc_rsp_ldv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | // -------------------------------------------------- // // Loads 8 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8); int end = index + 8; for (int i = index; i < end; i++) { VREG_B(dest, i) = READ8(rsp, ea); ea++; } } static void cfunc_rsp_lqv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; int end = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | // -------------------------------------------------- // // Loads up to 16 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); end = index + (16 - (ea & 0xf)); if (end > 16) end = 16; for (i=index; i < end; i++) { VREG_B(dest, i) = READ8(rsp, ea); ea++; } } static void cfunc_rsp_lrv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; int end = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset | // -------------------------------------------------- // // Stores up to 16 bytes starting from right side until 16-byte boundary ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); index = 16 - ((ea & 0xf) - index); end = 16; ea &= ~0xf; for (i=index; i < end; i++) { VREG_B(dest, i) = READ8(rsp, ea); ea++; } } static void cfunc_rsp_lpv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset | // -------------------------------------------------- // // Loads a byte as the upper 8 bits of each element ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8); for (i=0; i < 8; i++) { VREG_S(dest, i) = READ8(rsp, ea + (((16-index) + i) & 0xf)) << 8; } } static void cfunc_rsp_luv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset | // -------------------------------------------------- // // Loads a byte as the bits 14-7 of each element ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8); for (i=0; i < 8; i++) { VREG_S(dest, i) = READ8(rsp, ea + (((16-index) + i) & 0xf)) << 7; } } static void cfunc_rsp_lhv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset | // -------------------------------------------------- // // Loads a byte as the bits 14-7 of each element, with 2-byte stride ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); for (i=0; i < 8; i++) { VREG_S(dest, i) = READ8(rsp, ea + (((16-index) + (i<<1)) & 0xf)) << 7; } } static void cfunc_rsp_lfv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; int end = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset | // -------------------------------------------------- // // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); // not sure what happens if 16-byte boundary is crossed... end = (index >> 1) + 4; for (i=index >> 1; i < end; i++) { VREG_S(dest, i) = READ8(rsp, ea) << 7; ea += 4; } } static void cfunc_rsp_lwv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; int end = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset | // -------------------------------------------------- // // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 // after byte index 15 ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); end = (16 - index) + 16; for (i=(16 - index); i < end; i++) { VREG_B(dest, i & 0xf) = READ8(rsp, ea); ea += 4; } } static void cfunc_rsp_ltv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int i = 0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | // -------------------------------------------------- // // Loads one element to maximum of 8 vectors, while incrementing element index // FIXME: has a small problem with odd indices int element; int vs = dest; int ve = dest + 8; if (ve > 32) { ve = 32; } element = 7 - (index >> 1); ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); ea = ((ea + 8) & ~0xf) + (index & 1); for (i = vs; i < ve; i++) { element = ((8 - (index >> 1) + (i - vs)) << 1); VREG_B(i, (element & 0xf)) = READ8(rsp, ea); VREG_B(i, ((element + 1) & 0xf)) = READ8(rsp, ea + 1); ea += 2; } } static int generate_lwc2(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { //int loopdest; UINT32 op = desc->opptr.l[0]; //int dest = (op >> 16) & 0x1f; //int base = (op >> 21) & 0x1f; //int index = (op >> 7) & 0xf; int offset = (op & 0x7f); //int skip; if (offset & 0x40) { offset |= 0xffffffc0; } switch ((op >> 11) & 0x1f) { case 0x00: /* LBV */ //UML_ADD(block, I0, R32(RSREG), offset); UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lbv, rsp); return TRUE; case 0x01: /* LSV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lsv, rsp); return TRUE; case 0x02: /* LLV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_llv, rsp); return TRUE; case 0x03: /* LDV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_ldv, rsp); return TRUE; case 0x04: /* LQV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lqv, rsp); return TRUE; case 0x05: /* LRV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lrv, rsp); return TRUE; case 0x06: /* LPV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lpv, rsp); return TRUE; case 0x07: /* LUV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_luv, rsp); return TRUE; case 0x08: /* LHV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lhv, rsp); return TRUE; case 0x09: /* LFV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lfv, rsp); return TRUE; case 0x0a: /* LWV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_lwv, rsp); return TRUE; case 0x0b: /* LTV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_ltv, rsp); return TRUE; default: return FALSE; } } static void cfunc_rsp_sbv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | // -------------------------------------------------- // // Stores 1 byte from vector byte index ea = (base) ? rsp->r[base] + offset : offset; WRITE8(rsp, ea, VREG_B(dest, index)); } static void cfunc_rsp_ssv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | // -------------------------------------------------- // // Stores 2 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 2) : (offset * 2); int end = index + 2; for (int i = index; i < end; i++) { WRITE8(rsp, ea, VREG_B(dest, i)); ea++; } } static void cfunc_rsp_slv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | // -------------------------------------------------- // // Stores 4 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 4) : (offset * 4); int end = index + 4; for (int i = index; i < end; i++) { WRITE8(rsp, ea, VREG_B(dest, i)); ea++; } } static void cfunc_rsp_sdv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int end = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | // -------------------------------------------------- // // Stores 8 bytes starting from vector byte index ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8); end = index + 8; for (int i = index; i < end; i++) { WRITE8(rsp, ea, VREG_B(dest, i)); ea++; } } static void cfunc_rsp_sqv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int end = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset | // -------------------------------------------------- // // Stores up to 16 bytes starting from vector byte index until 16-byte boundary ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); end = index + (16 - (ea & 0xf)); for (i=index; i < end; i++) { WRITE8(rsp, ea, VREG_B(dest, i & 0xf)); ea++; } } static void cfunc_rsp_srv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset | // -------------------------------------------------- // // Stores up to 16 bytes starting from right side until 16-byte boundary UINT32 ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); int end = index + (ea & 0xf); int o = (16 - (ea & 0xf)) & 0xf; ea &= ~0xf; for (int i = index; i < end; i++) { WRITE8(rsp, ea, VREG_B(dest, ((i + o) & 0xf))); ea++; } } static void cfunc_rsp_spv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int end = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | // -------------------------------------------------- // // Stores upper 8 bits of each element ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8); end = index + 8; for (i=index; i < end; i++) { if ((i & 0xf) < 8) { WRITE8(rsp, ea, VREG_B(dest, ((i & 0xf) << 1))); } else { WRITE8(rsp, ea, VREG_S(dest, (i & 0x7)) >> 7); } ea++; } } static void cfunc_rsp_suv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int end = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | // -------------------------------------------------- // // Stores bits 14-7 of each element ea = (base) ? rsp->r[base] + (offset * 8) : (offset * 8); end = index + 8; for (i=index; i < end; i++) { if ((i & 0xf) < 8) { WRITE8(rsp, ea, VREG_S(dest, (i & 0x7)) >> 7); } else { WRITE8(rsp, ea, VREG_B(dest, ((i & 0x7) << 1))); } ea++; } } static void cfunc_rsp_shv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset | // -------------------------------------------------- // // Stores bits 14-7 of each element, with 2-byte stride ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); for (i=0; i < 8; i++) { UINT8 d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) | ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7); WRITE8(rsp, ea, d); ea += 2; } } static void cfunc_rsp_sfv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int end = 0; int eaoffset = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset | // -------------------------------------------------- // // Stores bits 14-7 of upper or lower quad, with 4-byte stride if (index & 0x7) printf("RSP: SFV: index = %d at %08X\n", index, rsp->ppc); ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); eaoffset = ea & 0xf; ea &= ~0xf; end = (index >> 1) + 4; for (i=index >> 1; i < end; i++) { WRITE8(rsp, ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); eaoffset += 4; } } static void cfunc_rsp_swv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int end = 0; int eaoffset = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset | // -------------------------------------------------- // // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 // after byte index 15 ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); eaoffset = ea & 0xf; ea &= ~0xf; end = index + 16; for (i=index; i < end; i++) { WRITE8(rsp, ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); eaoffset++; } } static void cfunc_rsp_stv(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; UINT32 ea = 0; int i = 0; int dest = (op >> 16) & 0x1f; int base = (op >> 21) & 0x1f; int index = (op >> 7) & 0xf; int offset = (op & 0x7f); if (offset & 0x40) { offset |= 0xffffffc0; } // 31 25 20 15 10 6 0 // -------------------------------------------------- // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | // -------------------------------------------------- // // Stores one element from maximum of 8 vectors, while incrementing element index int vs = dest; int ve = dest + 8; if (ve > 32) { ve = 32; } int element = 8 - (index >> 1); ea = (base) ? rsp->r[base] + (offset * 16) : (offset * 16); int eaoffset = (ea & 0xf) + (element * 2); ea &= ~0xf; for (i=vs; i < ve; i++) { WRITE16(rsp, ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); eaoffset += 2; element++; } } static int generate_swc2(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { // int loopdest; UINT32 op = desc->opptr.l[0]; //int dest = (op >> 16) & 0x1f; //int base = (op >> 21) & 0x1f; //int index = (op >> 7) & 0xf; int offset = (op & 0x7f); //int skip; if (offset & 0x40) { offset |= 0xffffffc0; } switch ((op >> 11) & 0x1f) { case 0x00: /* SBV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_sbv, rsp); return TRUE; case 0x01: /* SSV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_ssv, rsp); return TRUE; case 0x02: /* SLV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_slv, rsp); return TRUE; case 0x03: /* SDV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_sdv, rsp); return TRUE; case 0x04: /* SQV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_sqv, rsp); return TRUE; case 0x05: /* SRV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_srv, rsp); return TRUE; case 0x06: /* SPV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_spv, rsp); return TRUE; case 0x07: /* SUV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_suv, rsp); return TRUE; case 0x08: /* SHV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_shv, rsp); return TRUE; case 0x09: /* SFV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_sfv, rsp); return TRUE; case 0x0a: /* SWV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_swv, rsp); return TRUE; case 0x0b: /* STV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_stv, rsp); return TRUE; default: unimplemented_opcode(rsp, op); return FALSE; } return TRUE; } INLINE UINT16 SATURATE_ACCUM(rsp_state *rsp, int accum, int slice, UINT16 negative, UINT16 positive) { if ((INT16)ACCUM_H(accum) < 0) { if ((UINT16)(ACCUM_H(accum)) != 0xffff) { return negative; } else { if ((INT16)ACCUM_M(accum) >= 0) { return negative; } else { if (slice == 0) { return ACCUM_L(accum); } else if (slice == 1) { return ACCUM_M(accum); } } } } else { if ((UINT16)(ACCUM_H(accum)) != 0) { return positive; } else { if ((INT16)ACCUM_M(accum) < 0) { return positive; } else { if (slice == 0) { return ACCUM_L(accum); } else { return ACCUM_M(accum); } } } } return 0; } INLINE UINT16 SATURATE_ACCUM1(rsp_state *rsp, int accum, UINT16 negative, UINT16 positive) { if ((INT16)ACCUM_H(accum) < 0) { if ((UINT16)(ACCUM_H(accum)) != 0xffff) { return negative; } else { if ((INT16)ACCUM_M(accum) >= 0) { return negative; } else { return ACCUM_M(accum); } } } else { if ((UINT16)(ACCUM_H(accum)) != 0) { return positive; } else { if ((INT16)ACCUM_M(accum) < 0) { return positive; } else { return ACCUM_M(accum); } } } return 0; } #define WRITEBACK_RESULT() { \ VREG_S(VDREG, 0) = vres[0]; \ VREG_S(VDREG, 1) = vres[1]; \ VREG_S(VDREG, 2) = vres[2]; \ VREG_S(VDREG, 3) = vres[3]; \ VREG_S(VDREG, 4) = vres[4]; \ VREG_S(VDREG, 5) = vres[5]; \ VREG_S(VDREG, 6) = vres[6]; \ VREG_S(VDREG, 7) = vres[7]; \ } INLINE void cfunc_rsp_vmulf(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; //int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | // ------------------------------------------------------ // // Multiplies signed integer by signed integer * 2 int sel; INT32 s1, s2; INT64 r; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); if (s1 == -32768 && s2 == -32768) { // overflow ACCUM_H(i) = 0; ACCUM_M(i) = -32768; ACCUM_L(i) = -32768; vres[i] = 0x7fff; } else { r = s1 * s2 * 2; r += 0x8000; // rounding ? ACCUM_H(i) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit ACCUM_M(i) = (INT16)(r >> 16); ACCUM_L(i) = (UINT16)(r); vres[i] = ACCUM_M(i); } } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmulu(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | // ------------------------------------------------------ // int sel; INT32 s1, s2; INT64 r; for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r = s1 * s2 * 2; r += 0x8000; // rounding ? ACCUM_H(i) = (UINT16)(r >> 32); ACCUM_M(i) = (UINT16)(r >> 16); ACCUM_L(i) = (UINT16)(r); if (r < 0) { vres[i] = 0; } else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) { vres[i] = -1; } else { vres[i] = ACCUM_M(i); } } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmudl(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | // ------------------------------------------------------ // // Multiplies signed integer by unsigned fraction // The result is added into accumulator // The middle slice of accumulator is stored into destination element int sel; UINT32 s1, s2; UINT32 r; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel); r = s1 * s2; ACCUM_H(i) = 0; ACCUM_M(i) = 0; ACCUM_L(i) = (UINT16)(r >> 16); vres[i] = ACCUM_L(i); } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmudm(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; //int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 | // ------------------------------------------------------ // // Multiplies signed integer by unsigned fraction // The result is stored into accumulator // The middle slice of accumulator is stored into destination element int sel; INT32 s1, s2; INT32 r; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (UINT16)VREG_S(VS2REG, sel); // not sign-extended r = s1 * s2; ACCUM_H(i) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit ACCUM_M(i) = (INT16)(r >> 16); ACCUM_L(i) = (UINT16)(r); vres[i] = ACCUM_M(i); } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmudn(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 | // ------------------------------------------------------ // // Multiplies unsigned fraction by signed integer // The result is stored into accumulator // The low slice of accumulator is stored into destination element int sel; INT32 s1, s2; INT32 r; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r = s1 * s2; ACCUM_H(i) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit ACCUM_M(i) = (INT16)(r >> 16); ACCUM_L(i) = (UINT16)(r); vres[i] = ACCUM_L(i); } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmudh(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 | // ------------------------------------------------------ // // Multiplies signed integer by signed integer // The result is stored into highest 32 bits of accumulator, the low slice is zero // The highest 32 bits of accumulator is saturated into destination element int sel; INT32 s1, s2; INT32 r; for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r = s1 * s2; ACCUM_H(i) = (INT16)(r >> 16); ACCUM_M(i) = (UINT16)(r); ACCUM_L(i) = 0; if (r < -32768) r = -32768; if (r > 32767) r = 32767; vres[i] = (INT16)(r); } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmacf(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int sel; INT32 s1, s2; INT32 r; UINT16 res; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r = s1 * s2; ACCUM(i) += (INT64)(r) << 17; res = SATURATE_ACCUM(rsp, i, 1, 0x8000, 0x7fff); vres[i] = res; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmacu(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | // ------------------------------------------------------ // UINT16 res; int sel; INT32 s1, s2, r1; UINT32 r2, r3; for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r1 = s1 * s2; r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2); r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16); ACCUM_L(i) = (UINT16)(r2); ACCUM_M(i) = (UINT16)(r3); ACCUM_H(i) += (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31); //res = SATURATE_ACCUM(i, 1, 0x0000, 0xffff); if ((INT16)ACCUM_H(i) < 0) { res = 0; } else { if (ACCUM_H(i) != 0) { res = 0xffff; } else { if ((INT16)ACCUM_M(i) < 0) { res = 0xffff; } else { res = ACCUM_M(i); } } } vres[i] = res; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmadl(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 | // ------------------------------------------------------ // // Multiplies unsigned fraction by unsigned fraction // Adds the higher 16 bits of the 32-bit result to accumulator // The low slice of accumulator is stored into destination element UINT16 res; int sel; UINT32 s1, s2, r1; UINT32 r2, r3; for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel); r1 = s1 * s2; r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); ACCUM_L(i) = (UINT16)(r2); ACCUM_M(i) = (UINT16)(r3); ACCUM_H(i) += (INT16)(r3 >> 16); res = SATURATE_ACCUM(rsp, i, 0, 0x0000, 0xffff); vres[i] = res; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmadm(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; UINT16 res; int sel; UINT32 s1, s2, r1; UINT32 r2, r3; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (UINT16)VREG_S(VS2REG, sel); // not sign-extended r1 = s1 * s2; r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1); r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); ACCUM_L(i) = (UINT16)(r2); ACCUM_M(i) = (UINT16)(r3); ACCUM_H(i) += (UINT16)(r3 >> 16); if ((INT32)(r1) < 0) ACCUM_H(i) -= 1; res = SATURATE_ACCUM(rsp, i, 1, 0x8000, 0x7fff); vres[i] = res; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmadn(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; INT32 s1, s2; UINT16 res; int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended s2 = (INT32)(INT16)VREG_S(VS2REG, sel); ACCUM(i) += (INT64)(s1*s2)<<16; res = SATURATE_ACCUM(rsp, i, 0, 0x0000, 0xffff); vres[i] = res; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmadh(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 | // ------------------------------------------------------ // // Multiplies signed integer by signed integer // The result is added into highest 32 bits of accumulator, the low slice is zero // The highest 32 bits of accumulator is saturated into destination element UINT16 res; int sel; INT32 s1, s2; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); rsp->accum[i].l[1] += s1*s2; res = SATURATE_ACCUM1(rsp, i, 0x8000, 0x7fff); vres[i] = res; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vadd(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; //int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 | // ------------------------------------------------------ // // Adds two vector registers and carry flag, the result is saturated to 32767 int sel; INT32 s1, s2, r; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r = s1 + s2 + CARRY_FLAG(i); ACCUM_L(i) = (INT16)(r); if (r > 32767) r = 32767; if (r < -32768) r = -32768; vres[i] = (INT16)(r); } CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vsub(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 | // ------------------------------------------------------ // // Subtracts two vector registers and carry flag, the result is saturated to -32768 // TODO: check VS2REG == VDREG int sel; INT32 s1, s2, r; for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT32)(INT16)VREG_S(VS1REG, i); s2 = (INT32)(INT16)VREG_S(VS2REG, sel); r = s1 - s2 - CARRY_FLAG(i); ACCUM_L(i) = (INT16)(r); if (r > 32767) r = 32767; if (r < -32768) r = -32768; vres[i] = (INT16)(r); } CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vabs(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 | // ------------------------------------------------------ // // Changes the sign of source register 2 if source register 1 is negative and stores // the result to destination register int sel; INT16 s1, s2; for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (INT16)VREG_S(VS1REG, i); s2 = (INT16)VREG_S(VS2REG, sel); if (s1 < 0) { if (s2 == -32768) { vres[i] = 32767; } else { vres[i] = -s2; } } else if (s1 > 0) { vres[i] = s2; } else { vres[i] = 0; } ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vaddc(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 | // ------------------------------------------------------ // // Adds two vector registers, the carry out is stored into carry register // TODO: check VS2REG = VDREG int sel; INT32 s1, s2, r; CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel); r = s1 + s2; vres[i] = (INT16)(r); ACCUM_L(i) = (INT16)(r); if (r & 0xffff0000) { SET_CARRY_FLAG(i); } } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vsubc(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 | // ------------------------------------------------------ // // Subtracts two vector registers, the carry out is stored into carry register // TODO: check VS2REG = VDREG int sel; INT32 s1, s2, r; CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel); r = s1 - s2; vres[i] = (INT16)(r); ACCUM_L(i) = (UINT16)(r); if ((UINT16)(r) != 0) { SET_ZERO_FLAG(i); } if (r & 0xffff0000) { SET_CARRY_FLAG(i); } } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vsaw(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 | // ------------------------------------------------------ // // Stores high, middle or low slice of accumulator to destination vector switch (EL) { case 0x08: // VSAWH { for (int i = 0; i < 8; i++) { VREG_S(VDREG, i) = ACCUM_H(i); } break; } case 0x09: // VSAWM { for (int i = 0; i < 8; i++) { VREG_S(VDREG, i) = ACCUM_M(i); } break; } case 0x0a: // VSAWL { for (int i = 0; i < 8; i++) { VREG_S(VDREG, i) = ACCUM_L(i); } break; } default: fatalerror("RSP: VSAW: el = %d\n", EL); } } INLINE void cfunc_rsp_vlt(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; //int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 | // ------------------------------------------------------ // // Sets compare flags if elements in VS1 are less than VS2 // Moves the element in VS2 to destination vector int sel; rsp->flag[1] = 0; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); if (VREG_S(VS1REG, i) < VREG_S(VS2REG, sel)) { SET_COMPARE_FLAG(i); } else if (VREG_S(VS1REG, i) == VREG_S(VS2REG, sel)) { if (ZERO_FLAG(i) == 1 && CARRY_FLAG(i) != 0) { SET_COMPARE_FLAG(i); } } if (COMPARE_FLAG(i)) { vres[i] = VREG_S(VS1REG, i); } else { vres[i] = VREG_S(VS2REG, sel); } ACCUM_L(i) = vres[i]; } rsp->flag[0] = 0; WRITEBACK_RESULT(); } INLINE void cfunc_rsp_veq(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 | // ------------------------------------------------------ // // Sets compare flags if elements in VS1 are equal with VS2 // Moves the element in VS2 to destination vector int sel; rsp->flag[1] = 0; for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); if ((VREG_S(VS1REG, i) == VREG_S(VS2REG, sel)) && ZERO_FLAG(i) == 0) { SET_COMPARE_FLAG(i); vres[i] = VREG_S(VS1REG, i); } else { vres[i] = VREG_S(VS2REG, sel); } ACCUM_L(i) = vres[i]; } rsp->flag[0] = 0; WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vne(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 | // ------------------------------------------------------ // // Sets compare flags if elements in VS1 are not equal with VS2 // Moves the element in VS2 to destination vector int sel; rsp->flag[1] = 0; for (i=0; i < 8; i++)//?????????? ???? { sel = VEC_EL_2(EL, i); if (VREG_S(VS1REG, i) != VREG_S(VS2REG, sel)) { SET_COMPARE_FLAG(i); } else { if (ZERO_FLAG(i) == 1) { SET_COMPARE_FLAG(i); } } if (COMPARE_FLAG(i)) { vres[i] = VREG_S(VS1REG, i); } else { vres[i] = VREG_S(VS2REG, sel); } ACCUM_L(i) = vres[i]; } rsp->flag[0] = 0; WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vge(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; //int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 | // ------------------------------------------------------ // // Sets compare flags if elements in VS1 are greater or equal with VS2 // Moves the element in VS2 to destination vector int sel; rsp->flag[1] = 0; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); if (VREG_S(VS1REG, i) == VREG_S(VS2REG, sel)) { if (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0) { SET_COMPARE_FLAG(i); } } else if (VREG_S(VS1REG, i) > VREG_S(VS2REG, sel)) { SET_COMPARE_FLAG(i); } if (COMPARE_FLAG(i) != 0) { vres[i] = VREG_S(VS1REG, i); } else { vres[i] = VREG_S(VS2REG, sel); } ACCUM_L(i) = vres[i]; } rsp->flag[0] = 0; WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vcl(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | // ------------------------------------------------------ // // Vector clip low int sel; INT16 s1, s2; for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = VREG_S(VS1REG, i); s2 = VREG_S(VS2REG, sel); if (CARRY_FLAG(i) != 0) { if (ZERO_FLAG(i) != 0) { if (COMPARE_FLAG(i) != 0) { ACCUM_L(i) = -(UINT16)s2; } else { ACCUM_L(i) = s1; } } else//ZERO_FLAG(i)==0 { if (rsp->flag[2] & (1 << (i))) { if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) {//proper fix for Harvest Moon 64, r4 ACCUM_L(i) = s1; CLEAR_COMPARE_FLAG(i); } else { ACCUM_L(i) = -((UINT16)s2); SET_COMPARE_FLAG(i); } } else { if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) { ACCUM_L(i) = s1; CLEAR_COMPARE_FLAG(i); } else { ACCUM_L(i) = -((UINT16)s2); SET_COMPARE_FLAG(i); } } } }// else//CARRY_FLAG(i)==0 { if (ZERO_FLAG(i) != 0) { if (rsp->flag[1] & (1 << (8+i))) { ACCUM_L(i) = s2; } else { ACCUM_L(i) = s1; } } else { if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0) { ACCUM_L(i) = s2; rsp->flag[1] |= (1 << (8+i)); } else { ACCUM_L(i) = s1; rsp->flag[1] &= ~(1 << (8+i)); } } } vres[i] = ACCUM_L(i); } rsp->flag[0] = 0; rsp->flag[2] = 0; WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vch(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | // ------------------------------------------------------ // // Vector clip high int sel; INT16 s1, s2; rsp->flag[0] = 0; rsp->flag[1] = 0; rsp->flag[2] = 0; UINT32 vce = 0; for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = VREG_S(VS1REG, i); s2 = VREG_S(VS2REG, sel); if ((s1 ^ s2) < 0) { vce = (s1 + s2 == -1); SET_CARRY_FLAG(i); if (s2 < 0) { rsp->flag[1] |= (1 << (8+i)); } if (s1 + s2 <= 0) { SET_COMPARE_FLAG(i); vres[i] = -((UINT16)s2); } else { vres[i] = s1; } if (s1 + s2 != 0) { if (s1 != ~s2) { SET_ZERO_FLAG(i); } } }//sign else { vce = 0; if (s2 < 0) { SET_COMPARE_FLAG(i); } if (s1 - s2 >= 0) { rsp->flag[1] |= (1 << (8+i)); vres[i] = s2; } else { vres[i] = s1; } if ((s1 - s2) != 0) { if (s1 != ~s2) { SET_ZERO_FLAG(i); } } } rsp->flag[2] |= (vce << (i)); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vcr(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8]; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | // ------------------------------------------------------ // // Vector clip reverse int sel; INT16 s1, s2; rsp->flag[0] = 0; rsp->flag[1] = 0; rsp->flag[2] = 0; for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); s1 = VREG_S(VS1REG, i); s2 = VREG_S(VS2REG, sel); if ((INT16)(s1 ^ s2) < 0) { if (s2 < 0) { rsp->flag[1] |= (1 << (8+i)); } if ((s1 + s2) <= 0) { ACCUM_L(i) = ~((UINT16)s2); SET_COMPARE_FLAG(i); } else { ACCUM_L(i) = s1; } } else { if (s2 < 0) { SET_COMPARE_FLAG(i); } if ((s1 - s2) >= 0) { ACCUM_L(i) = s2; rsp->flag[1] |= (1 << (8+i)); } else { ACCUM_L(i) = s1; } } vres[i] = ACCUM_L(i); } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vmrg(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | // ------------------------------------------------------ // // Merges two vectors according to compare flags int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); if (COMPARE_FLAG(i) != 0) { vres[i] = VREG_S(VS1REG, i); } else { vres[i] = VREG_S(VS2REG, sel);//??? ??????????? } ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vand(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | // ------------------------------------------------------ // // Bitwise AND of two vector registers int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); vres[i] = VREG_S(VS1REG, i) & VREG_S(VS2REG, sel); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vnand(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 }; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | // ------------------------------------------------------ // // Bitwise NOT AND of two vector registers int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); vres[i] = ~((VREG_S(VS1REG, i) & VREG_S(VS2REG, sel))); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vor(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 };; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | // ------------------------------------------------------ // // Bitwise OR of two vector registers int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); vres[i] = VREG_S(VS1REG, i) | VREG_S(VS2REG, sel); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vnor(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 };; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | // ------------------------------------------------------ // // Bitwise NOT OR of two vector registers int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); vres[i] = ~((VREG_S(VS1REG, i) | VREG_S(VS2REG, sel))); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vxor(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 };; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | // ------------------------------------------------------ // // Bitwise XOR of two vector registers int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); vres[i] = VREG_S(VS1REG, i) ^ VREG_S(VS2REG, sel); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vnxor(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; INT16 vres[8] = { 0 };; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | // ------------------------------------------------------ // // Bitwise NOT XOR of two vector registers int sel; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); vres[i] = ~((VREG_S(VS1REG, i) ^ VREG_S(VS2REG, sel))); ACCUM_L(i) = vres[i]; } WRITEBACK_RESULT(); } INLINE void cfunc_rsp_vrcp(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | // ------------------------------------------------------ // // Calculates reciprocal int del = VS1REG & 7; int sel = EL & 7; INT32 shifter = 0; INT32 rec = (INT16)(VREG_S(VS2REG, sel)); INT32 datainput = (rec < 0) ? (-rec) : rec; if (datainput) { for (i = 0; i < 32; i++) { if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i { shifter = i; break; } } } else { shifter = 0x10; } INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; INT32 fetchval = rsp_divtable[address]; INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); if (rec < 0) { temp = ~temp; } if (!rec) { temp = 0x7fffffff; } else if (rec == 0xffff8000) { temp = 0xffff0000; } rec = temp; rsp->reciprocal_res = rec; rsp->dp_allowed = 0; VREG_S(VDREG, del) = (UINT16)(rec & 0xffff); for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); ACCUM_L(i) = VREG_S(VS2REG, sel); } } INLINE void cfunc_rsp_vrcpl(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | // ------------------------------------------------------ // // Calculates reciprocal low part int del = VS1REG & 7; int sel = EL & 7; INT32 shifter = 0; INT32 rec = ((UINT16)(VREG_S(VS2REG, sel)) | ((UINT32)(rsp->reciprocal_high) & 0xffff0000)); INT32 datainput = rec; if (rec < 0) { if (rsp->dp_allowed) { if (rec < -32768) { datainput = ~datainput; } else { datainput = -datainput; } } else { datainput = -datainput; } } if (datainput) { for (i = 0; i < 32; i++) { if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i { shifter = i; break; } } } else { if (rsp->dp_allowed) { shifter = 0; } else { shifter = 0x10; } } INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; INT32 fetchval = rsp_divtable[address]; INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); if (rec < 0) { temp = ~temp; } if (!rec) { temp = 0x7fffffff; } else if (rec == 0xffff8000) { temp = 0xffff0000; } rec = temp; rsp->reciprocal_res = rec; rsp->dp_allowed = 0; VREG_S(VDREG, del) = (UINT16)(rec & 0xffff); for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); ACCUM_L(i) = VREG_S(VS2REG, sel); } } INLINE void cfunc_rsp_vrcph(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | // ------------------------------------------------------ // // Calculates reciprocal high part int del = VS1REG & 7; int sel = EL & 7; rsp->reciprocal_high = (VREG_S(VS2REG, sel)) << 16; rsp->dp_allowed = 1; for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); ACCUM_L(i) = VREG_S(VS2REG, sel); } VREG_S(VDREG, del) = (INT16)(rsp->reciprocal_res >> 16); } INLINE void cfunc_rsp_vmov(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | // ------------------------------------------------------ // // Moves element from vector to destination vector int del = VS1REG & 7; int sel = EL & 7; VREG_S(VDREG, del) = VREG_S(VS2REG, sel); for (int i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); ACCUM_L(i) = VREG_S(VS2REG, sel); } } INLINE void cfunc_rsp_vrsql(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | // ------------------------------------------------------ // // Calculates reciprocal square-root low part int del = VS1REG & 7; int sel = EL & 7; INT32 shifter = 0; INT32 rec = ((UINT16)(VREG_S(VS2REG, sel)) | ((UINT32)(rsp->reciprocal_high) & 0xffff0000)); INT32 datainput = rec; if (rec < 0) { if (rsp->dp_allowed) { if (rec < -32768)//VDIV.C,208 { datainput = ~datainput; } else { datainput = -datainput; } } else { datainput = -datainput; } } if (datainput) { for (i = 0; i < 32; i++) { if (datainput & (1 << ((~i) & 0x1f))) { shifter = i; break; } } } else { if (rsp->dp_allowed) { shifter = 0; } else { shifter = 0x10; } } INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; address = ((address | 0x200) & 0x3fe) | (shifter & 1); INT32 fetchval = rsp_divtable[address]; INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); if (rec < 0) { temp = ~temp; } if (!rec) { temp = 0x7fffffff; } else if (rec == 0xffff8000) { temp = 0xffff0000; } rec = temp; rsp->reciprocal_res = rec; rsp->dp_allowed = 0; VREG_S(VDREG, del) = (UINT16)(rec & 0xffff); for (i = 0; i < 8; i++) { sel = VEC_EL_2(EL, i); ACCUM_L(i) = VREG_S(VS2REG, sel); } } INLINE void cfunc_rsp_vrsqh(void *param) { rsp_state *rsp = (rsp_state*)param; int op = rsp->impstate->arg0; int i; // 31 25 24 20 15 10 5 0 // ------------------------------------------------------ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | // ------------------------------------------------------ // // Calculates reciprocal square-root high part int del = VS1REG & 7; int sel = EL & 7; rsp->reciprocal_high = (VREG_S(VS2REG, sel)) << 16; rsp->dp_allowed = 1; for (i=0; i < 8; i++) { sel = VEC_EL_2(EL, i); ACCUM_L(i) = VREG_S(VS2REG, sel); } VREG_S(VDREG, del) = (INT16)(rsp->reciprocal_res >> 16); // store high part } static void cfunc_sp_set_status_cb(void *param) { rsp_state *rsp = (rsp_state*)param; (rsp->config->sp_set_status)(rsp->device, rsp->impstate->arg0); } static CPU_EXECUTE( rsp ) { rsp_state *rsp = get_safe_token(device); drcuml_state *drcuml = rsp->impstate->drcuml; int execute_result; /* reset the cache if dirty */ if (rsp->impstate->cache_dirty) code_flush_cache(rsp); rsp->impstate->cache_dirty = FALSE; /* execute */ do { if( rsp->sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) { rsp->icount = MIN(rsp->icount, 0); break; } /* run as much as we can */ execute_result = drcuml->execute(*rsp->impstate->entry); /* if we need to recompile, do it */ if (execute_result == EXECUTE_MISSING_CODE) { code_compile_block(rsp, rsp->pc); } else if (execute_result == EXECUTE_UNMAPPED_CODE) { fatalerror("Attempted to execute unmapped code at PC=%08X\n", rsp->pc); } else if (execute_result == EXECUTE_RESET_CACHE) { code_flush_cache(rsp); } } while (execute_result != EXECUTE_OUT_OF_CYCLES); } /*************************************************************************** CACHE MANAGEMENT ***************************************************************************/ /*------------------------------------------------- rspdrc_flush_drc_cache - outward-facing accessor to code_flush_cache -------------------------------------------------*/ void rspdrc_flush_drc_cache(device_t *device) { rsp_state *rsp = get_safe_token(device); rsp->impstate->cache_dirty = TRUE; } /*------------------------------------------------- code_flush_cache - flush the cache and regenerate static code -------------------------------------------------*/ static void code_flush_cache(rsp_state *rsp) { /* empty the transient cache contents */ rsp->impstate->drcuml->reset(); try { /* generate the entry point and out-of-cycles handlers */ static_generate_entry_point(rsp); static_generate_nocode_handler(rsp); static_generate_out_of_cycles(rsp); /* add subroutines for memory accesses */ static_generate_memory_accessor(rsp, 1, FALSE, "read8", rsp->impstate->read8); static_generate_memory_accessor(rsp, 1, TRUE, "write8", rsp->impstate->write8); static_generate_memory_accessor(rsp, 2, FALSE, "read16", rsp->impstate->read16); static_generate_memory_accessor(rsp, 2, TRUE, "write16", rsp->impstate->write16); static_generate_memory_accessor(rsp, 4, FALSE, "read32", rsp->impstate->read32); static_generate_memory_accessor(rsp, 4, TRUE, "write32", rsp->impstate->write32); } catch (drcuml_block::abort_compilation &) { fatalerror("Unable to generate static RSP code"); } } /*------------------------------------------------- code_compile_block - compile a block of the given mode at the specified pc -------------------------------------------------*/ static void code_compile_block(rsp_state *rsp, offs_t pc) { drcuml_state *drcuml = rsp->impstate->drcuml; compiler_state compiler = { 0 }; const opcode_desc *seqhead, *seqlast; const opcode_desc *desclist; int override = FALSE; drcuml_block *block; g_profiler.start(PROFILER_DRC_COMPILE); /* get a description of this sequence */ desclist = rsp->impstate->drcfe->describe_code(pc); bool succeeded = false; while (!succeeded) { try { /* start the block */ block = drcuml->begin_block(8192); /* loop until we get through all instruction sequences */ for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) { const opcode_desc *curdesc; UINT32 nextpc; /* add a code log entry */ if (LOG_UML) block->append_comment("-------------------------"); // comment /* determine the last instruction in this sequence */ for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) if (seqlast->flags & OPFLAG_END_SEQUENCE) break; assert(seqlast != NULL); /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ if (override || !drcuml->hash_exists(0, seqhead->pc)) UML_HASH(block, 0, seqhead->pc); // hash mode,pc /* if we already have a hash, and this is the first sequence, assume that we */ /* are recompiling due to being out of sync and allow future overrides */ else if (seqhead == desclist) { override = TRUE; UML_HASH(block, 0, seqhead->pc); // hash mode,pc } /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ else { UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc UML_HASHJMP(block, 0, seqhead->pc, *rsp->impstate->nocode); // hashjmp <0>,seqhead->pc,nocode continue; } /* validate this code block if we're not pointing into ROM */ if (rsp->program->get_write_ptr(seqhead->physpc) != NULL) generate_checksum_block(rsp, block, &compiler, seqhead, seqlast); /* label this instruction, if it may be jumped to locally */ if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc /* iterate over instructions in the sequence and compile them */ for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) generate_sequence_instruction(rsp, block, &compiler, curdesc); /* if we need to return to the start, do it */ if (seqlast->flags & OPFLAG_RETURN_TO_START) nextpc = pc; /* otherwise we just go to the next instruction */ else nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; /* count off cycles and go there */ generate_update_cycles(rsp, block, &compiler, nextpc, TRUE); // /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) UML_HASHJMP(block, 0, nextpc, *rsp->impstate->nocode); // hashjmp ,nextpc,nocode } /* end the sequence */ block->end(); g_profiler.stop(); succeeded = true; } catch (drcuml_block::abort_compilation &) { code_flush_cache(rsp); } } } /*************************************************************************** C FUNCTION CALLBACKS ***************************************************************************/ /*------------------------------------------------- cfunc_unimplemented - handler for unimplemented opcdes -------------------------------------------------*/ static void cfunc_unimplemented(void *param) { rsp_state *rsp = (rsp_state *)param; UINT32 opcode = rsp->impstate->arg0; fatalerror("PC=%08X: Unimplemented op %08X (%02X,%02X)", rsp->pc, opcode, opcode >> 26, opcode & 0x3f); } /*------------------------------------------------- cfunc_fatalerror - a generic fatalerror call -------------------------------------------------*/ #ifdef UNUSED_CODE static void cfunc_fatalerror(void *param) { fatalerror("fatalerror"); } #endif /*************************************************************************** STATIC CODEGEN ***************************************************************************/ /*------------------------------------------------- ferate_entry_point - generate a static entry point -------------------------------------------------*/ static void static_generate_entry_point(rsp_state *rsp) { drcuml_state *drcuml = rsp->impstate->drcuml; drcuml_block *block; /* begin generating */ block = drcuml->begin_block(20); /* forward references */ alloc_handle(drcuml, &rsp->impstate->nocode, "nocode"); alloc_handle(drcuml, &rsp->impstate->entry, "entry"); UML_HANDLE(block, *rsp->impstate->entry); // handle entry /* load fast integer registers */ load_fast_iregs(rsp, block); /* generate a hash jump via the current mode and PC */ UML_HASHJMP(block, 0, mem(&rsp->pc), *rsp->impstate->nocode); // hashjmp ,,nocode block->end(); } /*------------------------------------------------- static_generate_nocode_handler - generate an exception handler for "out of code" -------------------------------------------------*/ static void static_generate_nocode_handler(rsp_state *rsp) { drcuml_state *drcuml = rsp->impstate->drcuml; drcuml_block *block; /* begin generating */ block = drcuml->begin_block(10); /* generate a hash jump via the current mode and PC */ alloc_handle(drcuml, &rsp->impstate->nocode, "nocode"); UML_HANDLE(block, *rsp->impstate->nocode); // handle nocode UML_GETEXP(block, I0); // getexp i0 UML_MOV(block, mem(&rsp->pc), I0); // mov [pc],i0 save_fast_iregs(rsp, block); UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE block->end(); } /*------------------------------------------------- static_generate_out_of_cycles - generate an out of cycles exception handler -------------------------------------------------*/ static void static_generate_out_of_cycles(rsp_state *rsp) { drcuml_state *drcuml = rsp->impstate->drcuml; drcuml_block *block; /* begin generating */ block = drcuml->begin_block(10); /* generate a hash jump via the current mode and PC */ alloc_handle(drcuml, &rsp->impstate->out_of_cycles, "out_of_cycles"); UML_HANDLE(block, *rsp->impstate->out_of_cycles); // handle out_of_cycles UML_GETEXP(block, I0); // getexp i0 UML_MOV(block, mem(&rsp->pc), I0); // mov ,i0 save_fast_iregs(rsp, block); UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES block->end(); } /*------------------------------------------------------------------ static_generate_memory_accessor ------------------------------------------------------------------*/ static void static_generate_memory_accessor(rsp_state *rsp, int size, int iswrite, const char *name, code_handle *&handleptr) { /* on entry, address is in I0; data for writes is in I1 */ /* on exit, read result is in I0 */ /* routine trashes I0-I1 */ drcuml_state *drcuml = rsp->impstate->drcuml; drcuml_block *block; /* begin generating */ block = drcuml->begin_block(1024); /* add a global entry for this */ alloc_handle(drcuml, &handleptr, name); UML_HANDLE(block, *handleptr); // handle *handleptr // write: if (iswrite) { if (size == 1) { UML_MOV(block, mem(&rsp->impstate->arg0), I0); // mov [arg0],i0 ; address UML_MOV(block, mem(&rsp->impstate->arg1), I1); // mov [arg1],i1 ; data UML_CALLC(block, cfunc_write8, rsp); // callc cfunc_write8 } else if (size == 2) { UML_MOV(block, mem(&rsp->impstate->arg0), I0); // mov [arg0],i0 ; address UML_MOV(block, mem(&rsp->impstate->arg1), I1); // mov [arg1],i1 ; data UML_CALLC(block, cfunc_write16, rsp); // callc cfunc_write16 } else if (size == 4) { UML_MOV(block, mem(&rsp->impstate->arg0), I0); // mov [arg0],i0 ; address UML_MOV(block, mem(&rsp->impstate->arg1), I1); // mov [arg1],i1 ; data UML_CALLC(block, cfunc_write32, rsp); // callc cfunc_write32 } } else { if (size == 1) { UML_MOV(block, mem(&rsp->impstate->arg0), I0); // mov [arg0],i0 ; address UML_CALLC(block, cfunc_read8, rsp); // callc cfunc_printf_debug UML_MOV(block, I0, mem(&rsp->impstate->arg0)); // mov i0,[arg0],i0 ; result } else if (size == 2) { UML_MOV(block, mem(&rsp->impstate->arg0), I0); // mov [arg0],i0 ; address UML_CALLC(block, cfunc_read16, rsp); // callc cfunc_read16 UML_MOV(block, I0, mem(&rsp->impstate->arg0)); // mov i0,[arg0],i0 ; result } else if (size == 4) { UML_MOV(block, mem(&rsp->impstate->arg0), I0); // mov [arg0],i0 ; address UML_CALLC(block, cfunc_read32, rsp); // callc cfunc_read32 UML_MOV(block, I0, mem(&rsp->impstate->arg0)); // mov i0,[arg0],i0 ; result } } UML_RET(block); block->end(); } /*************************************************************************** CODE GENERATION ***************************************************************************/ /*------------------------------------------------- generate_update_cycles - generate code to subtract cycles from the icount and generate an exception if out -------------------------------------------------*/ static void generate_update_cycles(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, parameter param, int allow_exception) { /* account for cycles */ if (compiler->cycles > 0) { UML_SUB(block, mem(&rsp->icount), mem(&rsp->icount), MAPVAR_CYCLES); // sub icount,icount,cycles UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 UML_EXHc(block, COND_S, *rsp->impstate->out_of_cycles, param); } compiler->cycles = 0; } /*------------------------------------------------- generate_checksum_block - generate code to validate a sequence of opcodes -------------------------------------------------*/ static void generate_checksum_block(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) { const opcode_desc *curdesc; if (LOG_UML) { block->append_comment("[Validation for %08X]", seqhead->pc | 0x1000); // comment } /* loose verify or single instruction: just compare and fail */ if (!(rsp->impstate->drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next() == NULL) { if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) { void *base = rsp->direct->read_decrypted_ptr(seqhead->physpc | 0x1000); UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword UML_CMP(block, I0, seqhead->opptr.l[0]); // cmp i0,opptr[0] UML_EXHc(block, COND_NE, *rsp->impstate->nocode, epc(seqhead)); // exne nocode,seqhead->pc } } /* full verification; sum up everything */ else { UINT32 sum = 0; void *base = rsp->direct->read_decrypted_ptr(seqhead->physpc | 0x1000); UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword sum += seqhead->opptr.l[0]; for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { base = rsp->direct->read_decrypted_ptr(curdesc->physpc | 0x1000); UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword UML_ADD(block, I0, I0, I1); // add i0,i0,i1 sum += curdesc->opptr.l[0]; } UML_CMP(block, I0, sum); // cmp i0,sum UML_EXHc(block, COND_NE, *rsp->impstate->nocode, epc(seqhead)); // exne nocode,seqhead->pc } } /*------------------------------------------------- generate_sequence_instruction - generate code for a single instruction in a sequence -------------------------------------------------*/ static void generate_sequence_instruction(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { offs_t expc; /* add an entry for the log */ if (LOG_UML && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) log_add_disasm_comment(rsp, block, desc->pc, desc->opptr.l[0]); /* set the PC map variable */ expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc; UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc /* accumulate total cycles */ compiler->cycles += desc->cycles; /* update the icount map variable */ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles /* if we are debugging, call the debugger */ if ((rsp->device->machine->debug_flags & DEBUG_FLAG_ENABLED) != 0) { UML_MOV(block, mem(&rsp->pc), desc->pc); // mov [pc],desc->pc save_fast_iregs(rsp, block); UML_DEBUG(block, desc->pc); // debug desc->pc } /* if we hit an unmapped address, fatal error */ #if 0 if (desc->flags & OPFLAG_COMPILER_UNMAPPED) { UML_MOV(block, mem(&rsp->pc), desc->pc); // mov [pc],desc->pc save_fast_iregs(rsp, block); UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE } #endif /* otherwise, unless this is a virtual no-op, it's a regular instruction */ /*else*/ if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) { /* compile the instruction */ if (!generate_opcode(rsp, block, compiler, desc)) { UML_MOV(block, mem(&rsp->pc), desc->pc); // mov [pc],desc->pc UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_unimplemented, rsp); // callc cfunc_unimplemented } } } /*------------------------------------------------------------------ generate_delay_slot_and_branch ------------------------------------------------------------------*/ static void generate_delay_slot_and_branch(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg) { compiler_state compiler_temp = *compiler; UINT32 op = desc->opptr.l[0]; /* fetch the target register if dynamic, in case it is modified by the delay slot */ if (desc->targetpc == BRANCH_TARGET_DYNAMIC) { UML_AND(block, mem(&rsp->impstate->jmpdest), R32(RSREG), 0x00000fff); UML_OR(block, mem(&rsp->impstate->jmpdest), mem(&rsp->impstate->jmpdest), 0x1000); } /* set the link if needed -- before the delay slot */ if (linkreg != 0) { UML_MOV(block, R32(linkreg), (INT32)(desc->pc + 8)); // mov ,desc->pc + 8 } /* compile the delay slot using temporary compiler state */ assert(desc->delay.first() != NULL); generate_sequence_instruction(rsp, block, &compiler_temp, desc->delay.first()); // /* update the cycles and jump through the hash table to the target */ if (desc->targetpc != BRANCH_TARGET_DYNAMIC) { generate_update_cycles(rsp, block, &compiler_temp, desc->targetpc, TRUE); // if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) { UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc } else { UML_HASHJMP(block, 0, desc->targetpc, *rsp->impstate->nocode); // hashjmp ,desc->targetpc,nocode } } else { generate_update_cycles(rsp, block, &compiler_temp, mem(&rsp->impstate->jmpdest), TRUE); // UML_HASHJMP(block, 0, mem(&rsp->impstate->jmpdest), *rsp->impstate->nocode); // hashjmp ,,nocode } /* update the label */ compiler->labelnum = compiler_temp.labelnum; /* reset the mapvar to the current cycles and account for skipped slots */ compiler->cycles += desc->skipslots; UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles } /*------------------------------------------------- generate_opcode - generate code for a specific opcode -------------------------------------------------*/ static int generate_vector_opcode(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { UINT32 op = desc->opptr.l[0]; // Opcode legend: // E = VS2 element type // S = VS1, Source vector 1 // T = VS2, Source vector 2 // D = Destination vector switch (op & 0x3f) { case 0x00: /* VMULF */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmulf, rsp); return TRUE; case 0x01: /* VMULU */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmulu, rsp); return TRUE; case 0x04: /* VMUDL */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmudl, rsp); return TRUE; case 0x05: /* VMUDM */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmudm, rsp); return TRUE; case 0x06: /* VMUDN */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmudn, rsp); return TRUE; case 0x07: /* VMUDH */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmudh, rsp); return TRUE; case 0x08: /* VMACF */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmacf, rsp); return TRUE; case 0x09: /* VMACU */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmacu, rsp); return TRUE; case 0x0c: /* VMADL */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmadl, rsp); return TRUE; case 0x0d: /* VMADM */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmadm, rsp); return TRUE; case 0x0e: /* VMADN */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmadn, rsp); return TRUE; case 0x0f: /* VMADH */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmadh, rsp); return TRUE; case 0x10: /* VADD */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vadd, rsp); return TRUE; case 0x11: /* VSUB */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vsub, rsp); return TRUE; case 0x13: /* VABS */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vabs, rsp); return TRUE; case 0x14: /* VADDC */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vaddc, rsp); return TRUE; case 0x15: /* VSUBC */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vsubc, rsp); return TRUE; case 0x1d: /* VSAW */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vsaw, rsp); return TRUE; case 0x20: /* VLT */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vlt, rsp); return TRUE; case 0x21: /* VEQ */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_veq, rsp); return TRUE; case 0x22: /* VNE */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vne, rsp); return TRUE; case 0x23: /* VGE */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vge, rsp); return TRUE; case 0x24: /* VCL */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vcl, rsp); return TRUE; case 0x25: /* VCH */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vch, rsp); return TRUE; case 0x26: /* VCR */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vcr, rsp); return TRUE; case 0x27: /* VMRG */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmrg, rsp); return TRUE; case 0x28: /* VAND */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vand, rsp); return TRUE; case 0x29: /* VNAND */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vnand, rsp); return TRUE; case 0x2a: /* VOR */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vor, rsp); return TRUE; case 0x2b: /* VNOR */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vnor, rsp); return TRUE; case 0x2c: /* VXOR */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vxor, rsp); return TRUE; case 0x2d: /* VNXOR */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vnxor, rsp); return TRUE; case 0x30: /* VRCP */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vrcp, rsp); return TRUE; case 0x31: /* VRCPL */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vrcpl, rsp); return TRUE; case 0x32: /* VRCPH */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vrcph, rsp); return TRUE; case 0x33: /* VMOV */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vmov, rsp); return TRUE; case 0x35: /* VRSQL */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vrsql, rsp); return TRUE; case 0x36: /* VRSQH */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_rsp_vrsqh, rsp); return TRUE; default: UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_unimplemented_opcode, rsp); return FALSE; } } static int generate_opcode(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); UINT32 op = desc->opptr.l[0]; UINT8 opswitch = op >> 26; code_label skip; switch (opswitch) { /* ----- sub-groups ----- */ case 0x00: /* SPECIAL - MIPS I */ return generate_special(rsp, block, compiler, desc); case 0x01: /* REGIMM - MIPS I */ return generate_regimm(rsp, block, compiler, desc); /* ----- jumps and branches ----- */ case 0x02: /* J - MIPS I */ generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // return TRUE; case 0x03: /* JAL - MIPS I */ generate_delay_slot_and_branch(rsp, block, compiler, desc, 31); // return TRUE; case 0x04: /* BEQ - MIPS I */ UML_CMP(block, R32(RSREG), R32(RTREG)); // cmp , UML_JMPc(block, COND_NE, skip = compiler->labelnum++); // jmp skip,NE generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // UML_LABEL(block, skip); // skip: return TRUE; case 0x05: /* BNE - MIPS I */ UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp , UML_JMPc(block, COND_E, skip = compiler->labelnum++); // jmp skip,E generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // UML_LABEL(block, skip); // skip: return TRUE; case 0x06: /* BLEZ - MIPS I */ if (RSREG != 0) { UML_CMP(block, R32(RSREG), 0); // dcmp ,0 UML_JMPc(block, COND_G, skip = compiler->labelnum++); // jmp skip,G generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // UML_LABEL(block, skip); // skip: } else generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // return TRUE; case 0x07: /* BGTZ - MIPS I */ UML_CMP(block, R32(RSREG), 0); // dcmp ,0 UML_JMPc(block, COND_LE, skip = compiler->labelnum++); // jmp skip,LE generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // UML_LABEL(block, skip); // skip: return TRUE; /* ----- immediate arithmetic ----- */ case 0x0f: /* LUI - MIPS I */ if (RTREG != 0) UML_MOV(block, R32(RTREG), SIMMVAL << 16); // dmov ,SIMMVAL << 16 return TRUE; case 0x08: /* ADDI - MIPS I */ case 0x09: /* ADDIU - MIPS I */ if (RTREG != 0) { UML_ADD(block, R32(RTREG), R32(RSREG), SIMMVAL); // add i0,,SIMMVAL,V } return TRUE; case 0x0a: /* SLTI - MIPS I */ if (RTREG != 0) { UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp ,SIMMVAL UML_SETc(block, COND_L, R32(RTREG)); // dset ,l } return TRUE; case 0x0b: /* SLTIU - MIPS I */ if (RTREG != 0) { UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp ,SIMMVAL UML_SETc(block, COND_B, R32(RTREG)); // dset ,b } return TRUE; case 0x0c: /* ANDI - MIPS I */ if (RTREG != 0) UML_AND(block, R32(RTREG), R32(RSREG), UIMMVAL); // dand ,,UIMMVAL return TRUE; case 0x0d: /* ORI - MIPS I */ if (RTREG != 0) UML_OR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dor ,,UIMMVAL return TRUE; case 0x0e: /* XORI - MIPS I */ if (RTREG != 0) UML_XOR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dxor ,,UIMMVAL return TRUE; /* ----- memory load operations ----- */ case 0x20: /* LB - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_CALLH(block, *rsp->impstate->read8); // callh read8 if (RTREG != 0) UML_SEXT(block, R32(RTREG), I0, SIZE_BYTE); // dsext ,i0,byte if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x21: /* LH - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_CALLH(block, *rsp->impstate->read16); // callh read16 if (RTREG != 0) UML_SEXT(block, R32(RTREG), I0, SIZE_WORD); // dsext ,i0,word if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x23: /* LW - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_CALLH(block, *rsp->impstate->read32); // callh read32 if (RTREG != 0) UML_MOV(block, R32(RTREG), I0); if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x24: /* LBU - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_CALLH(block, *rsp->impstate->read8); // callh read8 if (RTREG != 0) UML_AND(block, R32(RTREG), I0, 0xff); // dand ,i0,0xff if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x25: /* LHU - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_CALLH(block, *rsp->impstate->read16); // callh read16 if (RTREG != 0) UML_AND(block, R32(RTREG), I0, 0xffff); // dand ,i0,0xffff if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x32: /* LWC2 - MIPS I */ return generate_lwc2(rsp, block, compiler, desc); /* ----- memory store operations ----- */ case 0x28: /* SB - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_MOV(block, I1, R32(RTREG)); // mov i1, UML_CALLH(block, *rsp->impstate->write8); // callh write8 if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x29: /* SH - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_MOV(block, I1, R32(RTREG)); // mov i1, UML_CALLH(block, *rsp->impstate->write16); // callh write16 if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x2b: /* SW - MIPS I */ UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL UML_MOV(block, I1, R32(RTREG)); // mov i1, UML_CALLH(block, *rsp->impstate->write32); // callh write32 if (!in_delay_slot) generate_update_cycles(rsp, block, compiler, desc->pc + 4, TRUE); return TRUE; case 0x3a: /* SWC2 - MIPS I */ return generate_swc2(rsp, block, compiler, desc); //UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l //UML_CALLC(block, cfunc_swc2, rsp); // callc cfunc_mfc2 //return TRUE; /* ----- coprocessor instructions ----- */ case 0x10: /* COP0 - MIPS I */ return generate_cop0(rsp, block, compiler, desc); case 0x12: /* COP2 - MIPS I */ return generate_cop2(rsp, block, compiler, desc); //UML_EXH(block, rsp->impstate->exception[EXCEPTION_INVALIDOP], 0);// exh invalidop,0 //return TRUE; /* ----- unimplemented/illegal instructions ----- */ //default: /* ??? */ invalid_instruction(op); break; } return FALSE; } /*------------------------------------------------- generate_special - compile opcodes in the 'SPECIAL' group -------------------------------------------------*/ static int generate_special(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { UINT32 op = desc->opptr.l[0]; UINT8 opswitch = op & 63; //code_label skip; switch (opswitch) { /* ----- shift instructions ----- */ case 0x00: /* SLL - MIPS I */ if (RDREG != 0) { UML_SHL(block, R32(RDREG), R32(RTREG), SHIFT); } return TRUE; case 0x02: /* SRL - MIPS I */ if (RDREG != 0) { UML_SHR(block, R32(RDREG), R32(RTREG), SHIFT); } return TRUE; case 0x03: /* SRA - MIPS I */ if (RDREG != 0) { UML_SAR(block, R32(RDREG), R32(RTREG), SHIFT); } return TRUE; case 0x04: /* SLLV - MIPS I */ if (RDREG != 0) { UML_SHL(block, R32(RDREG), R32(RTREG), R32(RSREG)); } return TRUE; case 0x06: /* SRLV - MIPS I */ if (RDREG != 0) { UML_SHR(block, R32(RDREG), R32(RTREG), R32(RSREG)); } return TRUE; case 0x07: /* SRAV - MIPS I */ if (RDREG != 0) { UML_SAR(block, R32(RDREG), R32(RTREG), R32(RSREG)); } return TRUE; /* ----- basic arithmetic ----- */ case 0x20: /* ADD - MIPS I */ case 0x21: /* ADDU - MIPS I */ if (RDREG != 0) { UML_ADD(block, R32(RDREG), R32(RSREG), R32(RTREG)); } return TRUE; case 0x22: /* SUB - MIPS I */ case 0x23: /* SUBU - MIPS I */ if (RDREG != 0) { UML_SUB(block, R32(RDREG), R32(RSREG), R32(RTREG)); } return TRUE; /* ----- basic logical ops ----- */ case 0x24: /* AND - MIPS I */ if (RDREG != 0) { UML_AND(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dand ,, } return TRUE; case 0x25: /* OR - MIPS I */ if (RDREG != 0) { UML_OR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dor ,, } return TRUE; case 0x26: /* XOR - MIPS I */ if (RDREG != 0) { UML_XOR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dxor ,, } return TRUE; case 0x27: /* NOR - MIPS I */ if (RDREG != 0) { UML_OR(block, I0, R32(RSREG), R32(RTREG)); // dor i0,, UML_XOR(block, R32(RDREG), I0, (UINT64)~0); // dxor ,i0,~0 } return TRUE; /* ----- basic comparisons ----- */ case 0x2a: /* SLT - MIPS I */ if (RDREG != 0) { UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp , UML_SETc(block, COND_L, R32(RDREG)); // dset ,l } return TRUE; case 0x2b: /* SLTU - MIPS I */ if (RDREG != 0) { UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp , UML_SETc(block, COND_B, R32(RDREG)); // dset ,b } return TRUE; /* ----- jumps and branches ----- */ case 0x08: /* JR - MIPS I */ generate_delay_slot_and_branch(rsp, block, compiler, desc, 0); // return TRUE; case 0x09: /* JALR - MIPS I */ generate_delay_slot_and_branch(rsp, block, compiler, desc, RDREG); // return TRUE; /* ----- system calls ----- */ case 0x0d: /* BREAK - MIPS I */ UML_MOV(block, mem(&rsp->impstate->arg0), 3); // mov [arg0],3 UML_CALLC(block, cfunc_sp_set_status_cb, rsp); // callc cfunc_sp_set_status_cb UML_MOV(block, mem(&rsp->icount), 0); // mov icount, #0 UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); return TRUE; } return FALSE; } /*------------------------------------------------- generate_regimm - compile opcodes in the 'REGIMM' group -------------------------------------------------*/ static int generate_regimm(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { UINT32 op = desc->opptr.l[0]; UINT8 opswitch = RTREG; code_label skip; switch (opswitch) { case 0x00: /* BLTZ */ case 0x10: /* BLTZAL */ if (RSREG != 0) { UML_CMP(block, R32(RSREG), 0); // dcmp ,0 UML_JMPc(block, COND_GE, skip = compiler->labelnum++); // jmp skip,GE generate_delay_slot_and_branch(rsp, block, compiler, desc, (opswitch & 0x10) ? 31 : 0); // UML_LABEL(block, skip); // skip: } return TRUE; case 0x01: /* BGEZ */ case 0x11: /* BGEZAL */ if (RSREG != 0) { UML_CMP(block, R32(RSREG), 0); // dcmp ,0 UML_JMPc(block, COND_L, skip = compiler->labelnum++); // jmp skip,L generate_delay_slot_and_branch(rsp, block, compiler, desc, (opswitch & 0x10) ? 31 : 0); // UML_LABEL(block, skip); // skip: } else generate_delay_slot_and_branch(rsp, block, compiler, desc, (opswitch & 0x10) ? 31 : 0); // return TRUE; } return FALSE; } /*------------------------------------------------- generate_cop2 - compile COP2 opcodes -------------------------------------------------*/ static int generate_cop2(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { UINT32 op = desc->opptr.l[0]; UINT8 opswitch = RSREG; switch (opswitch) { case 0x00: /* MFCz */ if (RTREG != 0) { UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_mfc2, rsp); // callc cfunc_mfc2 //UML_SEXT(block, R32(RTREG), I0, DWORD); // dsext ,i0,dword } return TRUE; case 0x02: /* CFCz */ if (RTREG != 0) { UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_cfc2, rsp); // callc cfunc_cfc2 //UML_SEXT(block, R32(RTREG), I0, DWORD); // dsext ,i0,dword } return TRUE; case 0x04: /* MTCz */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_mtc2, rsp); // callc cfunc_mtc2 return TRUE; case 0x06: /* CTCz */ UML_MOV(block, mem(&rsp->impstate->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l UML_CALLC(block, cfunc_ctc2, rsp); // callc cfunc_ctc2 return TRUE; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return generate_vector_opcode(rsp, block, compiler, desc); } return FALSE; } /*------------------------------------------------- generate_cop0 - compile COP0 opcodes -------------------------------------------------*/ static int generate_cop0(rsp_state *rsp, drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) { UINT32 op = desc->opptr.l[0]; UINT8 opswitch = RSREG; switch (opswitch) { case 0x00: /* MFCz */ if (RTREG != 0) { UML_MOV(block, mem(&rsp->impstate->arg0), RDREG); // mov [arg0], UML_MOV(block, mem(&rsp->impstate->arg1), RTREG); // mov [arg1], UML_CALLC(block, cfunc_get_cop0_reg, rsp); // callc cfunc_get_cop0_reg } return TRUE; case 0x04: /* MTCz */ UML_MOV(block, mem(&rsp->impstate->arg0), RDREG); // mov [arg0], UML_MOV(block, mem(&rsp->impstate->arg1), R32(RTREG)); // mov [arg1],rtreg UML_CALLC(block, cfunc_set_cop0_reg, rsp); // callc cfunc_set_cop0_reg return TRUE; } return FALSE; } static void cfunc_mfc2(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int el = (op >> 7) & 0xf; UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); } static void cfunc_cfc2(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; if (RTREG) { if (RDREG == 2) { // Anciliary clipping flags RTVAL = rsp->flag[RDREG] & 0x00ff; } else { // All other flags are 16 bits but sign-extended at retrieval RTVAL = (UINT32)rsp->flag[RDREG] | ( ( rsp->flag[RDREG] & 0x8000 ) ? 0xffff0000 : 0 ); } } } static void cfunc_mtc2(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; int el = (op >> 7) & 0xf; VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; } static void cfunc_ctc2(void *param) { rsp_state *rsp = (rsp_state*)param; UINT32 op = rsp->impstate->arg0; rsp->flag[RDREG] = RTVAL & 0xffff; } /*************************************************************************** CODE LOGGING HELPERS ***************************************************************************/ /*------------------------------------------------- log_add_disasm_comment - add a comment including disassembly of a RSP instruction -------------------------------------------------*/ static void log_add_disasm_comment(rsp_state *rsp, drcuml_block *block, UINT32 pc, UINT32 op) { #if (LOG_UML) char buffer[100]; rsp_dasm_one(buffer, pc, op); block->append_comment("%08X: %s", pc, buffer); // comment #endif } static CPU_SET_INFO( rsp ) { rsp_state *rsp = get_safe_token(device); switch (state) { /* --- the following bits of info are set as 64-bit signed integers --- */ case CPUINFO_INT_PC: case CPUINFO_INT_REGISTER + RSP_PC: rsp->pc = info->i; break; case CPUINFO_INT_REGISTER + RSP_R0: rsp->r[0] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R1: rsp->r[1] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R2: rsp->r[2] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R3: rsp->r[3] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R4: rsp->r[4] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R5: rsp->r[5] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R6: rsp->r[6] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R7: rsp->r[7] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R8: rsp->r[8] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R9: rsp->r[9] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R10: rsp->r[10] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R11: rsp->r[11] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R12: rsp->r[12] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R13: rsp->r[13] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R14: rsp->r[14] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R15: rsp->r[15] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R16: rsp->r[16] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R17: rsp->r[17] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R18: rsp->r[18] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R19: rsp->r[19] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R20: rsp->r[20] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R21: rsp->r[21] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R22: rsp->r[22] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R23: rsp->r[23] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R24: rsp->r[24] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R25: rsp->r[25] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R26: rsp->r[26] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R27: rsp->r[27] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R28: rsp->r[28] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R29: rsp->r[29] = info->i; break; case CPUINFO_INT_REGISTER + RSP_R30: rsp->r[30] = info->i; break; case CPUINFO_INT_SP: case CPUINFO_INT_REGISTER + RSP_R31: rsp->r[31] = info->i; break; case CPUINFO_INT_REGISTER + RSP_SR: rsp->sr = info->i; break; case CPUINFO_INT_REGISTER + RSP_NEXTPC: rsp->nextpc = info->i; break; case CPUINFO_INT_REGISTER + RSP_STEPCNT: rsp->step_count = info->i; break; } } CPU_GET_INFO( rsp ) { rsp_state *rsp = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; switch(state) { /* --- the following bits of info are returned as 64-bit signed integers --- */ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(rsp_state); break; case CPUINFO_INT_INPUT_LINES: info->i = 1; break; case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; case CPUINFO_INT_MAX_CYCLES: info->i = 1; break; case DEVINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; case DEVINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; case DEVINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break; case DEVINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; case DEVINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; case DEVINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break; case DEVINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; case DEVINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; case DEVINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break; case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break; case CPUINFO_INT_PREVIOUSPC: info->i = rsp->ppc; break; case CPUINFO_INT_PC: /* intentional fallthrough */ case CPUINFO_INT_REGISTER + RSP_PC: info->i = rsp->pc; break; case CPUINFO_INT_REGISTER + RSP_R0: info->i = rsp->r[0]; break; case CPUINFO_INT_REGISTER + RSP_R1: info->i = rsp->r[1]; break; case CPUINFO_INT_REGISTER + RSP_R2: info->i = rsp->r[2]; break; case CPUINFO_INT_REGISTER + RSP_R3: info->i = rsp->r[3]; break; case CPUINFO_INT_REGISTER + RSP_R4: info->i = rsp->r[4]; break; case CPUINFO_INT_REGISTER + RSP_R5: info->i = rsp->r[5]; break; case CPUINFO_INT_REGISTER + RSP_R6: info->i = rsp->r[6]; break; case CPUINFO_INT_REGISTER + RSP_R7: info->i = rsp->r[7]; break; case CPUINFO_INT_REGISTER + RSP_R8: info->i = rsp->r[8]; break; case CPUINFO_INT_REGISTER + RSP_R9: info->i = rsp->r[9]; break; case CPUINFO_INT_REGISTER + RSP_R10: info->i = rsp->r[10]; break; case CPUINFO_INT_REGISTER + RSP_R11: info->i = rsp->r[11]; break; case CPUINFO_INT_REGISTER + RSP_R12: info->i = rsp->r[12]; break; case CPUINFO_INT_REGISTER + RSP_R13: info->i = rsp->r[13]; break; case CPUINFO_INT_REGISTER + RSP_R14: info->i = rsp->r[14]; break; case CPUINFO_INT_REGISTER + RSP_R15: info->i = rsp->r[15]; break; case CPUINFO_INT_REGISTER + RSP_R16: info->i = rsp->r[16]; break; case CPUINFO_INT_REGISTER + RSP_R17: info->i = rsp->r[17]; break; case CPUINFO_INT_REGISTER + RSP_R18: info->i = rsp->r[18]; break; case CPUINFO_INT_REGISTER + RSP_R19: info->i = rsp->r[19]; break; case CPUINFO_INT_REGISTER + RSP_R20: info->i = rsp->r[20]; break; case CPUINFO_INT_REGISTER + RSP_R21: info->i = rsp->r[21]; break; case CPUINFO_INT_REGISTER + RSP_R22: info->i = rsp->r[22]; break; case CPUINFO_INT_REGISTER + RSP_R23: info->i = rsp->r[23]; break; case CPUINFO_INT_REGISTER + RSP_R24: info->i = rsp->r[24]; break; case CPUINFO_INT_REGISTER + RSP_R25: info->i = rsp->r[25]; break; case CPUINFO_INT_REGISTER + RSP_R26: info->i = rsp->r[26]; break; case CPUINFO_INT_REGISTER + RSP_R27: info->i = rsp->r[27]; break; case CPUINFO_INT_REGISTER + RSP_R28: info->i = rsp->r[28]; break; case CPUINFO_INT_REGISTER + RSP_R29: info->i = rsp->r[29]; break; case CPUINFO_INT_REGISTER + RSP_R30: info->i = rsp->r[30]; break; case CPUINFO_INT_SP: case CPUINFO_INT_REGISTER + RSP_R31: info->i = rsp->r[31]; break; case CPUINFO_INT_REGISTER + RSP_SR: info->i = rsp->sr; break; case CPUINFO_INT_REGISTER + RSP_NEXTPC: info->i = rsp->nextpc; break; case CPUINFO_INT_REGISTER + RSP_STEPCNT: info->i = rsp->step_count; break; /* --- the following bits of info are returned as pointers to data or functions --- */ case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(rsp); break; case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(rsp); break; case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(rsp); break; case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(rsp); break; case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(rsp); break; case CPUINFO_FCT_BURN: info->burn = NULL; break; case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(rsp); break; case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &rsp->icount; break; /* --- the following bits of info are returned as NULL-terminated strings --- */ case DEVINFO_STR_NAME: strcpy(info->s, "RSP"); break; case DEVINFO_STR_FAMILY: strcpy(info->s, "RSP"); break; case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; case CPUINFO_STR_REGISTER + RSP_PC: sprintf(info->s, "PC: %08X", rsp->pc); break; case CPUINFO_STR_REGISTER + RSP_R0: sprintf(info->s, "R0: %08X", rsp->r[0]); break; case CPUINFO_STR_REGISTER + RSP_R1: sprintf(info->s, "R1: %08X", rsp->r[1]); break; case CPUINFO_STR_REGISTER + RSP_R2: sprintf(info->s, "R2: %08X", rsp->r[2]); break; case CPUINFO_STR_REGISTER + RSP_R3: sprintf(info->s, "R3: %08X", rsp->r[3]); break; case CPUINFO_STR_REGISTER + RSP_R4: sprintf(info->s, "R4: %08X", rsp->r[4]); break; case CPUINFO_STR_REGISTER + RSP_R5: sprintf(info->s, "R5: %08X", rsp->r[5]); break; case CPUINFO_STR_REGISTER + RSP_R6: sprintf(info->s, "R6: %08X", rsp->r[6]); break; case CPUINFO_STR_REGISTER + RSP_R7: sprintf(info->s, "R7: %08X", rsp->r[7]); break; case CPUINFO_STR_REGISTER + RSP_R8: sprintf(info->s, "R8: %08X", rsp->r[8]); break; case CPUINFO_STR_REGISTER + RSP_R9: sprintf(info->s, "R9: %08X", rsp->r[9]); break; case CPUINFO_STR_REGISTER + RSP_R10: sprintf(info->s, "R10: %08X", rsp->r[10]); break; case CPUINFO_STR_REGISTER + RSP_R11: sprintf(info->s, "R11: %08X", rsp->r[11]); break; case CPUINFO_STR_REGISTER + RSP_R12: sprintf(info->s, "R12: %08X", rsp->r[12]); break; case CPUINFO_STR_REGISTER + RSP_R13: sprintf(info->s, "R13: %08X", rsp->r[13]); break; case CPUINFO_STR_REGISTER + RSP_R14: sprintf(info->s, "R14: %08X", rsp->r[14]); break; case CPUINFO_STR_REGISTER + RSP_R15: sprintf(info->s, "R15: %08X", rsp->r[15]); break; case CPUINFO_STR_REGISTER + RSP_R16: sprintf(info->s, "R16: %08X", rsp->r[16]); break; case CPUINFO_STR_REGISTER + RSP_R17: sprintf(info->s, "R17: %08X", rsp->r[17]); break; case CPUINFO_STR_REGISTER + RSP_R18: sprintf(info->s, "R18: %08X", rsp->r[18]); break; case CPUINFO_STR_REGISTER + RSP_R19: sprintf(info->s, "R19: %08X", rsp->r[19]); break; case CPUINFO_STR_REGISTER + RSP_R20: sprintf(info->s, "R20: %08X", rsp->r[20]); break; case CPUINFO_STR_REGISTER + RSP_R21: sprintf(info->s, "R21: %08X", rsp->r[21]); break; case CPUINFO_STR_REGISTER + RSP_R22: sprintf(info->s, "R22: %08X", rsp->r[22]); break; case CPUINFO_STR_REGISTER + RSP_R23: sprintf(info->s, "R23: %08X", rsp->r[23]); break; case CPUINFO_STR_REGISTER + RSP_R24: sprintf(info->s, "R24: %08X", rsp->r[24]); break; case CPUINFO_STR_REGISTER + RSP_R25: sprintf(info->s, "R25: %08X", rsp->r[25]); break; case CPUINFO_STR_REGISTER + RSP_R26: sprintf(info->s, "R26: %08X", rsp->r[26]); break; case CPUINFO_STR_REGISTER + RSP_R27: sprintf(info->s, "R27: %08X", rsp->r[27]); break; case CPUINFO_STR_REGISTER + RSP_R28: sprintf(info->s, "R28: %08X", rsp->r[28]); break; case CPUINFO_STR_REGISTER + RSP_R29: sprintf(info->s, "R29: %08X", rsp->r[29]); break; case CPUINFO_STR_REGISTER + RSP_R30: sprintf(info->s, "R30: %08X", rsp->r[30]); break; case CPUINFO_STR_REGISTER + RSP_R31: sprintf(info->s, "R31: %08X", rsp->r[31]); break; case CPUINFO_STR_REGISTER + RSP_SR: sprintf(info->s, "SR: %08X", rsp->sr); break; case CPUINFO_STR_REGISTER + RSP_NEXTPC: sprintf(info->s, "NPC: %08X", rsp->nextpc);break; case CPUINFO_STR_REGISTER + RSP_STEPCNT: sprintf(info->s, "STEP: %d", rsp->step_count); break; } } DEFINE_LEGACY_CPU_DEVICE(RSP, rsp); #endif // USE_RSPDRC