summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/x86drc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/x86drc.c')
-rw-r--r--src/emu/cpu/x86drc.c767
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