diff options
author | 2007-12-17 15:19:59 +0000 | |
---|---|---|
committer | 2007-12-17 15:19:59 +0000 | |
commit | 7b77f1218624ea26dbb2efd85a19f795f5d4e02e (patch) | |
tree | 19209304095572b4fd61c2a2d6a5aa75c4e471ad /src/emu/cpu/x86drc.c | |
parent | 3da7f476068b3ffef713218ba2fc1bd5030f2c38 (diff) |
Initial checkin of MAME 0.121.mame0121
Diffstat (limited to 'src/emu/cpu/x86drc.c')
-rw-r--r-- | src/emu/cpu/x86drc.c | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/src/emu/cpu/x86drc.c b/src/emu/cpu/x86drc.c new file mode 100644 index 00000000000..5092ee70d5c --- /dev/null +++ b/src/emu/cpu/x86drc.c @@ -0,0 +1,767 @@ +/*************************************************************************** + + x86drc.c + + x86 Dynamic recompiler support routines. + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "cpuintrf.h" +#include "x86drc.h" +#include "debugger.h" + +#define LOG_DISPATCHES 0 +#define BREAK_ON_MODIFIED_CODE 0 + + + + +static UINT16 fp_control[4] = { 0x023f, 0x063f, 0x0a3f, 0x0e3f }; +static UINT32 sse_control[4] = { 0x9fc0, 0xbfc0, 0xdfc0, 0xffc0 }; + + +static void append_entry_point(drc_core *drc); +static void append_recompile(drc_core *drc); +static void append_flush(drc_core *drc); +static void append_out_of_cycles(drc_core *drc); + +#if LOG_DISPATCHES +static void log_dispatch(drc_core *drc); +#endif + + + +/*************************************************************************** + EXTERNAL INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + drc_init - initialize the DRC core +-------------------------------------------------*/ + +drc_core *drc_init(UINT8 cpunum, drc_config *config) +{ + int address_bits = config->address_bits; + int effective_address_bits = address_bits - config->lsbs_to_ignore; + UINT8 cache_allocated = FALSE; + drc_core *drc = NULL; + + /* allocate memory */ + if (config->cache_base == NULL) + { + config->cache_base = osd_alloc_executable(config->cache_size); + if (config->cache_base == NULL) + goto error; + cache_allocated = TRUE; + } + + /* the drc structure lives at the start of the cache */ + drc = (drc_core *)config->cache_base; + memset(drc, 0, sizeof(*drc)); + + /* copy in relevant data from the config */ + drc->pcptr = config->pcptr; + drc->icountptr = config->icountptr; + drc->esiptr = config->esiptr; + drc->cb_reset = config->cb_reset; + drc->cb_recompile = config->cb_recompile; + drc->cb_entrygen = config->cb_entrygen; + drc->uses_fp = config->uses_fp; + drc->uses_sse = config->uses_sse; + drc->pc_in_memory = config->pc_in_memory; + drc->icount_in_memory = config->icount_in_memory; + drc->fpcw_curr = fp_control[0]; + drc->mxcsr_curr = sse_control[0]; + + /* configure cache */ + drc->cache_base = (UINT8 *)config->cache_base + sizeof(*drc); + drc->cache_size = config->cache_size - sizeof(*drc); + drc->cache_end = drc->cache_base + drc->cache_size; + drc->cache_danger = drc->cache_end - 65536; + drc->cache_allocated = cache_allocated; + + /* compute shifts and masks */ + drc->l1bits = effective_address_bits/2; + drc->l2bits = effective_address_bits - drc->l1bits; + drc->l1shift = config->lsbs_to_ignore + drc->l2bits; + drc->l2mask = ((1 << drc->l2bits) - 1) << config->lsbs_to_ignore; + drc->l2scale = 4 >> config->lsbs_to_ignore; + + /* allocate lookup tables */ + drc->lookup_l1 = malloc(sizeof(*drc->lookup_l1) * (1 << drc->l1bits)); + drc->lookup_l2_recompile = malloc(sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); + if (drc->lookup_l1 == NULL || drc->lookup_l2_recompile == NULL) + goto error; + memset(drc->lookup_l1, 0, sizeof(*drc->lookup_l1) * (1 << drc->l1bits)); + memset(drc->lookup_l2_recompile, 0, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); + + /* allocate the sequence and tentative lists */ + drc->sequence_count_max = config->max_instructions; + drc->sequence_list = malloc(drc->sequence_count_max * sizeof(*drc->sequence_list)); + if (drc->sequence_list == NULL) + goto error; + + drc->tentative_count_max = config->max_instructions; + drc->tentative_list = malloc(drc->tentative_count_max * sizeof(*drc->tentative_list)); + if (!drc->tentative_list) + return NULL; + + return drc; + +error: + if (drc != NULL) + drc_exit(drc); + return NULL; +} + + +/*------------------------------------------------- + drc_alloc - allocate memory from the top of + the DRC cache +-------------------------------------------------*/ + +void *drc_alloc(drc_core *drc, size_t amount) +{ + /* if we don't have enough space, reset the cache */ + if (drc->cache_top >= drc->cache_danger - amount) + drc_cache_reset(drc); + + /* if we still don't have enough space, fail */ + if (drc->cache_top >= drc->cache_danger - amount) + return NULL; + + /* adjust the end and danger values downward */ + drc->cache_end -= amount; + drc->cache_danger -= amount; + return drc->cache_end; +} + + +/*------------------------------------------------- + drc_cache_reset - reset the DRC cache +-------------------------------------------------*/ + +void drc_cache_reset(drc_core *drc) +{ + int i; + + /* reset the cache and add the basics */ + drc->cache_top = drc->cache_base; + + /* append the core entry points to the fresh cache */ + drc->entry_point = (void (*)(void))(UINT32)drc->cache_top; + append_entry_point(drc); + drc->out_of_cycles = drc->cache_top; + append_out_of_cycles(drc); + + /* append an INT 3 before the recompile so that BREAK_ON_MODIFIED_CODE works */ + emit_int_3(DRCTOP); + drc->recompile = drc->cache_top; + append_recompile(drc); + drc->dispatch = drc->cache_top; + drc_append_dispatcher(drc); + drc->flush = drc->cache_top; + append_flush(drc); + + /* populate the recompile table */ + for (i = 0; i < (1 << drc->l2bits); i++) + drc->lookup_l2_recompile[i] = drc->recompile; + + /* reset all the l1 tables */ + for (i = 0; i < (1 << drc->l1bits); i++) + { + /* point NULL entries to the generic recompile table */ + if (drc->lookup_l1[i] == NULL) + drc->lookup_l1[i] = drc->lookup_l2_recompile; + + /* reset allocated tables to point all entries back to the recompiler */ + else if (drc->lookup_l1[i] != drc->lookup_l2_recompile) + memcpy(drc->lookup_l1[i], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); + } + + /* call back to the host */ + if (drc->cb_reset) + (*drc->cb_reset)(drc); +} + + +/*------------------------------------------------------------------ + drc_execute +------------------------------------------------------------------*/ + +void drc_execute(drc_core *drc) +{ + (*drc->entry_point)(); +} + + +/*------------------------------------------------------------------ + drc_exit +------------------------------------------------------------------*/ + +void drc_exit(drc_core *drc) +{ + int i; + + /* free all the l2 tables allocated */ + for (i = 0; i < (1 << drc->l1bits); i++) + if (drc->lookup_l1[i] != drc->lookup_l2_recompile) + free(drc->lookup_l1[i]); + + /* free the l1 table */ + if (drc->lookup_l1) + free(drc->lookup_l1); + + /* free the default l2 table */ + if (drc->lookup_l2_recompile) + free(drc->lookup_l2_recompile); + + /* free the lists */ + if (drc->sequence_list) + free(drc->sequence_list); + if (drc->tentative_list) + free(drc->tentative_list); + + /* and the drc itself */ + if (drc->cache_allocated) + osd_free_executable(drc, drc->cache_size + sizeof(*drc)); +} + + +/*------------------------------------------------------------------ + drc_begin_sequence +------------------------------------------------------------------*/ + +void drc_begin_sequence(drc_core *drc, UINT32 pc) +{ + UINT32 l1index = pc >> drc->l1shift; + UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / 4; + + /* reset the sequence and tentative counts */ + drc->sequence_count = 0; + drc->tentative_count = 0; + + /* allocate memory if necessary */ + if (drc->lookup_l1[l1index] == drc->lookup_l2_recompile) + { + /* create a new copy of the recompile table */ + drc->lookup_l1[l1index] = malloc_or_die(sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); + + memcpy(drc->lookup_l1[l1index], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); + } + + /* nuke any previous link to this instruction */ + if (drc->lookup_l1[l1index][l2index] != drc->recompile) + { + UINT8 *cache_save = drc->cache_top; + drc->cache_top = drc->lookup_l1[l1index][l2index]; + emit_jmp(DRCTOP, drc->dispatch); + drc->cache_top = cache_save; + } + + /* note the current location for this instruction */ + drc->lookup_l1[l1index][l2index] = drc->cache_top; +} + + +/*------------------------------------------------------------------ + drc_end_sequence +------------------------------------------------------------------*/ + +void drc_end_sequence(drc_core *drc) +{ + int i, j; + + /* fix up any internal links */ + for (i = 0; i < drc->tentative_count; i++) + for (j = 0; j < drc->sequence_count; j++) + if (drc->tentative_list[i].pc == drc->sequence_list[j].pc) + { + UINT8 *cache_save = drc->cache_top; + drc->cache_top = drc->tentative_list[i].target; + emit_jmp(DRCTOP, drc->sequence_list[j].target); + drc->cache_top = cache_save; + break; + } +} + + +/*------------------------------------------------------------------ + drc_register_code_at_cache_top +------------------------------------------------------------------*/ + +void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc) +{ + pc_ptr_pair *pair = &drc->sequence_list[drc->sequence_count++]; + assert_always(drc->sequence_count <= drc->sequence_count_max, "drc_register_code_at_cache_top: too many instructions!"); + + pair->target = drc->cache_top; + pair->pc = pc; +} + + +/*------------------------------------------------------------------ + drc_get_code_at_pc +------------------------------------------------------------------*/ + +void *drc_get_code_at_pc(drc_core *drc, UINT32 pc) +{ + UINT32 l1index = pc >> drc->l1shift; + UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / 4; + return (drc->lookup_l1[l1index][l2index] != drc->recompile) ? drc->lookup_l1[l1index][l2index] : NULL; +} + + +/*------------------------------------------------------------------ + drc_append_verify_code +------------------------------------------------------------------*/ + +void drc_append_verify_code(drc_core *drc, void *code, UINT8 length) +{ +#if BREAK_ON_MODIFIED_CODE + x86code *recompile = drc->recompile - 1; +#else + x86code *recompile = drc->recompile; +#endif + + if (length > 8) + { + UINT32 *codeptr = code, sum = 0; + void *target; + int i; + + for (i = 0; i < length / 4; i++) + { + sum = (sum >> 1) | (sum << 31); + sum += *codeptr++; + } + + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + emit_mov_r32_imm(DRCTOP, REG_EBX, (FPTR)code); // mov ebx,code + emit_mov_r32_imm(DRCTOP, REG_ECX, length / 4); // mov ecx,length / 4 + target = drc->cache_top; // target: + emit_ror_r32_imm(DRCTOP, REG_EAX, 1); // ror eax,1 + emit_add_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, 0)); // add eax,[ebx] + emit_sub_r32_imm(DRCTOP, REG_ECX, 1); // sub ecx,1 + emit_lea_r32_m32(DRCTOP, REG_EBX, MBD(REG_EBX, 4)); // lea ebx,[ebx+4] + emit_jcc(DRCTOP, COND_NZ, target); // jnz target + emit_cmp_r32_imm(DRCTOP, REG_EAX, sum); // cmp eax,sum + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + } + else if (length >= 12) + { + emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 4), ((UINT32 *)code)[1]); // cmp [pc+4],opcode+4 + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 8), ((UINT32 *)code)[2]); // cmp [pc+8],opcode+8 + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + } + else if (length >= 8) + { + emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 4), ((UINT32 *)code)[1]); // cmp [pc+4],opcode+4 + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + } + else if (length >= 4) + { + emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + } + else if (length >= 2) + { + emit_cmp_m16_imm(DRCTOP, MABS(code), *(UINT16 *)code); // cmp [pc],opcode + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + } + else + { + emit_cmp_m8_imm(DRCTOP, MABS(code), *(UINT8 *)code); // cmp [pc],opcode + emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile + } +} + + +/*------------------------------------------------------------------ + drc_append_call_debugger +------------------------------------------------------------------*/ + +void drc_append_call_debugger(drc_core *drc) +{ +#ifdef MAME_DEBUG + if (Machine->debug_mode) + { + emit_link link; + emit_cmp_m32_imm(DRCTOP, MABS(&Machine->debug_mode), 0); // cmp [Machine->debug_mode],0 + emit_jcc_short_link(DRCTOP, COND_E, &link); // je skip + emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // align stack + drc_append_save_call_restore(drc, (x86code *)mame_debug_hook, 12); // save volatiles + resolve_link(DRCTOP, &link); + } +#endif +} + + +/*------------------------------------------------------------------ + drc_append_save_volatiles +------------------------------------------------------------------*/ + +void drc_append_save_volatiles(drc_core *drc) +{ + if (drc->icountptr && !drc->icount_in_memory) + emit_mov_m32_r32(DRCTOP, MABS(drc->icountptr), REG_EBP); + if (drc->pcptr && !drc->pc_in_memory) + emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI); + if (drc->esiptr) + emit_mov_m32_r32(DRCTOP, MABS(drc->esiptr), REG_ESI); +} + + +/*------------------------------------------------------------------ + drc_append_restore_volatiles +------------------------------------------------------------------*/ + +void drc_append_restore_volatiles(drc_core *drc) +{ + if (drc->icountptr && !drc->icount_in_memory) + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(drc->icountptr)); + if (drc->pcptr && !drc->pc_in_memory) + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(drc->pcptr)); + if (drc->esiptr) + emit_mov_r32_m32(DRCTOP, REG_ESI, MABS(drc->esiptr)); +} + + +/*------------------------------------------------------------------ + drc_append_save_call_restore +------------------------------------------------------------------*/ + +void drc_append_save_call_restore(drc_core *drc, x86code *target, UINT32 stackadj) +{ + drc_append_save_volatiles(drc); // save volatiles + emit_call(DRCTOP, target); // call target + drc_append_restore_volatiles(drc); // restore volatiles + if (stackadj) + emit_add_r32_imm(DRCTOP, REG_ESP, stackadj); // adjust stack +} + + +/*------------------------------------------------------------------ + drc_append_standard_epilogue +------------------------------------------------------------------*/ + +void drc_append_standard_epilogue(drc_core *drc, INT32 cycles, INT32 pcdelta, int allow_exit) +{ + if (pcdelta != 0 && drc->pc_in_memory) + emit_add_m32_imm(DRCTOP, MABS(drc->pcptr), pcdelta); // add [pc],pcdelta + if (cycles != 0) + { + if (drc->icount_in_memory) + emit_sub_m32_imm(DRCTOP, MABS(drc->icountptr), cycles); // sub [icount],cycles + else + emit_sub_r32_imm(DRCTOP, REG_EBP, cycles); // sub ebp,cycles + } + if (pcdelta != 0 && !drc->pc_in_memory) + emit_lea_r32_m32(DRCTOP, REG_EDI, MBD(REG_EDI, pcdelta)); // lea edi,[edi+pcdelta] + if (allow_exit && cycles != 0) + emit_jcc(DRCTOP, COND_S, drc->out_of_cycles); // js out_of_cycles +} + + +/*------------------------------------------------------------------ + drc_append_dispatcher +------------------------------------------------------------------*/ + +void drc_append_dispatcher(drc_core *drc) +{ +#if LOG_DISPATCHES + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack + emit_push_imm(DRCTOP, drc); // push drc + drc_append_save_call_restore(drc, (x86code *)log_dispatch, 12); // call log_dispatch +#endif + if (drc->pc_in_memory) + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(drc->pcptr)); // mov edi,[pc] + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi + emit_shr_r32_imm(DRCTOP, REG_EAX, drc->l1shift); // shr eax,l1shift + emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EDI); // mov edx,edi + emit_mov_r32_m32(DRCTOP, REG_EAX, MISD(REG_EAX, 4, (FPTR)drc->lookup_l1)); // mov eax,[eax*4 + l1lookup] + emit_and_r32_imm(DRCTOP, REG_EDX, drc->l2mask); // and edx,l2mask + emit_jmp_m32(DRCTOP, MBISD(REG_EAX, REG_EDX, drc->l2scale, 0)); // jmp [eax+edx*l2scale] +} + + +/*------------------------------------------------------------------ + drc_append_fixed_dispatcher +------------------------------------------------------------------*/ + +void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc) +{ + x86code **base = drc->lookup_l1[newpc >> drc->l1shift]; + if (base == drc->lookup_l2_recompile) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&drc->lookup_l1[newpc >> drc->l1shift])); + // mov eax,[(newpc >> l1shift)*4 + l1lookup] + emit_jmp_m32(DRCTOP, MBD(REG_EAX, (newpc & drc->l2mask) * drc->l2scale)); + // jmp [eax+(newpc & l2mask)*l2scale] + } + else + emit_jmp_m32(DRCTOP, MABS((UINT8 *)base + (newpc & drc->l2mask) * drc->l2scale)); + // jmp [eax+(newpc & l2mask)*l2scale] +} + + +/*------------------------------------------------------------------ + drc_append_tentative_fixed_dispatcher +------------------------------------------------------------------*/ + +void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc) +{ + pc_ptr_pair *pair = &drc->tentative_list[drc->tentative_count++]; + assert_always(drc->tentative_count <= drc->tentative_count_max, "drc_append_tentative_fixed_dispatcher: too many tentative branches!"); + + pair->target = drc->cache_top; + pair->pc = newpc; + drc_append_fixed_dispatcher(drc, newpc); +} + + +/*------------------------------------------------------------------ + drc_append_set_fp_rounding +------------------------------------------------------------------*/ + +void drc_append_set_fp_rounding(drc_core *drc, UINT8 regindex) +{ + emit_fldcw_m16(DRCTOP, MISD(regindex, 2, (INT32)&fp_control[0])); // fldcw [fp_control + reg*2] + emit_fstcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fnstcw [fpcw_curr] +} + + + +/*------------------------------------------------------------------ + drc_append_set_temp_fp_rounding +------------------------------------------------------------------*/ + +void drc_append_set_temp_fp_rounding(drc_core *drc, UINT8 rounding) +{ + emit_fldcw_m16(DRCTOP, MABS(&fp_control[rounding])); // fldcw [fp_control] +} + + + +/*------------------------------------------------------------------ + drc_append_restore_fp_rounding +------------------------------------------------------------------*/ + +void drc_append_restore_fp_rounding(drc_core *drc) +{ + emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fldcw [fpcw_curr] +} + + + +/*------------------------------------------------------------------ + drc_append_set_sse_rounding +------------------------------------------------------------------*/ + +void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex) +{ + emit_ldmxcsr_m32(DRCTOP, MISD(regindex, 4, (INT32)&sse_control[0])); // ldmxcsr [sse_control + reg*2] + emit_stmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // stmxcsr [mxcsr_curr] +} + + + +/*------------------------------------------------------------------ + drc_append_set_temp_sse_rounding +------------------------------------------------------------------*/ + +void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding) +{ + emit_ldmxcsr_m32(DRCTOP, MABS(&sse_control[rounding])); // ldmxcsr [sse_control] +} + + + +/*------------------------------------------------------------------ + drc_append_restore_sse_rounding +------------------------------------------------------------------*/ + +void drc_append_restore_sse_rounding(drc_core *drc) +{ + emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr] +} + + + +/*------------------------------------------------------------------ + drc_dasm + + An attempt to make a disassembler for DRC code; currently limited + by the functionality of DasmI386 +------------------------------------------------------------------*/ + +void drc_dasm(FILE *f, const void *begin, const void *end) +{ + extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode); + + char buffer[256]; + const UINT8 *begin_ptr = (const UINT8 *) begin; + const UINT8 *end_ptr = (const UINT8 *) end; + UINT32 pc = (UINT32) begin; + int length; + + while(begin_ptr < end_ptr) + { +#if defined(MAME_DEBUG) && HAS_I386 + length = i386_dasm_one(buffer, pc, (UINT8 *) begin_ptr, 32) & DASMFLAG_LENGTHMASK; +#else + sprintf(buffer, "%02X", *begin_ptr); + length = 1; +#endif + + fprintf(f, "%08X:\t%s\n", (unsigned) pc, buffer); + begin_ptr += length; + pc += length; + } +} + + + + +/*************************************************************************** + INTERNAL CODEGEN +***************************************************************************/ + +/*------------------------------------------------------------------ + append_entry_point +------------------------------------------------------------------*/ + +static void append_entry_point(drc_core *drc) +{ + emit_pushad(DRCTOP); // pushad + if (drc->uses_fp) + { + emit_fstcw_m16(DRCTOP, MABS(&drc->fpcw_save)); // fstcw [fpcw_save] + emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fldcw [fpcw_curr] + } + if (drc->uses_sse) + { + emit_stmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_save)); // stmxcsr [mxcsr_save] + emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr] + } + drc_append_restore_volatiles(drc); // load volatiles + if (drc->cb_entrygen) + (*drc->cb_entrygen)(drc); // additional entry point duties + drc_append_dispatcher(drc); // dispatch +} + + +/*------------------------------------------------------------------ + recompile_code +------------------------------------------------------------------*/ + +static void recompile_code(drc_core *drc) +{ + if (drc->cache_top >= drc->cache_danger) + drc_cache_reset(drc); + (*drc->cb_recompile)(drc); +} + + +/*------------------------------------------------------------------ + append_recompile +------------------------------------------------------------------*/ + +static void append_recompile(drc_core *drc) +{ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack + emit_push_imm(DRCTOP, (FPTR)drc); // push drc + drc_append_save_call_restore(drc, (x86code *)recompile_code, 12); // call recompile_code + drc_append_dispatcher(drc); // dispatch +} + + +/*------------------------------------------------------------------ + append_flush +------------------------------------------------------------------*/ + +static void append_flush(drc_core *drc) +{ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack + emit_push_imm(DRCTOP, (FPTR)drc); // push drc + drc_append_save_call_restore(drc, (x86code *)drc_cache_reset, 12); // call drc_cache_reset + drc_append_dispatcher(drc); // dispatch +} + + +/*------------------------------------------------------------------ + append_out_of_cycles +------------------------------------------------------------------*/ + +static void append_out_of_cycles(drc_core *drc) +{ + drc_append_save_volatiles(drc); // save volatiles + if (drc->uses_fp) + { + emit_fclex(DRCTOP); // fnclex + emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_save)); // fldcw [fpcw_save] + } + if (drc->uses_sse) + emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_save)); // ldmxcsr [mxcsr_save] + emit_popad(DRCTOP); // popad + emit_ret(DRCTOP); // ret +} + + + +/*------------------------------------------------------------------ + drc_x86_get_features() +------------------------------------------------------------------*/ +UINT32 drc_x86_get_features(void) +{ + UINT32 features = 0; +#ifdef _MSC_VER + __asm + { + mov eax, 1 + xor ebx, ebx + xor ecx, ecx + xor edx, edx + __asm _emit 0Fh __asm _emit 0A2h // cpuid + mov features, edx + } +#else /* !_MSC_VER */ + __asm__ + ( + "pushl %%ebx ; " + "movl $1,%%eax ; " + "xorl %%ebx,%%ebx ; " + "xorl %%ecx,%%ecx ; " + "xorl %%edx,%%edx ; " + "cpuid ; " + "movl %%edx,%0 ; " + "popl %%ebx ; " + : "=&a" (features) /* result has to go in eax */ + : /* no inputs */ + : "%ecx", "%edx" /* clobbers ebx, ecx and edx */ + ); +#endif /* MSC_VER */ + return features; +} + + + +/*------------------------------------------------------------------ + log_dispatch +------------------------------------------------------------------*/ + +#if LOG_DISPATCHES +static void log_dispatch(drc_core *drc) +{ + if (input_code_pressed(KEYCODE_D)) + logerror("Disp:%08X\n", *drc->pcptr); +} +#endif |