mirror of
https://github.com/holub/mame
synced 2025-04-26 02:07:14 +03:00
Added back-end validation mechanism, and a handful of tests as examples.
This will be expanded in the future. Added two new opcodes: SAVE and RESTORE to save and restore the entire virtual machine state for examination/setup. Added new back-end function get_info() which returns information from the back-end about how many actual registers will be mapped. Fixed a bug that mapped the high a low parts of registers to the same address. This should help the C back-end run better on big-endian architectures.
This commit is contained in:
parent
383c7daf62
commit
969a705508
@ -154,6 +154,7 @@ union _drcbec_instruction
|
||||
float * pfloat;
|
||||
double * pdouble;
|
||||
void (*cfunc)(void *);
|
||||
drcuml_machine_state *state;
|
||||
const drcuml_codehandle *handle;
|
||||
const drcbec_instruction *inst;
|
||||
const drcbec_instruction **pinst;
|
||||
@ -172,6 +173,7 @@ static void drcbec_reset(drcbe_state *drcbe);
|
||||
static int drcbec_execute(drcbe_state *state, drcuml_codehandle *entry);
|
||||
static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
|
||||
static int drcbec_hash_exists(drcbe_state *state, UINT32 mode, UINT32 pc);
|
||||
static void drcbec_get_info(drcbe_state *state, drcbe_info *info);
|
||||
|
||||
/* private helper functions */
|
||||
static void output_parameter(drcbe_state *drcbe, drcbec_instruction **dstptr, void **immedptr, int size, const drcuml_parameter *param);
|
||||
@ -236,7 +238,8 @@ const drcbe_interface drcbe_c_be_interface =
|
||||
drcbec_reset,
|
||||
drcbec_execute,
|
||||
drcbec_generate,
|
||||
drcbec_hash_exists
|
||||
drcbec_hash_exists,
|
||||
drcbec_get_info
|
||||
};
|
||||
|
||||
|
||||
@ -460,6 +463,18 @@ static int drcbec_hash_exists(drcbe_state *state, UINT32 mode, UINT32 pc)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbec_get_info - return information about
|
||||
the back-end implementation
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void drcbec_get_info(drcbe_state *state, drcbe_info *info)
|
||||
{
|
||||
info->direct_iregs = 0;
|
||||
info->direct_fregs = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
BACK-END EXECUTION
|
||||
@ -513,7 +528,7 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
if (newinst == NULL)
|
||||
{
|
||||
assert(sp < ARRAY_LENGTH(callstack));
|
||||
drcbe->state.exp.l = PARAM1;
|
||||
drcbe->state.exp = PARAM1;
|
||||
newinst = (const drcbec_instruction *)drcuml_handle_codeptr(inst[2].handle);
|
||||
callstack[sp++] = inst;
|
||||
}
|
||||
@ -574,7 +589,7 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
assert(sp < ARRAY_LENGTH(callstack));
|
||||
newinst = (const drcbec_instruction *)drcuml_handle_codeptr(inst[0].handle);
|
||||
assert_in_cache(drcbe->cache, newinst);
|
||||
drcbe->state.exp.l = PARAM1;
|
||||
drcbe->state.exp = PARAM1;
|
||||
callstack[sp++] = inst;
|
||||
inst = newinst;
|
||||
continue;
|
||||
@ -605,7 +620,17 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
break;
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_GETEXP, 4, 0): /* GETEXP dst */
|
||||
PARAM0 = drcbe->state.exp.l;
|
||||
PARAM0 = drcbe->state.exp;
|
||||
break;
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_SAVE, 4, 0): /* SAVE dst */
|
||||
*inst[0].state = drcbe->state;
|
||||
inst[0].state->flags = flags;
|
||||
break;
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_RESTORE, 4, 0): /* RESTORE dst */
|
||||
drcbe->state = *inst[0].state;
|
||||
flags = inst[0].state->flags;
|
||||
break;
|
||||
|
||||
|
||||
@ -736,7 +761,10 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_ADDC, 4, 1):
|
||||
temp32 = PARAM1 + PARAM2 + (flags & DRCUML_FLAG_C);
|
||||
flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2);
|
||||
if (PARAM2 + 1 != 0)
|
||||
flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2 + (flags & DRCUML_FLAG_C));
|
||||
else
|
||||
flags = FLAGS32_NZCV_ADD(temp32, PARAM1 + (flags & DRCUML_FLAG_C), PARAM2);
|
||||
PARAM0 = temp32;
|
||||
break;
|
||||
|
||||
@ -756,7 +784,10 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_SUBB, 4, 1):
|
||||
temp32 = PARAM1 - PARAM2 - (flags & DRCUML_FLAG_C);
|
||||
flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2);
|
||||
if (PARAM2 + 1 != 0)
|
||||
flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2 + (flags & DRCUML_FLAG_C));
|
||||
else
|
||||
flags = FLAGS32_NZCV_SUB(temp32, PARAM1 - (flags & DRCUML_FLAG_C), PARAM2);
|
||||
PARAM0 = temp32;
|
||||
break;
|
||||
|
||||
@ -1136,7 +1167,10 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_ADDC, 8, 1):
|
||||
temp64 = DPARAM1 + DPARAM2 + (flags & DRCUML_FLAG_C);
|
||||
flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2);
|
||||
if (DPARAM2 + 1 != 0)
|
||||
flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2 + (flags & DRCUML_FLAG_C));
|
||||
else
|
||||
flags = FLAGS64_NZCV_ADD(temp64, DPARAM1 + (flags & DRCUML_FLAG_C), DPARAM2);
|
||||
DPARAM0 = temp64;
|
||||
break;
|
||||
|
||||
@ -1156,7 +1190,10 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
|
||||
case MAKE_OPCODE_SHORT(DRCUML_OP_SUBB, 8, 1):
|
||||
temp64 = DPARAM1 - DPARAM2 - (flags & DRCUML_FLAG_C);
|
||||
flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2);
|
||||
if (DPARAM2 + 1 != 0)
|
||||
flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2 + (flags & DRCUML_FLAG_C));
|
||||
else
|
||||
flags = FLAGS64_NZCV_SUB(temp64, DPARAM1 - (flags & DRCUML_FLAG_C), DPARAM2);
|
||||
DPARAM0 = temp64;
|
||||
break;
|
||||
|
||||
@ -1682,7 +1719,7 @@ static void output_parameter(drcbe_state *drcbe, drcbec_instruction **dstptr, vo
|
||||
/* int registers point to the appropriate part of the integer register state */
|
||||
case DRCUML_PTYPE_INT_REGISTER:
|
||||
if (size == 4)
|
||||
(dst++)->puint32 = &drcbe->state.r[param->value - DRCUML_REG_I0].l;
|
||||
(dst++)->puint32 = &drcbe->state.r[param->value - DRCUML_REG_I0].w.l;
|
||||
else
|
||||
(dst++)->puint64 = &drcbe->state.r[param->value - DRCUML_REG_I0].d;
|
||||
break;
|
||||
@ -1690,7 +1727,7 @@ static void output_parameter(drcbe_state *drcbe, drcbec_instruction **dstptr, vo
|
||||
/* float registers point to the appropriate part of the floating point register state */
|
||||
case DRCUML_PTYPE_FLOAT_REGISTER:
|
||||
if (size == 4)
|
||||
(dst++)->pfloat = &drcbe->state.f[param->value - DRCUML_REG_F0].l;
|
||||
(dst++)->pfloat = &drcbe->state.f[param->value - DRCUML_REG_F0].s.l;
|
||||
else
|
||||
(dst++)->pdouble = &drcbe->state.f[param->value - DRCUML_REG_F0].d;
|
||||
break;
|
||||
|
@ -57,43 +57,6 @@ struct _drchash_state
|
||||
};
|
||||
|
||||
|
||||
/* an integer register, with low/high parts */
|
||||
typedef union _drcuml_ireg drcuml_ireg;
|
||||
union _drcuml_ireg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
UINT32 l,h; /* 32-bit low, high parts of the register */
|
||||
#else
|
||||
UINT32 h,l; /* 32-bit low, high parts of the register */
|
||||
#endif
|
||||
UINT64 d; /* 64-bit full register */
|
||||
};
|
||||
|
||||
|
||||
/* an floating-point register, with low/high parts */
|
||||
typedef union _drcuml_freg drcuml_freg;
|
||||
union _drcuml_freg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
float l,unused; /* 32-bit low, high parts of the register */
|
||||
#else
|
||||
float unused,l; /* 32-bit low, high parts of the register */
|
||||
#endif
|
||||
double d; /* 64-bit full register */
|
||||
};
|
||||
|
||||
|
||||
/* the collected machine state of a system */
|
||||
typedef struct _drcuml_machine_state drcuml_machine_state;
|
||||
struct _drcuml_machine_state
|
||||
{
|
||||
drcuml_ireg r[DRCUML_REG_I_END - DRCUML_REG_I0]; /* integer registers */
|
||||
drcuml_freg f[DRCUML_REG_F_END - DRCUML_REG_F0]; /* floating-point registers */
|
||||
drcuml_ireg exp; /* exception parameter register */
|
||||
UINT8 fmod; /* fmod (floating-point mode) register */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
|
@ -171,6 +171,7 @@
|
||||
#undef REG_SP
|
||||
#include "x86log.h"
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
|
||||
@ -277,6 +278,7 @@ struct _drcbe_state
|
||||
|
||||
UINT8 * rbpvalue; /* value of RBP */
|
||||
UINT8 flagsmap[0x1000]; /* flags map */
|
||||
UINT64 flagsunmap[0x20]; /* flags unmapper */
|
||||
|
||||
x86log_context * log; /* logging */
|
||||
};
|
||||
@ -294,6 +296,7 @@ static void drcbex64_reset(drcbe_state *drcbe);
|
||||
static int drcbex64_execute(drcbe_state *drcbe, drcuml_codehandle *entry);
|
||||
static void drcbex64_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
|
||||
static int drcbex64_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc);
|
||||
static void drcbex64_get_info(drcbe_state *state, drcbe_info *info);
|
||||
|
||||
/* private helper functions */
|
||||
static void fixup_label(void *parameter, drccodeptr labelcodeptr);
|
||||
@ -312,7 +315,8 @@ const drcbe_interface drcbe_x64_be_interface =
|
||||
drcbex64_reset,
|
||||
drcbex64_execute,
|
||||
drcbex64_generate,
|
||||
drcbex64_hash_exists
|
||||
drcbex64_hash_exists,
|
||||
drcbex64_get_info
|
||||
};
|
||||
|
||||
/* opcode table */
|
||||
@ -391,6 +395,8 @@ static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instru
|
||||
static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
|
||||
static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
@ -503,6 +509,8 @@ static const opcode_table_entry opcode_table_source[] =
|
||||
{ DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */
|
||||
{ DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */
|
||||
{ DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */
|
||||
{ DRCUML_OP_SAVE, op_save }, /* SAVE dst,index */
|
||||
{ DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst,index */
|
||||
|
||||
/* Integer Operations */
|
||||
{ DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */
|
||||
@ -775,6 +783,16 @@ static drcbe_state *drcbex64_alloc(drcuml_state *drcuml, drccache *cache, UINT32
|
||||
if (entry & 0x800) flags |= DRCUML_FLAG_V;
|
||||
drcbe->flagsmap[entry] = flags;
|
||||
}
|
||||
for (entry = 0; entry < ARRAY_LENGTH(drcbe->flagsunmap); entry++)
|
||||
{
|
||||
UINT64 flags = 0;
|
||||
if (entry & DRCUML_FLAG_C) flags |= 0x001;
|
||||
if (entry & DRCUML_FLAG_U) flags |= 0x004;
|
||||
if (entry & DRCUML_FLAG_Z) flags |= 0x040;
|
||||
if (entry & DRCUML_FLAG_S) flags |= 0x080;
|
||||
if (entry & DRCUML_FLAG_V) flags |= 0x800;
|
||||
drcbe->flagsunmap[entry] = flags;
|
||||
}
|
||||
|
||||
/* create the log */
|
||||
if (flags & DRCUML_OPTION_LOG_NATIVE)
|
||||
@ -884,6 +902,18 @@ static void drcbex64_reset(drcbe_state *drcbe)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbex64_execute - execute a block of code
|
||||
referenced by the given handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int drcbex64_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
{
|
||||
/* call our entry point which will jump to the destination */
|
||||
return (*drcbe->entry)(drcbe->rbpvalue, (x86code *)drcuml_handle_codeptr(entry));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbex64_generate - generate code
|
||||
-------------------------------------------------*/
|
||||
@ -968,14 +998,18 @@ static int drcbex64_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc)
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbec_execute - execute a block of code
|
||||
registered at the given mode/pc
|
||||
drcbex64_get_info - return information about
|
||||
the back-end implementation
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int drcbex64_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
static void drcbex64_get_info(drcbe_state *state, drcbe_info *info)
|
||||
{
|
||||
/* call our entry point which will jump to the destination */
|
||||
return (*drcbe->entry)(drcbe->rbpvalue, (x86code *)drcuml_handle_codeptr(entry));
|
||||
for (info->direct_iregs = 0; info->direct_iregs < DRCUML_REG_I_END - DRCUML_REG_I0; info->direct_iregs++)
|
||||
if (int_register_map[info->direct_iregs] == 0)
|
||||
break;
|
||||
for (info->direct_fregs = 0; info->direct_fregs < DRCUML_REG_F_END - DRCUML_REG_F0; info->direct_fregs++)
|
||||
if (float_register_map[info->direct_fregs] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -2992,7 +3026,7 @@ static x86code *op_handle(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
|
||||
drcuml_handle_set_codeptr((drcuml_codehandle *)(FPTR)inst->param[0].value, dst);
|
||||
|
||||
/* by default, the handle points to prolog code that moves the stack pointer */
|
||||
emit_sub_r64_imm(&dst, REG_RSP, 40); // sub rsp,40
|
||||
emit_lea_r64_m64(&dst, REG_RSP, MBD(REG_RSP, -40)); // lea rsp,[rsp-40]
|
||||
return dst;
|
||||
}
|
||||
|
||||
@ -3195,7 +3229,7 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
|
||||
}
|
||||
|
||||
/* in all cases, if there is no code, we return here to generate the exception */
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp.l), &pcp); // mov [exp],param
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp), &pcp); // mov [exp],param
|
||||
emit_sub_r64_imm(&dst, REG_RSP, 8); // sub rsp,8
|
||||
emit_call_m64(&dst, MABS(drcbe, exp.value)); // call [exp]
|
||||
|
||||
@ -3254,7 +3288,7 @@ static x86code *op_exh(drcbe_state *drcbe, x86code *dst, const drcuml_instructio
|
||||
/* perform the exception processing inline if unconditional */
|
||||
if (inst->condflags == DRCUML_COND_ALWAYS)
|
||||
{
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp.l), &exp); // mov [exp],exp
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp), &exp); // mov [exp],exp
|
||||
if (*targetptr != NULL)
|
||||
emit_call(&dst, *targetptr); // call *targetptr
|
||||
else
|
||||
@ -3326,7 +3360,7 @@ static x86code *op_ret(drcbe_state *drcbe, x86code *dst, const drcuml_instructio
|
||||
emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
|
||||
|
||||
/* return */
|
||||
emit_add_r64_imm(&dst, REG_RSP, 40); // add rsp,40
|
||||
emit_lea_r64_m64(&dst, REG_RSP, MBD(REG_RSP, 40)); // lea rsp,[rsp+40]
|
||||
emit_ret(&dst); // ret
|
||||
|
||||
/* resolve the conditional link */
|
||||
@ -3482,10 +3516,10 @@ static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
|
||||
|
||||
/* fetch the exception parameter and store to the destination */
|
||||
if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
|
||||
emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe, &drcbe->state.exp.l)); // mov reg,[exp]
|
||||
emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe, &drcbe->state.exp)); // mov reg,[exp]
|
||||
else
|
||||
{
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(drcbe, &drcbe->state.exp.l)); // mov eax,[exp]
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(drcbe, &drcbe->state.exp)); // mov eax,[exp]
|
||||
emit_mov_m32_r32(&dst, MABS(drcbe, dstp.value), REG_EAX); // mov [dstp],eax
|
||||
}
|
||||
|
||||
@ -3493,6 +3527,128 @@ static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
op_save - process a SAVE opcode
|
||||
-------------------------------------------------*/
|
||||
|
||||
static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
|
||||
{
|
||||
drcuml_parameter dstp;
|
||||
int regnum;
|
||||
|
||||
/* validate instruction */
|
||||
assert(inst->size == 4);
|
||||
assert(inst->condflags == DRCUML_COND_ALWAYS);
|
||||
|
||||
/* normalize parameters */
|
||||
param_normalize_1(drcbe, inst, &dstp, PTYPE_M);
|
||||
|
||||
/* copy live state to the destination */
|
||||
emit_mov_r64_imm(&dst, REG_RCX, dstp.value); // mov rcx,dstp
|
||||
|
||||
/* copy flags */
|
||||
emit_pushf(&dst); // pushf
|
||||
emit_pop_r64(&dst, REG_RAX); // pop rax
|
||||
emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5
|
||||
emit_mov_r8_m8(&dst, REG_AL, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsmap[0])));
|
||||
// mov al,[flags_map]
|
||||
emit_mov_m8_r8(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, flags)), REG_AL); // mov state->flags,al
|
||||
|
||||
/* copy fmod and exp */
|
||||
emit_mov_r8_m8(&dst, REG_AL, MABS(drcbe, &drcbe->state.fmod)); // mov al,[fmod]
|
||||
emit_mov_m8_r8(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, fmod)), REG_AL); // mov state->fmod,al
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(drcbe, &drcbe->state.exp)); // mov eax,[exp]
|
||||
emit_mov_m32_r32(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, exp)), REG_EAX); // mov state->exp,eax
|
||||
|
||||
/* copy integer registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.r); regnum++)
|
||||
{
|
||||
if (int_register_map[regnum] != 0)
|
||||
emit_mov_m64_r64(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, r[regnum].d)), int_register_map[regnum]);
|
||||
else
|
||||
{
|
||||
emit_mov_r64_m64(&dst, REG_RAX, MABS(drcbe, &drcbe->state.r[regnum].d));
|
||||
emit_mov_m64_r64(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, r[regnum].d)), REG_RAX);
|
||||
}
|
||||
}
|
||||
|
||||
/* copy FP registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.f); regnum++)
|
||||
{
|
||||
if (float_register_map[regnum] != 0)
|
||||
emit_movsd_m64_r128(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, f[regnum].d)), float_register_map[regnum]);
|
||||
else
|
||||
{
|
||||
emit_mov_r64_m64(&dst, REG_RAX, MABS(drcbe, &drcbe->state.f[regnum].d));
|
||||
emit_mov_m64_r64(&dst, MBD(REG_RCX, offsetof(drcuml_machine_state, f[regnum].d)), REG_RAX);
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
op_restore - process a RESTORE opcode
|
||||
-------------------------------------------------*/
|
||||
|
||||
static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
|
||||
{
|
||||
drcuml_parameter dstp;
|
||||
int regnum;
|
||||
|
||||
/* validate instruction */
|
||||
assert(inst->size == 4);
|
||||
assert(inst->condflags == DRCUML_COND_ALWAYS);
|
||||
|
||||
/* normalize parameters */
|
||||
param_normalize_1(drcbe, inst, &dstp, PTYPE_M);
|
||||
|
||||
/* copy live state from the destination */
|
||||
emit_mov_r64_imm(&dst, REG_ECX, dstp.value); // mov rcx,dstp
|
||||
|
||||
/* copy integer registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.r); regnum++)
|
||||
{
|
||||
if (int_register_map[regnum] != 0)
|
||||
emit_mov_r64_m64(&dst, int_register_map[regnum], MBD(REG_RCX, offsetof(drcuml_machine_state, r[regnum].d)));
|
||||
else
|
||||
{
|
||||
emit_mov_r64_m64(&dst, REG_RAX, MBD(REG_RCX, offsetof(drcuml_machine_state, r[regnum].d)));
|
||||
emit_mov_m64_r64(&dst, MABS(drcbe, &drcbe->state.r[regnum].d), REG_RAX);
|
||||
}
|
||||
}
|
||||
|
||||
/* copy FP registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.f); regnum++)
|
||||
{
|
||||
if (float_register_map[regnum] != 0)
|
||||
emit_movsd_r128_m64(&dst, float_register_map[regnum], MBD(REG_RCX, offsetof(drcuml_machine_state, f[regnum].d)));
|
||||
else
|
||||
{
|
||||
emit_mov_r64_m64(&dst, REG_RAX, MBD(REG_RCX, offsetof(drcuml_machine_state, f[regnum].d)));
|
||||
emit_mov_m64_r64(&dst, MABS(drcbe, &drcbe->state.f[regnum].d), REG_RAX);
|
||||
}
|
||||
}
|
||||
|
||||
/* copy fmod and exp */
|
||||
emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_RCX, offsetof(drcuml_machine_state, fmod)));// movzx eax,state->fmod
|
||||
emit_and_r32_imm(&dst, REG_EAX, 3); // and eax,3
|
||||
emit_mov_m8_r8(&dst, MABS(drcbe, &drcbe->state.fmod), REG_AL); // mov [fmod],al
|
||||
emit_ldmxcsr_m32(&dst, MBISD(REG_RBP, REG_RAX, 4, offset_from_rbp(drcbe, (FPTR)&drcbe->ssecontrol[0])));
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_RCX, offsetof(drcuml_machine_state, exp))); // mov eax,state->exp
|
||||
emit_mov_m32_r32(&dst, MABS(drcbe, &drcbe->state.exp), REG_EAX); // mov [exp],eax
|
||||
|
||||
/* copy flags */
|
||||
emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_RCX, offsetof(drcuml_machine_state, flags)));// movzx eax,state->flags
|
||||
emit_push_m64(&dst, MBISD(REG_RBP, REG_RAX, 8, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsunmap[0])));
|
||||
// push flags_unmap[eax*8]
|
||||
emit_popf(&dst); // popf
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INTEGER OPERATIONS
|
||||
@ -5043,7 +5199,7 @@ static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instructio
|
||||
{
|
||||
/* dstp == src1p in memory */
|
||||
if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
|
||||
emit_add_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // add [dstp],src2p
|
||||
emit_add_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // add [dstp],src2p
|
||||
|
||||
/* reg = reg + imm */
|
||||
else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
|
||||
|
@ -81,6 +81,7 @@
|
||||
#undef REG_SP
|
||||
#include "x86log.h"
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
|
||||
@ -180,6 +181,7 @@ static void drcbex86_reset(drcbe_state *drcbe);
|
||||
static int drcbex86_execute(drcbe_state *drcbe, drcuml_codehandle *entry);
|
||||
static void drcbex86_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
|
||||
static int drcbex86_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc);
|
||||
static void drcbex86_get_info(drcbe_state *state, drcbe_info *info);
|
||||
|
||||
/* private helper functions */
|
||||
static void fixup_label(void *parameter, drccodeptr labelcodeptr);
|
||||
@ -204,7 +206,8 @@ const drcbe_interface drcbe_x86_be_interface =
|
||||
drcbex86_reset,
|
||||
drcbex86_execute,
|
||||
drcbex86_generate,
|
||||
drcbex86_hash_exists
|
||||
drcbex86_hash_exists,
|
||||
drcbex86_get_info
|
||||
};
|
||||
|
||||
/* opcode table */
|
||||
@ -221,6 +224,7 @@ static UINT8 int_register_map[DRCUML_REG_I_END - DRCUML_REG_I0] =
|
||||
|
||||
/* flags mapping tables */
|
||||
static UINT8 flags_map[0x1000];
|
||||
static UINT32 flags_unmap[0x20];
|
||||
|
||||
/* condition mapping table */
|
||||
static UINT8 condition_map[DRCUML_COND_MAX - DRCUML_COND_Z] =
|
||||
@ -277,6 +281,8 @@ static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instru
|
||||
static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
|
||||
static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
|
||||
@ -389,6 +395,8 @@ static const opcode_table_entry opcode_table_source[] =
|
||||
{ DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */
|
||||
{ DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */
|
||||
{ DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */
|
||||
{ DRCUML_OP_SAVE, op_save }, /* SAVE dst,index */
|
||||
{ DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst,index */
|
||||
|
||||
/* Integer Operations */
|
||||
{ DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */
|
||||
@ -590,13 +598,23 @@ static drcbe_state *drcbex86_alloc(drcuml_state *drcuml, drccache *cache, UINT32
|
||||
if (entry & 0x800) flags |= DRCUML_FLAG_V;
|
||||
flags_map[entry] = flags;
|
||||
}
|
||||
for (entry = 0; entry < ARRAY_LENGTH(flags_unmap); entry++)
|
||||
{
|
||||
UINT32 flags = 0;
|
||||
if (entry & DRCUML_FLAG_C) flags |= 0x001;
|
||||
if (entry & DRCUML_FLAG_U) flags |= 0x004;
|
||||
if (entry & DRCUML_FLAG_Z) flags |= 0x040;
|
||||
if (entry & DRCUML_FLAG_S) flags |= 0x080;
|
||||
if (entry & DRCUML_FLAG_V) flags |= 0x800;
|
||||
flags_unmap[entry] = flags;
|
||||
}
|
||||
|
||||
/* compute hi pointers for each register */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(int_register_map); regnum++)
|
||||
if (int_register_map[regnum] != 0)
|
||||
{
|
||||
drcbe->reglo[int_register_map[regnum]] = &drcbe->state.r[regnum].l;
|
||||
drcbe->reghi[int_register_map[regnum]] = &drcbe->state.r[regnum].h;
|
||||
drcbe->reglo[int_register_map[regnum]] = &drcbe->state.r[regnum].w.l;
|
||||
drcbe->reghi[int_register_map[regnum]] = &drcbe->state.r[regnum].w.h;
|
||||
}
|
||||
|
||||
/* create the log */
|
||||
@ -691,6 +709,18 @@ static void drcbex86_reset(drcbe_state *drcbe)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbex86_execute - execute a block of code
|
||||
referenced by the given handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int drcbex86_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
{
|
||||
/* call our entry point which will jump to the destination */
|
||||
return (*drcbe->entry)((x86code *)drcuml_handle_codeptr(entry));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbex86_generate - generate code
|
||||
-------------------------------------------------*/
|
||||
@ -775,14 +805,16 @@ static int drcbex86_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc)
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcbec_execute - execute a block of code
|
||||
registered at the given mode/pc
|
||||
drcbex86_get_info - return information about
|
||||
the back-end implementation
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int drcbex86_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
|
||||
static void drcbex86_get_info(drcbe_state *state, drcbe_info *info)
|
||||
{
|
||||
/* call our entry point which will jump to the destination */
|
||||
return (*drcbe->entry)((x86code *)drcuml_handle_codeptr(entry));
|
||||
for (info->direct_iregs = 0; info->direct_iregs < DRCUML_REG_I_END - DRCUML_REG_I0; info->direct_iregs++)
|
||||
if (int_register_map[info->direct_iregs] == 0)
|
||||
break;
|
||||
info->direct_fregs = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -3248,7 +3280,7 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
|
||||
}
|
||||
|
||||
/* in all cases, if there is no code, we return here to generate the exception */
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp.l), &pcp); // mov [exp],param
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp), &pcp); // mov [exp],param
|
||||
emit_sub_r32_imm(&dst, REG_ESP, 4); // sub esp,4
|
||||
emit_call_m32(&dst, MABS(exp.value)); // call [exp]
|
||||
|
||||
@ -3305,7 +3337,7 @@ static x86code *op_exh(drcbe_state *drcbe, x86code *dst, const drcuml_instructio
|
||||
/* perform the exception processing inline if unconditional */
|
||||
if (inst->condflags == DRCUML_COND_ALWAYS)
|
||||
{
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp.l), &exp); // mov [exp],exp
|
||||
emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp), &exp); // mov [exp],exp
|
||||
if (*targetptr != NULL)
|
||||
emit_call(&dst, *targetptr); // call *targetptr
|
||||
else
|
||||
@ -3534,10 +3566,10 @@ static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
|
||||
|
||||
/* fetch the exception parameter and store to the destination */
|
||||
if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
|
||||
emit_mov_r32_m32(&dst, dstp.value, MABS(&drcbe->state.exp.l)); // mov reg,[exp]
|
||||
emit_mov_r32_m32(&dst, dstp.value, MABS(&drcbe->state.exp)); // mov reg,[exp]
|
||||
else
|
||||
{
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.exp.l)); // mov eax,[exp]
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.exp)); // mov eax,[exp]
|
||||
emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax
|
||||
}
|
||||
|
||||
@ -3545,6 +3577,124 @@ static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
op_save - process a SAVE opcode
|
||||
-------------------------------------------------*/
|
||||
|
||||
static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
|
||||
{
|
||||
drcuml_parameter dstp;
|
||||
int regnum;
|
||||
|
||||
/* validate instruction */
|
||||
assert(inst->size == 4);
|
||||
assert(inst->condflags == DRCUML_COND_ALWAYS);
|
||||
|
||||
/* normalize parameters */
|
||||
param_normalize_1(drcbe, inst, &dstp, PTYPE_M);
|
||||
|
||||
/* copy live state to the destination */
|
||||
emit_mov_r32_imm(&dst, REG_ECX, dstp.value); // mov ecx,dstp
|
||||
|
||||
/* copy flags */
|
||||
emit_pushf(&dst); // pushf
|
||||
emit_pop_r32(&dst, REG_EAX); // pop eax
|
||||
emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5
|
||||
emit_mov_r8_m8(&dst, REG_AL, MBD(REG_EAX, flags_map)); // mov al,[flags_map]
|
||||
emit_mov_m8_r8(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, flags)), REG_AL); // mov state->flags,al
|
||||
|
||||
/* copy fmod and exp */
|
||||
emit_mov_r8_m8(&dst, REG_AL, MABS(&drcbe->state.fmod)); // mov al,[fmod]
|
||||
emit_mov_m8_r8(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, fmod)), REG_AL); // mov state->fmod,al
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.exp)); // mov eax,[exp]
|
||||
emit_mov_m32_r32(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, exp)), REG_EAX); // mov state->exp,eax
|
||||
|
||||
/* copy integer registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.r); regnum++)
|
||||
{
|
||||
if (int_register_map[regnum] != 0)
|
||||
emit_mov_m32_r32(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, r[regnum].w.l)), int_register_map[regnum]);
|
||||
else
|
||||
{
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.r[regnum].w.l));
|
||||
emit_mov_m32_r32(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, r[regnum].w.l)), REG_EAX);
|
||||
}
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.r[regnum].w.h));
|
||||
emit_mov_m32_r32(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, r[regnum].w.h)), REG_EAX);
|
||||
}
|
||||
|
||||
/* copy FP registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.f); regnum++)
|
||||
{
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.f[regnum].s.l));
|
||||
emit_mov_m32_r32(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, f[regnum].s.l)), REG_EAX);
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.f[regnum].s.h));
|
||||
emit_mov_m32_r32(&dst, MBD(REG_ECX, offsetof(drcuml_machine_state, f[regnum].s.h)), REG_EAX);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
op_restore - process a RESTORE opcode
|
||||
-------------------------------------------------*/
|
||||
|
||||
static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
|
||||
{
|
||||
drcuml_parameter dstp;
|
||||
int regnum;
|
||||
|
||||
/* validate instruction */
|
||||
assert(inst->size == 4);
|
||||
assert(inst->condflags == DRCUML_COND_ALWAYS);
|
||||
|
||||
/* normalize parameters */
|
||||
param_normalize_1(drcbe, inst, &dstp, PTYPE_M);
|
||||
|
||||
/* copy live state from the destination */
|
||||
emit_mov_r32_imm(&dst, REG_ECX, dstp.value); // mov ecx,dstp
|
||||
|
||||
/* copy integer registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.r); regnum++)
|
||||
{
|
||||
if (int_register_map[regnum] != 0)
|
||||
emit_mov_r32_m32(&dst, int_register_map[regnum], MBD(REG_ECX, offsetof(drcuml_machine_state, r[regnum].w.l)));
|
||||
else
|
||||
{
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, r[regnum].w.l)));
|
||||
emit_mov_m32_r32(&dst, MABS(&drcbe->state.r[regnum].w.l), REG_EAX);
|
||||
}
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, r[regnum].w.h)));
|
||||
emit_mov_m32_r32(&dst, MABS(&drcbe->state.r[regnum].w.h), REG_EAX);
|
||||
}
|
||||
|
||||
/* copy FP registers */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(drcbe->state.f); regnum++)
|
||||
{
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, f[regnum].s.l)));
|
||||
emit_mov_m32_r32(&dst, MABS(&drcbe->state.f[regnum].s.l), REG_EAX);
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, f[regnum].s.h)));
|
||||
emit_mov_m32_r32(&dst, MABS(&drcbe->state.f[regnum].s.h), REG_EAX);
|
||||
}
|
||||
|
||||
/* copy fmod and exp */
|
||||
emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, fmod)));// movzx eax,state->fmod
|
||||
emit_and_r32_imm(&dst, REG_EAX, 3); // and eax,3
|
||||
emit_mov_m8_r8(&dst, MABS(&drcbe->state.fmod), REG_AL); // mov [fmod],al
|
||||
emit_fldcw_m16(&dst, MISD(REG_EAX, 2, &fp_control[0])); // fldcw fp_control[eax]
|
||||
emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, exp))); // mov eax,state->exp
|
||||
emit_mov_m32_r32(&dst, MABS(&drcbe->state.exp), REG_EAX); // mov [exp],eax
|
||||
|
||||
/* copy flags */
|
||||
emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, flags)));// movzx eax,state->flags
|
||||
emit_push_m32(&dst, MISD(REG_EAX, 4, flags_unmap)); // push flags_unmap[eax*4]
|
||||
emit_popf(&dst); // popf
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INTEGER OPERATIONS
|
||||
|
@ -32,10 +32,6 @@
|
||||
- RECALL handle
|
||||
change code at caller to call handle in the future
|
||||
|
||||
* Add interface for getting hints from the backend:
|
||||
- number of direct-mapped integer registers
|
||||
- number of direct-mapped floating point registers
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "drcuml.h"
|
||||
@ -47,6 +43,14 @@
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
DEBUGGING
|
||||
***************************************************************************/
|
||||
|
||||
#define VALIDATE_BACKEND (0)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
@ -54,21 +58,40 @@
|
||||
/* opcode validation condition/flag valid bitmasks */
|
||||
#define OV_CONDFLAG_NONE 0x00
|
||||
#define OV_CONDFLAG_COND 0x80
|
||||
#define OV_CONDFLAG_SZ (DRCUML_FLAG_S | DRCUML_FLAG_Z)
|
||||
#define OV_CONDFLAG_SZC (DRCUML_FLAG_S | DRCUML_FLAG_Z | DRCUML_FLAG_C)
|
||||
#define OV_CONDFLAG_SZVC (DRCUML_FLAG_S | DRCUML_FLAG_Z | DRCUML_FLAG_V | DRCUML_FLAG_C)
|
||||
#define OV_CONDFLAG_UZC (DRCUML_FLAG_U | DRCUML_FLAG_Z | DRCUML_FLAG_C)
|
||||
#define OV_CONDFLAG_FLAGS 0x1f
|
||||
|
||||
/* opcode validation parameter valid bitmasks */
|
||||
/* bitmasks of valid parameter types and flags */
|
||||
#define OV_PARAM_ALLOWED_NONE (1 << DRCUML_PTYPE_NONE)
|
||||
#define OV_PARAM_ALLOWED_IMM (1 << DRCUML_PTYPE_IMMEDIATE)
|
||||
#define OV_PARAM_ALLOWED_IREG (1 << DRCUML_PTYPE_INT_REGISTER)
|
||||
#define OV_PARAM_ALLOWED_FREG (1 << DRCUML_PTYPE_FLOAT_REGISTER)
|
||||
#define OV_PARAM_ALLOWED_MVAR (1 << DRCUML_PTYPE_MAPVAR)
|
||||
#define OV_PARAM_ALLOWED_MEM (1 << DRCUML_PTYPE_MEMORY)
|
||||
#define OV_PARAM_ALLOWED_NCMEM (OV_PARAM_ALLOWED_MEM | 0x80)
|
||||
#define OV_PARAM_FLAG_ANYMEM 0x100
|
||||
#define OV_PARAM_FLAG_FIXED4 0x200
|
||||
#define OV_PARAM_FLAG_FIXED8 0x400
|
||||
|
||||
/* opcode validation parameter valid bitmasks */
|
||||
#define OV_PARAM_ALLOWED_ANYMEM (OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_ANYMEM)
|
||||
#define OV_PARAM_ALLOWED_IMV (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR)
|
||||
#define OV_PARAM_ALLOWED_IMV4 (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR | OV_PARAM_FLAG_FIXED4)
|
||||
#define OV_PARAM_ALLOWED_IMV8 (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR | OV_PARAM_FLAG_FIXED8)
|
||||
#define OV_PARAM_ALLOWED_IRM (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM)
|
||||
#define OV_PARAM_ALLOWED_IRM4 (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED4)
|
||||
#define OV_PARAM_ALLOWED_IRM8 (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED8)
|
||||
#define OV_PARAM_ALLOWED_FRM (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM)
|
||||
#define OV_PARAM_ALLOWED_FRM4 (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED4)
|
||||
#define OV_PARAM_ALLOWED_FRM8 (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM | OV_PARAM_FLAG_FIXED8)
|
||||
#define OV_PARAM_ALLOWED_IANY (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV)
|
||||
#define OV_PARAM_ALLOWED_IANY4 (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV | OV_PARAM_FLAG_FIXED4)
|
||||
#define OV_PARAM_ALLOWED_IANY8 (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV | OV_PARAM_FLAG_FIXED8)
|
||||
#define OV_PARAM_ALLOWED_FANY (OV_PARAM_ALLOWED_FRM)
|
||||
#define OV_PARAM_ALLOWED_FANY4 (OV_PARAM_ALLOWED_FRM | OV_PARAM_FLAG_FIXED4)
|
||||
#define OV_PARAM_ALLOWED_FANY8 (OV_PARAM_ALLOWED_FRM | OV_PARAM_FLAG_FIXED8)
|
||||
|
||||
|
||||
|
||||
@ -121,10 +144,20 @@ struct _drcuml_opcode_valid
|
||||
drcuml_opcode opcode; /* the opcode itself */
|
||||
UINT8 sizes; /* allowed sizes */
|
||||
UINT8 condflags; /* allowed conditions/flags */
|
||||
UINT8 p0types; /* allowed types for parameter 0 */
|
||||
UINT8 p1types; /* allowed types for parameter 1 */
|
||||
UINT8 p2types; /* allowed types for parameter 2 */
|
||||
UINT8 p3types; /* allowed types for parameter 3 */
|
||||
UINT16 ptypes[4]; /* allowed types for parameters */
|
||||
};
|
||||
|
||||
|
||||
/* structure describing back-end validation test */
|
||||
typedef struct _bevalidate_test bevalidate_test;
|
||||
struct _bevalidate_test
|
||||
{
|
||||
drcuml_opcode opcode;
|
||||
UINT8 size;
|
||||
UINT8 destmask;
|
||||
UINT8 iflags;
|
||||
UINT8 flags;
|
||||
UINT64 param[4];
|
||||
};
|
||||
|
||||
|
||||
@ -134,11 +167,11 @@ struct _drcuml_opcode_valid
|
||||
***************************************************************************/
|
||||
|
||||
/* macro to simplify the table */
|
||||
#define OPVALID_ENTRY_0(op,sizes,condflag) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_1(op,sizes,condflag,p0) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_2(op,sizes,condflag,p0,p1) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_3(op,sizes,condflag,p0,p1,p2) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_4(op,sizes,condflag,p0,p1,p2,p3) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_##p3 },
|
||||
#define OPVALID_ENTRY_0(op,sizes,condflag) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE } },
|
||||
#define OPVALID_ENTRY_1(op,sizes,condflag,p0) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE } },
|
||||
#define OPVALID_ENTRY_2(op,sizes,condflag,p0,p1) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE } },
|
||||
#define OPVALID_ENTRY_3(op,sizes,condflag,p0,p1,p2) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_NONE } },
|
||||
#define OPVALID_ENTRY_4(op,sizes,condflag,p0,p1,p2,p3) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, { OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_##p3 } },
|
||||
|
||||
/* opcode validation table */
|
||||
static const drcuml_opcode_valid opcode_valid_list[] =
|
||||
@ -147,7 +180,7 @@ static const drcuml_opcode_valid opcode_valid_list[] =
|
||||
OPVALID_ENTRY_1(HANDLE, 4, NONE, MEM)
|
||||
OPVALID_ENTRY_2(HASH, 4, NONE, IMV, IMV)
|
||||
OPVALID_ENTRY_1(LABEL, 4, NONE, IMV)
|
||||
OPVALID_ENTRY_1(COMMENT, 4, NONE, NCMEM)
|
||||
OPVALID_ENTRY_1(COMMENT, 4, NONE, ANYMEM)
|
||||
OPVALID_ENTRY_2(MAPVAR, 4, NONE, MVAR, IMV)
|
||||
|
||||
/* Control Flow Operations */
|
||||
@ -159,102 +192,104 @@ static const drcuml_opcode_valid opcode_valid_list[] =
|
||||
OPVALID_ENTRY_2(EXH, 4, COND, MEM, IANY)
|
||||
OPVALID_ENTRY_1(CALLH, 4, COND, MEM)
|
||||
OPVALID_ENTRY_0(RET, 4, COND)
|
||||
OPVALID_ENTRY_2(CALLC, 4, COND, NCMEM,NCMEM)
|
||||
OPVALID_ENTRY_2(CALLC, 4, COND, ANYMEM,ANYMEM)
|
||||
OPVALID_ENTRY_2(RECOVER, 4, NONE, IRM, MVAR)
|
||||
|
||||
/* Internal Register Operations */
|
||||
OPVALID_ENTRY_1(SETFMOD, 4, NONE, IANY)
|
||||
OPVALID_ENTRY_1(GETFMOD, 4, NONE, IRM)
|
||||
OPVALID_ENTRY_1(GETEXP, 4, NONE, IRM)
|
||||
OPVALID_ENTRY_1(SAVE, 4, NONE, ANYMEM)
|
||||
OPVALID_ENTRY_1(RESTORE, 4, NONE, ANYMEM)
|
||||
|
||||
/* Integer Operations */
|
||||
OPVALID_ENTRY_3(LOAD1U, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD1S, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD2U, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD2S, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD4U, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD4S, 8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD8U, 8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(STORE1, 4|8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(STORE2, 4|8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(STORE4, 4|8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(STORE8, 8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(READ1U, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ1S, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ2U, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ2S, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_4(READ2M, 4|8, NONE, IRM, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(READ4U, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ4S, 8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_4(READ4M, 4|8, NONE, IRM, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(READ8U, 8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_4(READ8M, 8, NONE, IRM, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE1, 4|8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE2, 4|8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_4(WRIT2M, 4|8, NONE, IMV, IANY, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE4, 4|8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_4(WRIT4M, 4|8, NONE, IMV, IANY, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE8, 8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_4(WRIT8M, 8, NONE, IMV, IANY, IANY, IANY)
|
||||
OPVALID_ENTRY_3(FLAGS, 4|8, NONE, IRM, IMV, MEM)
|
||||
OPVALID_ENTRY_2(MOV, 4|8, COND, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT1, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT2, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT4, 8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(SEXT1, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(SEXT2, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(SEXT4, 8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_3(ADD, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ADDC, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SUB, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SUBB, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_2(CMP, 4|8, FLAGS, IANY, IANY)
|
||||
OPVALID_ENTRY_4(MULU, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(MULS, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(DIVU, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(DIVS, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(AND, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_2(TEST, 4|8, FLAGS, IANY, IANY)
|
||||
OPVALID_ENTRY_3(OR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(XOR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SHL, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SHR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SAR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROL, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROLC, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(RORC, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(LOAD1U, 4|8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(LOAD1S, 4|8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(LOAD2U, 4|8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(LOAD2S, 4|8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(LOAD4U, 4|8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(LOAD4S, 8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(LOAD8U, 8, NONE, IRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(STORE1, 4|8, NONE, ANYMEM,IANY4, IANY)
|
||||
OPVALID_ENTRY_3(STORE2, 4|8, NONE, ANYMEM,IANY4, IANY)
|
||||
OPVALID_ENTRY_3(STORE4, 4|8, NONE, ANYMEM,IANY4, IANY)
|
||||
OPVALID_ENTRY_3(STORE8, 8, NONE, ANYMEM,IANY4, IANY)
|
||||
OPVALID_ENTRY_3(READ1U, 4|8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_3(READ1S, 4|8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_3(READ2U, 4|8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_3(READ2S, 4|8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_4(READ2M, 4|8, NONE, IRM, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_3(READ4U, 4|8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_3(READ4S, 8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_4(READ4M, 4|8, NONE, IRM, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_3(READ8U, 8, NONE, IRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_4(READ8M, 8, NONE, IRM, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_3(WRITE1, 4|8, NONE, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_3(WRITE2, 4|8, NONE, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_4(WRIT2M, 4|8, NONE, IMV4, IANY4, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE4, 4|8, NONE, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_4(WRIT4M, 4|8, NONE, IMV4, IANY4, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE8, 8, NONE, IMV4, IANY4, IANY)
|
||||
OPVALID_ENTRY_4(WRIT8M, 8, NONE, IMV4, IANY4, IANY, IANY)
|
||||
OPVALID_ENTRY_3(FLAGS, 4|8, NONE, IRM, IMV, MEM)
|
||||
OPVALID_ENTRY_2(MOV, 4|8, COND, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT1, 4|8, NONE, IRM, IANY4)
|
||||
OPVALID_ENTRY_2(ZEXT2, 4|8, NONE, IRM, IANY4)
|
||||
OPVALID_ENTRY_2(ZEXT4, 8, NONE, IRM, IANY4)
|
||||
OPVALID_ENTRY_2(SEXT1, 4|8, NONE, IRM, IANY4)
|
||||
OPVALID_ENTRY_2(SEXT2, 4|8, NONE, IRM, IANY4)
|
||||
OPVALID_ENTRY_2(SEXT4, 8, NONE, IRM, IANY4)
|
||||
OPVALID_ENTRY_3(ADD, 4|8, SZVC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ADDC, 4|8, SZVC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SUB, 4|8, SZVC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SUBB, 4|8, SZVC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_2(CMP, 4|8, SZVC, IANY, IANY)
|
||||
OPVALID_ENTRY_4(MULU, 4|8, SZ, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(MULS, 4|8, SZ, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(DIVU, 4|8, SZ, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(DIVS, 4|8, SZ, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(AND, 4|8, SZ, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_2(TEST, 4|8, SZ, IANY, IANY)
|
||||
OPVALID_ENTRY_3(OR, 4|8, SZ, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(XOR, 4|8, SZ, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SHL, 4|8, SZC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SHR, 4|8, SZC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SAR, 4|8, SZC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROL, 4|8, SZC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROLC, 4|8, SZC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROR, 4|8, SZC, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(RORC, 4|8, SZC, IRM, IANY, IANY)
|
||||
|
||||
/* Floating Point Operations */
|
||||
OPVALID_ENTRY_3(FLOAD, 4|8, NONE, FRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(FSTORE, 4|8, NONE, NCMEM,IANY, FANY)
|
||||
OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IMV, IANY, FANY)
|
||||
OPVALID_ENTRY_2(FMOV, 4|8, COND, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4T, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4R, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4F, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4C, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8T, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8R, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8F, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8C, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FFRFS, 8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FFRFD, 4 , NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FFRI4, 4|8, NONE, FRM, IANY)
|
||||
OPVALID_ENTRY_2(FFRI8, 4|8, NONE, FRM, IANY)
|
||||
OPVALID_ENTRY_3(FADD, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FSUB, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_2(FCMP, 4|8, FLAGS, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FMUL, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FDIV, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_2(FNEG, 4|8, FLAGS, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FABS, 4|8, FLAGS, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FSQRT, 4|8, FLAGS, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FRECIP, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FRSQRT, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_3(FLOAD, 4|8, NONE, FRM, ANYMEM,IANY4)
|
||||
OPVALID_ENTRY_3(FSTORE, 4|8, NONE, ANYMEM,IANY4, FANY)
|
||||
OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IMV4, IANY4)
|
||||
OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IMV4, IANY4, FANY)
|
||||
OPVALID_ENTRY_2(FMOV, 4|8, COND, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4, 4|8, NONE, IRM4, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4T, 4|8, NONE, IRM4, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4R, 4|8, NONE, IRM4, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4F, 4|8, NONE, IRM4, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4C, 4|8, NONE, IRM4, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8, 4|8, NONE, IRM8, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8T, 4|8, NONE, IRM8, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8R, 4|8, NONE, IRM8, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8F, 4|8, NONE, IRM8, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8C, 4|8, NONE, IRM8, FANY)
|
||||
OPVALID_ENTRY_2(FFRFS, 8, NONE, FRM, FANY4)
|
||||
OPVALID_ENTRY_2(FFRFD, 4 , NONE, FRM, FANY8)
|
||||
OPVALID_ENTRY_2(FFRI4, 4|8, NONE, FRM, IANY4)
|
||||
OPVALID_ENTRY_2(FFRI8, 4|8, NONE, FRM, IANY8)
|
||||
OPVALID_ENTRY_3(FADD, 4|8, NONE, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FSUB, 4|8, NONE, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_2(FCMP, 4|8, UZC, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FMUL, 4|8, NONE, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FDIV, 4|8, NONE, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_2(FNEG, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FABS, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FSQRT, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FRECIP, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FRSQRT, 4|8, NONE, FRM, FANY)
|
||||
};
|
||||
|
||||
|
||||
@ -282,11 +317,53 @@ static drcuml_opcode_valid opcode_valid_table[DRCUML_OP_MAX];
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
static void validate_instruction(drcuml_block *block, const drcuml_instruction *inst);
|
||||
#else
|
||||
#define validate_instruction(block, inst) do { } while (0)
|
||||
#endif
|
||||
static void validate_backend(drcuml_state *drcuml);
|
||||
static void bevalidate_iterate_over_params(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist, int pnum);
|
||||
static void bevalidate_iterate_over_flags(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist);
|
||||
static void bevalidate_execute(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, const drcuml_parameter *paramlist, UINT8 flagmask);
|
||||
static void bevalidate_initialize_random_state(drcuml_block *block, drcuml_machine_state *state);
|
||||
static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *paramlist, drcuml_parameter *params, UINT64 *parammem);
|
||||
static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *params, const drcuml_instruction *testinst, drccodeptr codestart, drccodeptr codeend, UINT8 flagmask);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
size_for_param - given a set of parameter
|
||||
flags and the instruction size, return the
|
||||
size of the parameter
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE int size_for_param(int instsize, UINT16 flags)
|
||||
{
|
||||
if (flags & OV_PARAM_FLAG_FIXED4)
|
||||
return 4;
|
||||
else if (flags & OV_PARAM_FLAG_FIXED8)
|
||||
return 8;
|
||||
else
|
||||
return instsize;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
mask_for_param - given a set of parameter
|
||||
flags and the instruction size, return a
|
||||
mask of valid bits for that parameter
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE UINT64 mask_for_param(int instsize, UINT16 flags)
|
||||
{
|
||||
switch (size_for_param(instsize, flags))
|
||||
{
|
||||
case 4: return U64(0x00000000ffffffff);
|
||||
case 8: return U64(0xffffffffffffffff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -334,6 +411,17 @@ drcuml_state *drcuml_alloc(drccache *cache, UINT32 flags, int modes, int addrbit
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_get_backend_info - return information
|
||||
about the back-end
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_get_backend_info(drcuml_state *drcuml, drcbe_info *info)
|
||||
{
|
||||
(*drcuml->beintf->be_get_info)(drcuml->bestate, info);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_reset - reset the state completely,
|
||||
flushing the cache and all information
|
||||
@ -343,7 +431,7 @@ void drcuml_reset(drcuml_state *drcuml)
|
||||
{
|
||||
drcuml_codehandle *handle;
|
||||
jmp_buf errorbuf;
|
||||
|
||||
|
||||
/* flush the cache */
|
||||
drccache_flush(drcuml->cache);
|
||||
|
||||
@ -357,6 +445,17 @@ void drcuml_reset(drcuml_state *drcuml)
|
||||
|
||||
/* call the backend to reset */
|
||||
(*drcuml->beintf->be_reset)(drcuml->bestate);
|
||||
|
||||
/* do a one-time validation if requested */
|
||||
if (VALIDATE_BACKEND)
|
||||
{
|
||||
static int validated = FALSE;
|
||||
if (!validated)
|
||||
{
|
||||
validated = TRUE;
|
||||
validate_backend(drcuml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -817,7 +916,6 @@ void drcuml_add_comment(drcuml_block *block, const char *format, ...)
|
||||
instruction created meets all requirements
|
||||
-------------------------------------------------*/
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
static void validate_instruction(drcuml_block *block, const drcuml_instruction *inst)
|
||||
{
|
||||
const drcuml_opcode_valid *opvalid = &opcode_valid_table[inst->opcode];
|
||||
@ -829,30 +927,484 @@ static void validate_instruction(drcuml_block *block, const drcuml_instruction *
|
||||
if (inst->numparams > 0)
|
||||
{
|
||||
assert(inst->param[0].type > DRCUML_PTYPE_NONE && inst->param[0].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p0types >> inst->param[0].type) & 1) != 0);
|
||||
if (inst->param[0].type == DRCUML_PTYPE_MEMORY && !(opvalid->p0types & 0x80))
|
||||
assert(((opvalid->ptypes[0] >> inst->param[0].type) & 1) != 0);
|
||||
if (inst->param[0].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[0] & OV_PARAM_FLAG_ANYMEM))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[0].value);
|
||||
}
|
||||
if (inst->numparams > 1)
|
||||
{
|
||||
assert(inst->param[1].type > DRCUML_PTYPE_NONE && inst->param[1].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p1types >> inst->param[1].type) & 1) != 0);
|
||||
if (inst->param[1].type == DRCUML_PTYPE_MEMORY && !(opvalid->p1types & 0x80))
|
||||
assert(((opvalid->ptypes[1] >> inst->param[1].type) & 1) != 0);
|
||||
if (inst->param[1].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[1] & OV_PARAM_FLAG_ANYMEM))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[1].value);
|
||||
}
|
||||
if (inst->numparams > 2)
|
||||
{
|
||||
assert(inst->param[2].type > DRCUML_PTYPE_NONE && inst->param[2].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p2types >> inst->param[2].type) & 1) != 0);
|
||||
if (inst->param[2].type == DRCUML_PTYPE_MEMORY && !(opvalid->p2types & 0x80))
|
||||
assert(((opvalid->ptypes[2] >> inst->param[2].type) & 1) != 0);
|
||||
if (inst->param[2].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[2] & OV_PARAM_FLAG_ANYMEM))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[2].value);
|
||||
}
|
||||
if (inst->numparams > 3)
|
||||
{
|
||||
assert(inst->param[3].type > DRCUML_PTYPE_NONE && inst->param[3].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p3types >> inst->param[3].type) & 1) != 0);
|
||||
if (inst->param[3].type == DRCUML_PTYPE_MEMORY && !(opvalid->p3types & 0x80))
|
||||
assert(((opvalid->ptypes[3] >> inst->param[3].type) & 1) != 0);
|
||||
if (inst->param[3].type == DRCUML_PTYPE_MEMORY && !(opvalid->ptypes[3] & OV_PARAM_FLAG_ANYMEM))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[3].value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
BACK-END VALIDATION
|
||||
***************************************************************************/
|
||||
|
||||
#define TEST_ENTRY_DSS(op, size, p1, p2, p3, flags) { DRCUML_OP_##op, size, 0x01, 0, flags, { U64(p1), U64(p2), U64(p3) } },
|
||||
#define TEST_ENTRY_DSSI(op, size, p1, p2, p3, iflags, flags) { DRCUML_OP_##op, size, 0x01, iflags, flags, { U64(p1), U64(p2), U64(p3) } },
|
||||
|
||||
static const bevalidate_test bevalidate_test_list[] =
|
||||
{
|
||||
TEST_ENTRY_DSS(ADD, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0)
|
||||
TEST_ENTRY_DSS(ADD, 4, 0x80000000, 0x12345678, 0x6dcba988, FLAGS_V | FLAGS_S)
|
||||
TEST_ENTRY_DSS(ADD, 4, 0xffffffff, 0x92345678, 0x6dcba987, FLAGS_S)
|
||||
TEST_ENTRY_DSS(ADD, 4, 0x00000000, 0x92345678, 0x6dcba988, FLAGS_C | FLAGS_Z)
|
||||
|
||||
TEST_ENTRY_DSS(ADD, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0)
|
||||
TEST_ENTRY_DSS(ADD, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, FLAGS_V | FLAGS_S)
|
||||
TEST_ENTRY_DSS(ADD, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, FLAGS_S)
|
||||
TEST_ENTRY_DSS(ADD, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, FLAGS_C | FLAGS_Z)
|
||||
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0, 0)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba986, FLAGS_C, 0)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba988, 0, FLAGS_V | FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba987, FLAGS_C, FLAGS_V | FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba987, 0, FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba986, FLAGS_C, FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba988, 0, FLAGS_C | FLAGS_Z)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba987, FLAGS_C, FLAGS_C | FLAGS_Z)
|
||||
TEST_ENTRY_DSSI(ADDC, 4, 0x12345678, 0x12345678, 0xffffffff, FLAGS_C, FLAGS_C)
|
||||
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0, 0)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba987654320f, FLAGS_C, 0)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, 0, FLAGS_V | FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543210, FLAGS_C, FLAGS_V | FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, 0, FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba987654320f, FLAGS_C, FLAGS_S)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, 0, FLAGS_C | FLAGS_Z)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543210, FLAGS_C, FLAGS_C | FLAGS_Z)
|
||||
TEST_ENTRY_DSSI(ADDC, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAGS_C, FLAGS_C)
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
validate_backend - execute a number of
|
||||
generic tests on the backend code generator
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void validate_backend(drcuml_state *drcuml)
|
||||
{
|
||||
drcuml_codehandle *handles[3];
|
||||
int tnum;
|
||||
|
||||
/* allocate handles for the code */
|
||||
handles[0] = drcuml_handle_alloc(drcuml, "test_entry");
|
||||
handles[1] = drcuml_handle_alloc(drcuml, "code_start");
|
||||
handles[2] = drcuml_handle_alloc(drcuml, "code_end");
|
||||
|
||||
/* iterate over test entries */
|
||||
printf("Backend validation....\n");
|
||||
for (tnum = 0; tnum < ARRAY_LENGTH(bevalidate_test_list); tnum++)
|
||||
{
|
||||
const bevalidate_test *test = &bevalidate_test_list[tnum];
|
||||
drcuml_parameter param[ARRAY_LENGTH(test->param)];
|
||||
|
||||
/* reset parameter list and iterate */
|
||||
memset(param, 0, sizeof(param));
|
||||
printf("Executing test %d/%d", tnum + 1, ARRAY_LENGTH(bevalidate_test_list));
|
||||
bevalidate_iterate_over_params(drcuml, handles, test, param, 0);
|
||||
printf("\n");
|
||||
}
|
||||
fatalerror("All tests passed!");
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bevalidate_iterate_over_params - iterate over
|
||||
all supported types and values of a parameter
|
||||
and recursively hand off to the next parameter,
|
||||
or else move on to iterate over the flags
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_iterate_over_params(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist, int pnum)
|
||||
{
|
||||
const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
|
||||
|
||||
/* if no parameters, execute now */
|
||||
if (pnum >= ARRAY_LENGTH(opvalid->ptypes) || opvalid->ptypes[pnum] == OV_PARAM_ALLOWED_NONE)
|
||||
{
|
||||
bevalidate_iterate_over_flags(drcuml, handles, test, paramlist);
|
||||
return;
|
||||
}
|
||||
|
||||
/* iterate over valid parameter types */
|
||||
for (paramlist[pnum].type = DRCUML_PTYPE_IMMEDIATE; paramlist[pnum].type < DRCUML_PTYPE_MAX; paramlist[pnum].type++)
|
||||
if (opvalid->ptypes[pnum] & (1 << paramlist[pnum].type))
|
||||
{
|
||||
int pindex, pcount;
|
||||
|
||||
/* mapvars can only do 32-bit tests */
|
||||
if (paramlist[pnum].type == DRCUML_PTYPE_MAPVAR && size_for_param(test->size, opvalid->ptypes[pnum]) == 8)
|
||||
continue;
|
||||
|
||||
/* for some parameter types, we wish to iterate over all possibilities */
|
||||
switch (paramlist[pnum].type)
|
||||
{
|
||||
case DRCUML_PTYPE_INT_REGISTER: pcount = DRCUML_REG_I_END - DRCUML_REG_I0; break;
|
||||
case DRCUML_PTYPE_FLOAT_REGISTER: pcount = DRCUML_REG_F_END - DRCUML_REG_F0; break;
|
||||
case DRCUML_PTYPE_MAPVAR: pcount = DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0; break;
|
||||
default: pcount = 1; break;
|
||||
}
|
||||
|
||||
/* iterate over possibilities */
|
||||
for (pindex = 0; pindex < pcount; pindex++)
|
||||
{
|
||||
int skip = FALSE;
|
||||
int pscannum;
|
||||
|
||||
/* for param 0, print a dot */
|
||||
if (pnum == 0)
|
||||
printf(".");
|
||||
|
||||
/* can't duplicate multiple source parameters unless they are immediates */
|
||||
if (paramlist[pnum].type != DRCUML_PTYPE_IMMEDIATE && ((test->destmask >> pnum) & 1) == 0)
|
||||
|
||||
/* loop over all parameters we've done before; if the parameter is a source and matches us, skip this case */
|
||||
for (pscannum = 0; pscannum < pnum; pscannum++)
|
||||
if (((test->destmask >> pscannum) & 1) == 0 && paramlist[pnum].type == paramlist[pscannum].type && pindex == paramlist[pscannum].value)
|
||||
skip = TRUE;
|
||||
|
||||
/* iterate over the next parameter in line */
|
||||
if (!skip)
|
||||
{
|
||||
paramlist[pnum].value = pindex;
|
||||
bevalidate_iterate_over_params(drcuml, handles, test, paramlist, pnum + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bevalidate_iterate_over_flags - iterate over
|
||||
all supported flag masks
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_iterate_over_flags(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, drcuml_parameter *paramlist)
|
||||
{
|
||||
const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
|
||||
UINT8 flagmask = opvalid->condflags & 0x1f;
|
||||
UINT8 curmask;
|
||||
|
||||
/* iterate over all possible flag combinations */
|
||||
for (curmask = 0; curmask <= flagmask; curmask++)
|
||||
if ((curmask & flagmask) == curmask)
|
||||
bevalidate_execute(drcuml, handles, test, paramlist, curmask);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bevalidate_execute - execute a single instance
|
||||
of a test, generating code and verifying the
|
||||
results
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_execute(drcuml_state *drcuml, drcuml_codehandle **handles, const bevalidate_test *test, const drcuml_parameter *paramlist, UINT8 flagmask)
|
||||
{
|
||||
drcuml_parameter params[ARRAY_LENGTH(test->param)];
|
||||
drcuml_machine_state istate, fstate;
|
||||
drcuml_instruction testinst;
|
||||
drcuml_block *block;
|
||||
UINT64 *parammem;
|
||||
int numparams;
|
||||
|
||||
/* allocate memory for parameters */
|
||||
parammem = drccache_memory_alloc_near(drcuml->cache, sizeof(UINT64) * ARRAY_LENGTH(test->param));
|
||||
|
||||
/* flush the cache */
|
||||
drcuml_reset(drcuml);
|
||||
|
||||
/* start a new block */
|
||||
block = drcuml_block_begin(drcuml, 30, NULL);
|
||||
UML_HANDLE(block, handles[0]);
|
||||
|
||||
/* set up a random initial state */
|
||||
bevalidate_initialize_random_state(block, &istate);
|
||||
|
||||
/* then populate the state with the parameters */
|
||||
numparams = bevalidate_populate_state(block, &istate, test, paramlist, params, parammem);
|
||||
|
||||
/* generate the code */
|
||||
UML_RESTORE(block, &istate);
|
||||
UML_HANDLE(block, handles[1]);
|
||||
switch (numparams)
|
||||
{
|
||||
case 0:
|
||||
drcuml_block_append_0(block, test->opcode, test->size, flagmask);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
drcuml_block_append_1(block, test->opcode, test->size, flagmask, params[0].type, params[0].value);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
drcuml_block_append_2(block, test->opcode, test->size, flagmask, params[0].type, params[0].value, params[1].type, params[1].value);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
drcuml_block_append_3(block, test->opcode, test->size, flagmask, params[0].type, params[0].value, params[1].type, params[1].value, params[2].type, params[2].value);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
drcuml_block_append_4(block, test->opcode, test->size, flagmask, params[0].type, params[0].value, params[1].type, params[1].value, params[2].type, params[2].value, params[3].type, params[3].value);
|
||||
break;
|
||||
}
|
||||
testinst = block->inst[block->nextinst - 1];
|
||||
UML_HANDLE(block, handles[2]);
|
||||
UML_SAVE(block, &fstate);
|
||||
UML_EXIT(block, IMM(0));
|
||||
|
||||
/* end the block */
|
||||
drcuml_block_end(block);
|
||||
|
||||
/* execute */
|
||||
drcuml_execute(drcuml, handles[0]);
|
||||
|
||||
/* verify the results */
|
||||
bevalidate_verify_state(drcuml, &istate, &fstate, test, params, &testinst, handles[1]->code, handles[2]->code, flagmask);
|
||||
|
||||
/* free memory */
|
||||
drccache_memory_free(drcuml->cache, parammem, sizeof(UINT64) * ARRAY_LENGTH(test->param));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bevalidate_initialize_random_state -
|
||||
initialize the machine state to randomness
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void bevalidate_initialize_random_state(drcuml_block *block, drcuml_machine_state *state)
|
||||
{
|
||||
int regnum;
|
||||
|
||||
/* initialize core state to random values */
|
||||
state->fmod = mame_rand(Machine) & 0x03;
|
||||
state->flags = mame_rand(Machine) & 0x1f;
|
||||
state->exp = mame_rand(Machine);
|
||||
|
||||
/* initialize integer registers to random values */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++)
|
||||
{
|
||||
state->r[regnum].w.h = mame_rand(Machine);
|
||||
state->r[regnum].w.l = mame_rand(Machine);
|
||||
}
|
||||
|
||||
/* initialize float registers to random values */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++)
|
||||
{
|
||||
*(UINT32 *)&state->f[regnum].s.h = mame_rand(Machine);
|
||||
*(UINT32 *)&state->f[regnum].s.l = mame_rand(Machine);
|
||||
}
|
||||
|
||||
/* initialize map variables to random values */
|
||||
for (regnum = 0; regnum < DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0; regnum++)
|
||||
UML_MAPVAR(block, MVAR(regnum), mame_rand(Machine));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bevalidate_populate_state - populate the
|
||||
machine state with the proper values prior
|
||||
to executing a test
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *paramlist, drcuml_parameter *params, UINT64 *parammem)
|
||||
{
|
||||
const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
|
||||
int numparams = ARRAY_LENGTH(test->param);
|
||||
int pnum;
|
||||
|
||||
/* copy flags as-is */
|
||||
state->flags = test->iflags;
|
||||
|
||||
/* iterate over parameters */
|
||||
for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++)
|
||||
{
|
||||
int psize = size_for_param(test->size, opvalid->ptypes[pnum]);
|
||||
drcuml_parameter *curparam = ¶ms[pnum];
|
||||
|
||||
/* start with a copy of the parameter from the list */
|
||||
*curparam = paramlist[pnum];
|
||||
|
||||
/* switch off the type */
|
||||
switch (curparam->type)
|
||||
{
|
||||
/* immediate parameters: take the value from the test entry */
|
||||
case DRCUML_PTYPE_IMMEDIATE:
|
||||
curparam->value = test->param[pnum];
|
||||
break;
|
||||
|
||||
/* register parameters: set the register value in the state and set the parameter value to the register index */
|
||||
case DRCUML_PTYPE_INT_REGISTER:
|
||||
state->r[curparam->value].d = test->param[pnum];
|
||||
curparam->value += DRCUML_REG_I0;
|
||||
break;
|
||||
|
||||
/* register parameters: set the register value in the state and set the parameter value to the register index */
|
||||
case DRCUML_PTYPE_FLOAT_REGISTER:
|
||||
state->f[curparam->value].d = test->param[pnum];
|
||||
curparam->value += DRCUML_REG_F0;
|
||||
break;
|
||||
|
||||
/* memory parameters: set the memory value in the parameter space and set the parameter value to point to it */
|
||||
case DRCUML_PTYPE_MEMORY:
|
||||
curparam->value = (FPTR)¶mmem[pnum];
|
||||
if (psize == 4)
|
||||
*(UINT32 *)(FPTR)curparam->value = test->param[pnum];
|
||||
else
|
||||
*(UINT64 *)(FPTR)curparam->value = test->param[pnum];
|
||||
break;
|
||||
|
||||
/* map variables: issue a MAPVAR instruction to set the value and set the parameter value to the mapvar index */
|
||||
case DRCUML_PTYPE_MAPVAR:
|
||||
UML_MAPVAR(block, MVAR(curparam->value), test->param[pnum]);
|
||||
curparam->value += DRCUML_MAPVAR_M0;
|
||||
break;
|
||||
|
||||
/* use anything else to count the number of parameters */
|
||||
default:
|
||||
numparams = MIN(numparams, pnum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the total number of parameters */
|
||||
return numparams;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bevalidate_verify_state - verify the final
|
||||
state after executing a test, and report any
|
||||
discrepancies
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, const drcuml_parameter *params, const drcuml_instruction *testinst, drccodeptr codestart, drccodeptr codeend, UINT8 flagmask)
|
||||
{
|
||||
const drcuml_opcode_valid *opvalid = &opcode_valid_table[test->opcode];
|
||||
UINT8 ireg[DRCUML_REG_I_END - DRCUML_REG_I0] = { 0 };
|
||||
UINT8 freg[DRCUML_REG_F_END - DRCUML_REG_F0] = { 0 };
|
||||
char errorbuf[1024];
|
||||
char *errend = errorbuf;
|
||||
int pnum, regnum;
|
||||
|
||||
*errend = 0;
|
||||
|
||||
/* check flags */
|
||||
if ((state->flags & flagmask) != (test->flags & flagmask))
|
||||
{
|
||||
errend += sprintf(errend, " Flags ... result:%c%c%c%c%c expected:%c%c%c%c%c\n",
|
||||
(flagmask & DRCUML_FLAG_U) ? ((state->flags & DRCUML_FLAG_U) ? 'U' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_S) ? ((state->flags & DRCUML_FLAG_S) ? 'S' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_Z) ? ((state->flags & DRCUML_FLAG_Z) ? 'Z' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_V) ? ((state->flags & DRCUML_FLAG_V) ? 'V' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_C) ? ((state->flags & DRCUML_FLAG_C) ? 'C' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_U) ? ((test->flags & DRCUML_FLAG_U) ? 'U' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_S) ? ((test->flags & DRCUML_FLAG_S) ? 'S' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_Z) ? ((test->flags & DRCUML_FLAG_Z) ? 'Z' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_V) ? ((test->flags & DRCUML_FLAG_V) ? 'V' : '.') : '-',
|
||||
(flagmask & DRCUML_FLAG_C) ? ((test->flags & DRCUML_FLAG_C) ? 'C' : '.') : '-');
|
||||
}
|
||||
|
||||
/* check destination parameters */
|
||||
for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++)
|
||||
if (test->destmask & (1 << pnum))
|
||||
{
|
||||
UINT64 mask = mask_for_param(test->size, opvalid->ptypes[pnum]);
|
||||
int psize = size_for_param(test->size, opvalid->ptypes[pnum]);
|
||||
UINT64 result = 0;
|
||||
|
||||
/* fetch the result from the parameters */
|
||||
switch (params[pnum].type)
|
||||
{
|
||||
/* integer registers fetch from the state */
|
||||
case DRCUML_PTYPE_INT_REGISTER:
|
||||
ireg[params[pnum].value - DRCUML_REG_I0] = 1;
|
||||
result = state->r[params[pnum].value - DRCUML_REG_I0].d;
|
||||
break;
|
||||
|
||||
/* float registers fetch from the state */
|
||||
case DRCUML_PTYPE_FLOAT_REGISTER:
|
||||
freg[params[pnum].value - DRCUML_REG_I0] = 1;
|
||||
result = state->f[params[pnum].value - DRCUML_REG_F0].d;
|
||||
break;
|
||||
|
||||
/* memory registers fetch from the memory address */
|
||||
case DRCUML_PTYPE_MEMORY:
|
||||
if (psize == 4)
|
||||
result = *(UINT32 *)(FPTR)params[pnum].value;
|
||||
else
|
||||
result = *(UINT64 *)(FPTR)params[pnum].value;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* check against the mask */
|
||||
if ((result & mask) != (test->param[pnum] & mask))
|
||||
{
|
||||
if ((UINT32)mask == mask)
|
||||
errend += sprintf(errend, " Parameter %d ... result:%08X expected:%08X\n", pnum,
|
||||
(UINT32)(result & mask), (UINT32)(test->param[pnum] & mask));
|
||||
else
|
||||
errend += sprintf(errend, " Parameter %d ... result:%08X%08X expected:%08X%08X\n", pnum,
|
||||
(UINT32)((result & mask) >> 32), (UINT32)(result & mask),
|
||||
(UINT32)((test->param[pnum] & mask) >> 32), (UINT32)(test->param[pnum] & mask));
|
||||
}
|
||||
}
|
||||
|
||||
/* check source integer parameters for unexpected alterations */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++)
|
||||
if (ireg[regnum] == 0 && istate->r[regnum].d != state->r[regnum].d)
|
||||
errend += sprintf(errend, " Register i%d ... result:%08X%08X originally:%08X%08X\n", regnum,
|
||||
(UINT32)(state->r[regnum].d >> 32), (UINT32)state->r[regnum].d,
|
||||
(UINT32)(istate->r[regnum].d >> 32), (UINT32)istate->r[regnum].d);
|
||||
|
||||
/* check source float parameters for unexpected alterations */
|
||||
for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++)
|
||||
if (freg[regnum] == 0 && *(UINT64 *)&istate->f[regnum].d != *(UINT64 *)&state->f[regnum].d)
|
||||
errend += sprintf(errend, " Register f%d ... result:%08X%08X originally:%08X%08X\n", regnum,
|
||||
(UINT32)(*(UINT64 *)&state->f[regnum].d >> 32), (UINT32)*(UINT64 *)&state->f[regnum].d,
|
||||
(UINT32)(*(UINT64 *)&istate->f[regnum].d >> 32), (UINT32)*(UINT64 *)&istate->f[regnum].d);
|
||||
|
||||
/* output the error if we have one */
|
||||
if (errend != errorbuf)
|
||||
{
|
||||
char disasm[100];
|
||||
|
||||
/* disassemble the test instruction */
|
||||
drcuml_disasm(testinst, disasm);
|
||||
|
||||
/* output a description of what went wrong */
|
||||
printf("\n");
|
||||
printf("----------------------------------------------\n");
|
||||
printf("Backend validation error:\n");
|
||||
printf(" %s\n", disasm);
|
||||
printf("\n");
|
||||
printf("Errors:\n");
|
||||
printf("%s\n", errorbuf);
|
||||
fatalerror("Error during validation");
|
||||
}
|
||||
return errend != errorbuf;
|
||||
}
|
||||
|
@ -176,6 +176,8 @@ enum _drcuml_opcode
|
||||
DRCUML_OP_SETFMOD, /* SETFMOD src */
|
||||
DRCUML_OP_GETFMOD, /* GETFMOD dst */
|
||||
DRCUML_OP_GETEXP, /* GETEXP dst,index */
|
||||
DRCUML_OP_SAVE, /* SAVE mem */
|
||||
DRCUML_OP_RESTORE, /* RESTORE mem */
|
||||
|
||||
/* Integer Operations */
|
||||
DRCUML_OP_LOAD1U, /* LOAD1U dst,base,index */
|
||||
@ -317,6 +319,53 @@ struct _drcuml_instruction
|
||||
};
|
||||
|
||||
|
||||
/* an integer register, with low/high parts */
|
||||
typedef union _drcuml_ireg drcuml_ireg;
|
||||
union _drcuml_ireg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
struct { UINT32 l,h; } w; /* 32-bit low, high parts of the register */
|
||||
#else
|
||||
struct { UINT32 h,l; } w; /* 32-bit low, high parts of the register */
|
||||
#endif
|
||||
UINT64 d; /* 64-bit full register */
|
||||
};
|
||||
|
||||
|
||||
/* a floating-point register, with low/high parts */
|
||||
typedef union _drcuml_freg drcuml_freg;
|
||||
union _drcuml_freg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
struct { float l,h; } s; /* 32-bit low, high parts of the register */
|
||||
#else
|
||||
struct { float h,l; } s; /* 32-bit low, high parts of the register */
|
||||
#endif
|
||||
double d; /* 64-bit full register */
|
||||
};
|
||||
|
||||
|
||||
/* the collected machine state of a system */
|
||||
typedef struct _drcuml_machine_state drcuml_machine_state;
|
||||
struct _drcuml_machine_state
|
||||
{
|
||||
drcuml_ireg r[DRCUML_REG_I_END - DRCUML_REG_I0]; /* integer registers */
|
||||
drcuml_freg f[DRCUML_REG_F_END - DRCUML_REG_F0]; /* floating-point registers */
|
||||
UINT32 exp; /* exception parameter register */
|
||||
UINT8 fmod; /* fmod (floating-point mode) register */
|
||||
UINT8 flags; /* flags state */
|
||||
};
|
||||
|
||||
|
||||
/* hints and information about the back-end */
|
||||
typedef struct _drcbe_info drcbe_info;
|
||||
struct _drcbe_info
|
||||
{
|
||||
UINT8 direct_iregs; /* number of direct-mapped integer registers */
|
||||
UINT8 direct_fregs; /* number of direct-mapped floating point registers */
|
||||
};
|
||||
|
||||
|
||||
/* typedefs for back-end callback functions */
|
||||
typedef drcbe_state *(*drcbe_alloc_func)(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
|
||||
typedef void (*drcbe_free_func)(drcbe_state *state);
|
||||
@ -324,6 +373,7 @@ typedef void (*drcbe_reset_func)(drcbe_state *state);
|
||||
typedef int (*drcbe_execute_func)(drcbe_state *state, drcuml_codehandle *entry);
|
||||
typedef void (*drcbe_generate_func)(drcbe_state *state, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
|
||||
typedef int (*drcbe_hash_exists)(drcbe_state *state, UINT32 mode, UINT32 pc);
|
||||
typedef void (*drcbe_get_info)(drcbe_state *state, drcbe_info *info);
|
||||
|
||||
|
||||
/* interface structure for a back-end */
|
||||
@ -336,6 +386,7 @@ struct _drcbe_interface
|
||||
drcbe_execute_func be_execute;
|
||||
drcbe_generate_func be_generate;
|
||||
drcbe_hash_exists be_hash_exists;
|
||||
drcbe_get_info be_get_info;
|
||||
};
|
||||
|
||||
|
||||
@ -349,6 +400,9 @@ struct _drcbe_interface
|
||||
/* allocate state for the code generator and initialize the back-end */
|
||||
drcuml_state *drcuml_alloc(drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
|
||||
|
||||
/* return information about the back-end */
|
||||
void drcuml_get_backend_info(drcuml_state *drcuml, drcbe_info *info);
|
||||
|
||||
/* reset the state completely, flushing the cache and all information */
|
||||
void drcuml_reset(drcuml_state *drcuml);
|
||||
|
||||
|
@ -89,6 +89,8 @@ static const drcuml_opdesc opcode_source_table[] =
|
||||
{ DRCUML_OP_SETFMOD, "setfmod", { output_param } },
|
||||
{ DRCUML_OP_GETFMOD, "getfmod", { output_param } },
|
||||
{ DRCUML_OP_GETEXP, "getexp", { output_param } },
|
||||
{ DRCUML_OP_SAVE, "save", { output_param } },
|
||||
{ DRCUML_OP_RESTORE, "restore", { output_param } },
|
||||
|
||||
/* Integer Operations */
|
||||
{ DRCUML_OP_LOAD1U, "!load1u", { output_param, output_param, output_param } },
|
||||
|
@ -128,12 +128,11 @@
|
||||
|
||||
|
||||
/* ----- Internal Register Operations ----- */
|
||||
#define UML_SETMODE(block, mode) do { drcuml_block_append_1(block, DRCUML_OP_SETMODE, 4, IF_ALWAYS, mode); } while (0)
|
||||
#define UML_GETMODE(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETMODE, 4, IF_ALWAYS, dst); } while (0)
|
||||
#define UML_SETFMOD(block, mode) do { drcuml_block_append_1(block, DRCUML_OP_SETFMOD, 4, IF_ALWAYS, mode); } while (0)
|
||||
#define UML_GETFMOD(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETFMOD, 4, IF_ALWAYS, dst); } while (0)
|
||||
#define UML_SUBICNT(block, delta, param) do { drcuml_block_append_2(block, DRCUML_OP_SUBICNT, 4, IF_ALWAYS, delta, param); } while (0)
|
||||
#define UML_GETEXP(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETEXP, 4, IF_ALWAYS, dst); } while (0)
|
||||
#define UML_SAVE(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_SAVE, 4, IF_ALWAYS, MEM(dst)); } while (0)
|
||||
#define UML_RESTORE(block, src) do { drcuml_block_append_1(block, DRCUML_OP_RESTORE, 4, IF_ALWAYS, MEM(src)); } while (0)
|
||||
|
||||
|
||||
/* ----- 32-Bit Integer Operations ----- */
|
||||
|
@ -891,7 +891,7 @@ static void code_compile_block(drcuml_state *drcuml, UINT8 mode, offs_t pc)
|
||||
|
||||
/* get a description of this sequence */
|
||||
desclist = drcfe_describe_code(mips3.drcfe, pc);
|
||||
if (LOG_UML)
|
||||
if (LOG_UML || LOG_NATIVE)
|
||||
log_opcode_desc(drcuml, desclist, 0);
|
||||
|
||||
/* if we get an error back, flush the cache and try again */
|
||||
@ -3588,7 +3588,7 @@ static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, i
|
||||
char buffer[100];
|
||||
|
||||
/* disassemle the current instruction and output it to the log */
|
||||
#if LOG_UML
|
||||
#if (LOG_UML || LOG_NATIVE)
|
||||
dasmmips3(buffer, desclist->pc, *desclist->opptr.l);
|
||||
#else
|
||||
strcpy(buffer, "???");
|
||||
@ -4003,7 +4003,7 @@ void rm7000le_get_info(UINT32 state, cpuinfo *info)
|
||||
DISASSEMBLERS
|
||||
***************************************************************************/
|
||||
|
||||
#if !defined(MAME_DEBUG) && (LOG_UML)
|
||||
#if !defined(MAME_DEBUG) && (LOG_UML || LOG_NATIVE)
|
||||
#include "mips3dsm.c"
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user