diff options
Diffstat (limited to 'trunk/src/emu/cpu/drcbec.c')
-rw-r--r-- | trunk/src/emu/cpu/drcbec.c | 2281 |
1 files changed, 2281 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/drcbec.c b/trunk/src/emu/cpu/drcbec.c new file mode 100644 index 00000000000..491175a9145 --- /dev/null +++ b/trunk/src/emu/cpu/drcbec.c @@ -0,0 +1,2281 @@ +/*************************************************************************** + + drcbec.c + + Interpreted C core back-end for the universal machine language. + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "drcbec.h" + +#ifdef _MSC_VER +#include <float.h> +#define isnan _isnan +#endif + +using namespace uml; + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// define a bit to match each possible condition, starting at bit 12 +#define ZBIT (0x1000 << (COND_Z & 15)) +#define NZBIT (0x1000 << (COND_NZ & 15)) +#define SBIT (0x1000 << (COND_S & 15)) +#define NSBIT (0x1000 << (COND_NS & 15)) +#define CBIT (0x1000 << (COND_C & 15)) +#define NCBIT (0x1000 << (COND_NC & 15)) +#define VBIT (0x1000 << (COND_V & 15)) +#define NVBIT (0x1000 << (COND_NV & 15)) +#define UBIT (0x1000 << (COND_U & 15)) +#define NUBIT (0x1000 << (COND_NU & 15)) +#define ABIT (0x1000 << (COND_A & 15)) +#define BEBIT (0x1000 << (COND_BE & 15)) +#define GBIT (0x1000 << (COND_G & 15)) +#define GEBIT (0x1000 << (COND_GE & 15)) +#define LBIT (0x1000 << (COND_L & 15)) +#define LEBIT (0x1000 << (COND_LE & 15)) + + +// internal opcodes +enum +{ + OP_LOAD1 = OP_MAX, + OP_LOAD1x2, + OP_LOAD1x4, + OP_LOAD1x8, + OP_LOAD2x1, + OP_LOAD2, + OP_LOAD2x4, + OP_LOAD2x8, + OP_LOAD4x1, + OP_LOAD4x2, + OP_LOAD4, + OP_LOAD4x8, + OP_LOAD8x1, + OP_LOAD8x2, + OP_LOAD8x4, + OP_LOAD8, + OP_LOADS1, + OP_LOADS1x2, + OP_LOADS1x4, + OP_LOADS1x8, + OP_LOADS2x1, + OP_LOADS2, + OP_LOADS2x4, + OP_LOADS2x8, + OP_LOADS4x1, + OP_LOADS4x2, + OP_LOADS4, + OP_LOADS4x8, + OP_LOADS8x1, + OP_LOADS8x2, + OP_LOADS8x4, + OP_LOADS8, + OP_STORE1, + OP_STORE1x2, + OP_STORE1x4, + OP_STORE1x8, + OP_STORE2x1, + OP_STORE2, + OP_STORE2x4, + OP_STORE2x8, + OP_STORE4x1, + OP_STORE4x2, + OP_STORE4, + OP_STORE4x8, + OP_STORE8x1, + OP_STORE8x2, + OP_STORE8x4, + OP_STORE8, + OP_READ1, + OP_READ2, + OP_READ4, + OP_READ8, + OP_READM1, + OP_READM2, + OP_READM4, + OP_READM8, + OP_WRITE1, + OP_WRITE2, + OP_WRITE4, + OP_WRITE8, + OP_WRITEM1, + OP_WRITEM2, + OP_WRITEM4, + OP_WRITEM8, + OP_SEXT1, + OP_SEXT2, + OP_SEXT4, + OP_SEXT8, + OP_FTOI4T, + OP_FTOI4R, + OP_FTOI4C, + OP_FTOI4F, + OP_FTOI4, + OP_FTOI8T, + OP_FTOI8R, + OP_FTOI8C, + OP_FTOI8F, + OP_FTOI8, + OP_FFRI4, + OP_FFRI8, + OP_FFRFS, + OP_FFRFD, +}; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +// +// opcode format: +// +// bits 31..28 == number of words following the opcode itself (0-15) +// bits 27..12 == bitmask specify which condition code we care about +// bits 11.. 2 == opcode +// bit 1 == flags/condition summary (0 if no condition/flags, 1 otherwise) +// bit 0 == operation size (0=32-bit, 1=64-bit) +// + +// build a short opcode from the raw opcode and size +#define MAKE_OPCODE_SHORT(op, size, conditionorflags) \ + ((((size) == 8) << 0) | (((conditionorflags) != 0) << 1) | ((op) << 2)) + +// build a full opcode from the raw opcode, size, condition/flags, and immediate count +#define MAKE_OPCODE_FULL(op, size, condition, flags, pwords) \ + (MAKE_OPCODE_SHORT(op, size, (condition | flags)) | ((condition != COND_ALWAYS) ? (0x1000 << ((condition) & 15)) : 0) | ((pwords) << 28)) + +// extract various parts of the opcode +#define OPCODE_GET_SHORT(op) ((op) & 0xfff) +#define OPCODE_PASS_CONDITION(op,f) (((op) & s_condition_map[f]) != 0) +#define OPCODE_FAIL_CONDITION(op,f) (((op) & s_condition_map[f]) == 0) +#define OPCODE_GET_PWORDS(op) ((op) >> 28) + +// shorthand for accessing parameters in the instruction stream +#define PARAM0 (*inst[0].puint32) +#define PARAM1 (*inst[1].puint32) +#define PARAM2 (*inst[2].puint32) +#define PARAM3 (*inst[3].puint32) + +#define DPARAM0 (*inst[0].puint64) +#define DPARAM1 (*inst[1].puint64) +#define DPARAM2 (*inst[2].puint64) +#define DPARAM3 (*inst[3].puint64) + +#define FSPARAM0 (*inst[0].pfloat) +#define FSPARAM1 (*inst[1].pfloat) +#define FSPARAM2 (*inst[2].pfloat) +#define FSPARAM3 (*inst[3].pfloat) + +#define FDPARAM0 (*inst[0].pdouble) +#define FDPARAM1 (*inst[1].pdouble) +#define FDPARAM2 (*inst[2].pdouble) +#define FDPARAM3 (*inst[3].pdouble) + +// compute C and V flags for 32-bit add/subtract +#define FLAGS32_C_ADD(a,b) ((UINT32)~(a) < (UINT32)(b)) +#define FLAGS32_C_SUB(a,b) ((UINT32)(b) > (UINT32)(a)) +#define FLAGS32_V_SUB(r,a,b) (((((a) ^ (b)) & ((a) ^ (r))) >> 30) & FLAG_V) +#define FLAGS32_V_ADD(r,a,b) (((~((a) ^ (b)) & ((a) ^ (r))) >> 30) & FLAG_V) + +// compute N and Z flags for 32-bit operations +#define FLAGS32_NZ(v) ((((v) >> 28) & FLAG_S) | (((UINT32)(v) == 0) << 2)) +#define FLAGS32_NZCV_ADD(r,a,b) (FLAGS32_NZ(r) | FLAGS32_C_ADD(a,b) | FLAGS32_V_ADD(r,a,b)) +#define FLAGS32_NZCV_SUB(r,a,b) (FLAGS32_NZ(r) | FLAGS32_C_SUB(a,b) | FLAGS32_V_SUB(r,a,b)) + +// compute C and V flags for 64-bit add/subtract +#define FLAGS64_C_ADD(a,b) ((UINT64)~(a) < (UINT64)(b)) +#define FLAGS64_C_SUB(a,b) ((UINT64)(b) > (UINT64)(a)) +#define FLAGS64_V_SUB(r,a,b) (((((a) ^ (b)) & ((a) ^ (r))) >> 62) & FLAG_V) +#define FLAGS64_V_ADD(r,a,b) (((~((a) ^ (b)) & ((a) ^ (r))) >> 62) & FLAG_V) + +// compute N and Z flags for 64-bit operations +#define FLAGS64_NZ(v) ((((v) >> 60) & FLAG_S) | (((UINT64)(v) == 0) << 2)) +#define FLAGS64_NZCV_ADD(r,a,b) (FLAGS64_NZ(r) | FLAGS64_C_ADD(a,b) | FLAGS64_V_ADD(r,a,b)) +#define FLAGS64_NZCV_SUB(r,a,b) (FLAGS64_NZ(r) | FLAGS64_C_SUB(a,b) | FLAGS64_V_SUB(r,a,b)) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// union to simplify accessing data via the instruction stream +union drcbec_instruction +{ + UINT32 i; + void * v; + char * c; + UINT8 * puint8; + INT8 * pint8; + UINT16 * puint16; + INT16 * pint16; + UINT32 * puint32; + INT32 * pint32; + UINT64 * puint64; + INT64 * pint64; + float * pfloat; + double * pdouble; + void (*cfunc)(void *); + drcuml_machine_state *state; + const code_handle * handle; + const drcbec_instruction *inst; + const drcbec_instruction **pinst; +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +UINT64 drcbe_c::s_immediate_zero = 0; + +const UINT32 drcbe_c::s_condition_map[] = +{ + /* ..... */ NCBIT | NVBIT | NZBIT | NSBIT | NUBIT | ABIT | GBIT | GEBIT, + /* ....C */ CBIT | NVBIT | NZBIT | NSBIT | NUBIT | BEBIT | GBIT | GEBIT, + /* ...V. */ NCBIT | VBIT | NZBIT | NSBIT | NUBIT | ABIT | LEBIT | LBIT, + /* ...VC */ CBIT | VBIT | NZBIT | NSBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* ..Z.. */ NCBIT | NVBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* ..Z.C */ CBIT | NVBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* ..ZV. */ NCBIT | VBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* ..ZVC */ CBIT | VBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .S... */ NCBIT | NVBIT | NZBIT | SBIT | NUBIT | ABIT | LEBIT | LBIT, + /* .S..C */ CBIT | NVBIT | NZBIT | SBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .S.V. */ NCBIT | VBIT | NZBIT | SBIT | NUBIT | ABIT | GBIT | GEBIT, + /* .S.VC */ CBIT | VBIT | NZBIT | SBIT | NUBIT | BEBIT | GBIT | GEBIT, + /* .SZ.. */ NCBIT | NVBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .SZ.C */ CBIT | NVBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .SZV. */ NCBIT | VBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* .SZVC */ CBIT | VBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* U.... */ NCBIT | NVBIT | NZBIT | NSBIT | UBIT | ABIT | GBIT | GEBIT, + /* U...C */ CBIT | NVBIT | NZBIT | NSBIT | UBIT | BEBIT | GBIT | GEBIT, + /* U..V. */ NCBIT | VBIT | NZBIT | NSBIT | UBIT | ABIT | LEBIT | LBIT, + /* U..VC */ CBIT | VBIT | NZBIT | NSBIT | UBIT | BEBIT | LEBIT | LBIT, + /* U.Z.. */ NCBIT | NVBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | GEBIT, + /* U.Z.C */ CBIT | NVBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | GEBIT, + /* U.ZV. */ NCBIT | VBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | LBIT, + /* U.ZVC */ CBIT | VBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | LBIT, + /* US... */ NCBIT | NVBIT | NZBIT | SBIT | UBIT | ABIT | LEBIT | LBIT, + /* US..C */ CBIT | NVBIT | NZBIT | SBIT | UBIT | BEBIT | LEBIT | LBIT, + /* US.V. */ NCBIT | VBIT | NZBIT | SBIT | UBIT | ABIT | GBIT | GEBIT, + /* US.VC */ CBIT | VBIT | NZBIT | SBIT | UBIT | BEBIT | GBIT | GEBIT, + /* USZ.. */ NCBIT | NVBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | LBIT, + /* USZ.C */ CBIT | NVBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | LBIT, + /* USZV. */ NCBIT | VBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | GEBIT, + /* USZVC */ CBIT | VBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | GEBIT +}; + + + +//************************************************************************** +// C BACKEND +//************************************************************************** + +//------------------------------------------------- +// drcbe_c - constructor +//------------------------------------------------- + +drcbe_c::drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits) + : drcbe_interface(drcuml, cache, device), + m_hash(cache, modes, addrbits, ignorebits), + m_map(cache, 0), + m_labels(cache), + m_fixup_delegate(FUNC(drcbe_c::fixup_label), this) +{ +} + + +//------------------------------------------------- +// ~drcbe_c - destructor +//------------------------------------------------- + +drcbe_c::~drcbe_c() +{ +} + + +//------------------------------------------------- +// reset - reset back-end specific state +//------------------------------------------------- + +void drcbe_c::reset() +{ + // reset our hash tables + m_hash.reset(); + m_hash.set_default_codeptr(NULL); +} + + +//------------------------------------------------- +// drcbec_generate - generate code +//------------------------------------------------- + +void drcbe_c::generate(drcuml_block &block, const instruction *instlist, UINT32 numinst) +{ + // tell all of our utility objects that a block is beginning + m_hash.block_begin(block, instlist, numinst); + m_labels.block_begin(block); + m_map.block_begin(block); + + // begin codegen; fail if we can't + drccodeptr *cachetop = m_cache.begin_codegen(numinst * sizeof(drcbec_instruction) * 4); + if (cachetop == NULL) + block.abort(); + + // compute the base by aligning the cache top to an even multiple of drcbec_instruction + drcbec_instruction *base = (drcbec_instruction *)(((FPTR)*cachetop + sizeof(drcbec_instruction) - 1) & ~(sizeof(drcbec_instruction) - 1)); + drcbec_instruction *dst = base; + + // generate code by copying the instructions and extracting immediates + for (int inum = 0; inum < numinst; inum++) + { + const instruction &inst = instlist[inum]; + UINT8 psize[instruction::MAX_PARAMS]; + + // handle most instructions generally, but a few special cases + opcode_t opcode = inst.opcode(); + switch (opcode) + { + // when we hit a HANDLE opcode, register the current pointer for the handle + case OP_HANDLE: + inst.param(0).handle().set_codeptr((drccodeptr)dst); + break; + + // when we hit a HASH opcode, register the current pointer for the mode/PC + case OP_HASH: + m_hash.set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), (drccodeptr)dst); + break; + + // when we hit a LABEL opcode, register the current pointer for the label + case OP_LABEL: + m_labels.set_codeptr(inst.param(0).label(), (drccodeptr)dst); + break; + + // ignore COMMENT and NOP opcodes + case OP_COMMENT: + case OP_NOP: + break; + + // when we hit a MAPVAR opcode, log the change for the current PC + case OP_MAPVAR: + m_map.set_value((drccodeptr)dst, inst.param(0).mapvar(), inst.param(1).immediate()); + break; + + // JMP instructions need to resolve their labels + case OP_JMP: + (dst++)->i = MAKE_OPCODE_FULL(opcode, inst.size(), inst.condition(), inst.flags(), 1); + dst->inst = (drcbec_instruction *)m_labels.get_codeptr(inst.param(0).label(), m_fixup_delegate, dst); + dst++; + break; + + // generically handle everything else + default: + + // determine the operand size for each operand; mostly this is just the instruction size + for (int pnum = 0; pnum < inst.numparams(); pnum++) + psize[pnum] = inst.size(); + if (opcode == OP_LOAD || opcode == OP_FLOAD) + psize[2] = 4; + if (opcode == OP_STORE || opcode == OP_FSTORE) + psize[1] = 4; + if (opcode == OP_READ || opcode == OP_READM || opcode == OP_FREAD) + psize[1] = psize[2] = 4; + if (opcode == OP_WRITE || opcode == OP_WRITEM || opcode == OP_FWRITE) + psize[0] = psize[2] = 4; + if (opcode == OP_SEXT && inst.param(2).size() != SIZE_QWORD) + psize[1] = 4; + if (opcode == OP_FTOINT) + psize[0] = 1 << inst.param(2).size(); + if (opcode == OP_FFRINT || opcode == OP_FFRFLT) + psize[1] = 1 << inst.param(2).size(); + + // pre-expand opcodes that encode size/scale in them + if (opcode == OP_LOAD) + opcode = (opcode_t)(OP_LOAD1 + inst.param(3).size() * 4 + inst.param(3).scale()); + if (opcode == OP_LOADS) + opcode = (opcode_t)(OP_LOADS1 + inst.param(3).size() * 4 + inst.param(3).scale()); + if (opcode == OP_STORE) + opcode = (opcode_t)(OP_STORE1 + inst.param(3).size() * 4 + inst.param(3).scale()); + if (opcode == OP_READ) + opcode = (opcode_t)(OP_READ1 + inst.param(2).size()); + if (opcode == OP_READM) + opcode = (opcode_t)(OP_READM1 + inst.param(3).size()); + if (opcode == OP_WRITE) + opcode = (opcode_t)(OP_WRITE1 + inst.param(2).size()); + if (opcode == OP_WRITEM) + opcode = (opcode_t)(OP_WRITEM1 + inst.param(3).size()); + if (opcode == OP_SEXT) + opcode = (opcode_t)(OP_SEXT1 + inst.param(2).size()); + if (opcode == OP_FTOINT) + opcode = (opcode_t)(OP_FTOI4T + 5 * (inst.param(2).size() - 2) + inst.param(3).rounding()); + if (opcode == OP_FFRINT) + opcode = (opcode_t)(OP_FFRI4 + (inst.param(2).size() - 2)); + if (opcode == OP_FFRFLT) + opcode = (opcode_t)(OP_FFRFS + (inst.param(2).size() - 2)); + + // count how many bytes of immediates we need + int immedbytes = 0; + for (int pnum = 0; pnum < inst.numparams(); pnum++) + if (inst.param(pnum).is_mapvar() || + (inst.param(pnum).is_immediate() && inst.param(pnum).immediate() != 0) || + (inst.param(pnum).is_size_space() && inst.param(pnum).space() != 0)) + immedbytes += psize[pnum]; + + // compute how many instruction words we need for that + int immedwords = (immedbytes + sizeof(drcbec_instruction) - 1) / sizeof(drcbec_instruction); + + // first item is the opcode, size, condition flags and length + (dst++)->i = MAKE_OPCODE_FULL(opcode, inst.size(), inst.condition(), inst.flags(), inst.numparams() + immedwords); + + // immediates start after parameters + void *immed = dst + inst.numparams(); + + // output each of the parameters + for (int pnum = 0; pnum < inst.numparams(); pnum++) + output_parameter(&dst, &immed, psize[pnum], inst.param(pnum)); + + // point past the end of the immediates + dst += immedwords; + break; + } + } + + // complete codegen + *cachetop = (drccodeptr)dst; + m_cache.end_codegen(); + + // tell all of our utility objects that the block is finished + m_hash.block_end(block); + m_labels.block_end(block); + m_map.block_end(block); +} + + +//------------------------------------------------- +// hash_exists - return true if the given mode/pc +// exists in the hash table +//------------------------------------------------- + +bool drcbe_c::hash_exists(UINT32 mode, UINT32 pc) +{ + return m_hash.code_exists(mode, pc); +} + + +//------------------------------------------------- +// get_info - return information about the +// back-end implementation +//------------------------------------------------- + +void drcbe_c::get_info(drcbe_info &info) +{ + info.direct_iregs = 0; + info.direct_fregs = 0; +} + + +//------------------------------------------------- +// execute - execute a block of code registered +// at the given mode/pc +//------------------------------------------------- + +int drcbe_c::execute(code_handle &entry) +{ + // get the entry point + const drcbec_instruction *inst = (const drcbec_instruction *)entry.codeptr(); + assert_in_cache(m_cache, inst); + + // loop while we have cycles + const drcbec_instruction *callstack[32]; + const drcbec_instruction *newinst; + UINT32 temp32; + UINT64 temp64; + int shift; + UINT8 flags = 0; + UINT8 sp = 0; + while (true) + { + UINT32 opcode = (inst++)->i; + + switch (OPCODE_GET_SHORT(opcode)) + { + // ----------------------- Control Flow Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_HANDLE, 4, 0): // HANDLE handle + case MAKE_OPCODE_SHORT(OP_HASH, 4, 0): // HASH mode,pc + case MAKE_OPCODE_SHORT(OP_LABEL, 4, 0): // LABEL imm + case MAKE_OPCODE_SHORT(OP_COMMENT, 4, 0): // COMMENT string + case MAKE_OPCODE_SHORT(OP_MAPVAR, 4, 0): // MAPVAR mapvar,value + + // these opcodes should be processed at compile-time only + fatalerror("Unexpected opcode"); + break; + + case MAKE_OPCODE_SHORT(OP_DEBUG, 4, 0): // DEBUG pc + debugger_instruction_hook(&m_device, PARAM0); + break; + + case MAKE_OPCODE_SHORT(OP_HASHJMP, 4, 0): // HASHJMP mode,pc,handle + sp = 0; + newinst = (const drcbec_instruction *)m_hash.get_codeptr(PARAM0, PARAM1); + if (newinst == NULL) + { + assert(sp < ARRAY_LENGTH(callstack)); + m_state.exp = PARAM1; + newinst = (const drcbec_instruction *)inst[2].handle->codeptr(); + callstack[sp++] = inst; + } + assert_in_cache(m_cache, newinst); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_EXIT, 4, 1): // EXIT src1[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_EXIT, 4, 0): + return PARAM0; + + case MAKE_OPCODE_SHORT(OP_JMP, 4, 1): // JMP imm[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_JMP, 4, 0): + newinst = inst[0].inst; + assert_in_cache(m_cache, newinst); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_CALLH, 4, 1): // CALLH handle[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_CALLH, 4, 0): + assert(sp < ARRAY_LENGTH(callstack)); + newinst = (const drcbec_instruction *)inst[0].handle->codeptr(); + assert_in_cache(m_cache, newinst); + callstack[sp++] = inst + OPCODE_GET_PWORDS(opcode); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_RET, 4, 1): // RET [c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_RET, 4, 0): + assert(sp > 0); + newinst = callstack[--sp]; + assert_in_cache(m_cache, newinst); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_EXH, 4, 1): // EXH handle,param[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_EXH, 4, 0): + assert(sp < ARRAY_LENGTH(callstack)); + newinst = (const drcbec_instruction *)inst[0].handle->codeptr(); + assert_in_cache(m_cache, newinst); + m_state.exp = PARAM1; + callstack[sp++] = inst; + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_CALLC, 4, 1): // CALLC func,ptr[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_CALLC, 4, 0): + (*inst[0].cfunc)(inst[1].v); + break; + + case MAKE_OPCODE_SHORT(OP_RECOVER, 4, 0): // RECOVER dst,mapvar + assert(sp > 0); + PARAM0 = m_map.get_value((drccodeptr)callstack[0], PARAM1); + break; + + + // ----------------------- Internal Register Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_SETFMOD, 4, 0): // SETFMOD src + m_state.fmod = PARAM0; + break; + + case MAKE_OPCODE_SHORT(OP_GETFMOD, 4, 0): // GETFMOD dst + PARAM0 = m_state.fmod; + break; + + case MAKE_OPCODE_SHORT(OP_GETEXP, 4, 0): // GETEXP dst + PARAM0 = m_state.exp; + break; + + case MAKE_OPCODE_SHORT(OP_GETFLGS, 4, 0): // GETFLGS dst[,f] + PARAM0 = flags & PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SAVE, 4, 0): // SAVE dst + *inst[0].state = m_state; + inst[0].state->flags = flags; + break; + + case MAKE_OPCODE_SHORT(OP_RESTORE, 4, 0): // RESTORE dst + case MAKE_OPCODE_SHORT(OP_RESTORE, 4, 1): // RESTORE dst + m_state = *inst[0].state; + flags = inst[0].state->flags; + break; + + + // ----------------------- 32-Bit Integer Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_LOAD1, 4, 0): // LOAD dst,base,index,BYTE + PARAM0 = inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x2, 4, 0): // LOAD dst,base,index,BYTE_x2 + PARAM0 = *(UINT8 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x4, 4, 0): // LOAD dst,base,index,BYTE_x4 + PARAM0 = *(UINT8 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x8, 4, 0): // LOAD dst,base,index,BYTE_x8 + PARAM0 = *(UINT8 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x1, 4, 0): // LOAD dst,base,index,WORD_x1 + PARAM0 = *(UINT16 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2, 4, 0): // LOAD dst,base,index,WORD + PARAM0 = inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x4, 4, 0): // LOAD dst,base,index,WORD_x4 + PARAM0 = *(UINT16 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x8, 4, 0): // LOAD dst,base,index,WORD_x8 + PARAM0 = *(UINT16 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x1, 4, 0): // LOAD dst,base,index,DWORD_x1 + PARAM0 = *(UINT32 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x2, 4, 0): // LOAD dst,base,index,DWORD_x2 + PARAM0 = *(UINT32 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4, 4, 0): // LOAD dst,base,index,DWORD + PARAM0 = inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x8, 4, 0): // LOAD dst,base,index,DWORD_x8 + PARAM0 = *(UINT32 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1, 4, 0): // LOADS dst,base,index,BYTE + PARAM0 = inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x2, 4, 0): // LOADS dst,base,index,BYTE_x2 + PARAM0 = *(INT8 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x4, 4, 0): // LOADS dst,base,index,BYTE_x4 + PARAM0 = *(INT8 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x8, 4, 0): // LOADS dst,base,index,BYTE_x8 + PARAM0 = *(INT8 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x1, 4, 0): // LOADS dst,base,index,WORD_x1 + PARAM0 = *(INT16 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2, 4, 0): // LOADS dst,base,index,WORD + PARAM0 = inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x4, 4, 0): // LOADS dst,base,index,WORD_x4 + PARAM0 = *(INT16 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x8, 4, 0): // LOADS dst,base,index,WORD_x8 + PARAM0 = *(INT16 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x1, 4, 0): // LOADS dst,base,index,DWORD_x1 + PARAM0 = *(INT32 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x2, 4, 0): // LOADS dst,base,index,DWORD_x2 + PARAM0 = *(INT32 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4, 4, 0): // LOADS dst,base,index,DWORD + PARAM0 = inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x8, 4, 0): // LOADS dst,base,index,DWORD_x8 + PARAM0 = *(INT32 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1, 4, 0): // STORE dst,base,index,BYTE + inst[0].puint8[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x2, 4, 0): // STORE dst,base,index,BYTE_x2 + *(UINT8 *)&inst[0].puint16[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x4, 4, 0): // STORE dst,base,index,BYTE_x4 + *(UINT8 *)&inst[0].puint32[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x8, 4, 0): // STORE dst,base,index,BYTE_x8 + *(UINT8 *)&inst[0].puint64[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x1, 4, 0): // STORE dst,base,index,WORD_x1 + *(UINT16 *)&inst[0].puint8[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2, 4, 0): // STORE dst,base,index,WORD + inst[0].puint16[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x4, 4, 0): // STORE dst,base,index,WORD_x4 + *(UINT16 *)&inst[0].puint32[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x8, 4, 0): // STORE dst,base,index,WORD_x8 + *(UINT16 *)&inst[0].puint64[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x1, 4, 0): // STORE dst,base,index,DWORD_x1 + *(UINT32 *)&inst[0].puint8[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x2, 4, 0): // STORE dst,base,index,DWORD_x2 + *(UINT32 *)&inst[0].puint16[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4, 4, 0): // STORE dst,base,index,DWORD + inst[0].puint32[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x8, 4, 0): // STORE dst,base,index,DWORD_x8 + *(UINT32 *)&inst[0].puint64[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_READ1, 4, 0): // READ dst,src1,space_BYTE + PARAM0 = m_space[PARAM2]->read_byte(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ2, 4, 0): // READ dst,src1,space_WORD + PARAM0 = m_space[PARAM2]->read_word(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ4, 4, 0): // READ dst,src1,space_DWORD + PARAM0 = m_space[PARAM2]->read_dword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READM2, 4, 0): // READM dst,src1,mask,space_WORD + PARAM0 = m_space[PARAM3]->read_word(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_READM4, 4, 0): // READM dst,src1,mask,space_DWORD + PARAM0 = m_space[PARAM3]->read_dword(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE1, 4, 0): // WRITE dst,src1,space_BYTE + m_space[PARAM2]->write_byte(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE2, 4, 0): // WRITE dst,src1,space_WORD + m_space[PARAM2]->write_word(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE4, 4, 0): // WRITE dst,src1,space_DWORD + m_space[PARAM2]->write_dword(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM2, 4, 0): // WRITEM dst,src1,mask,space_WORD + m_space[PARAM3]->write_word(PARAM0, PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM4, 4, 0): // WRITEM dst,src1,mask,space_DWORD + m_space[PARAM3]->write_dword(PARAM0, PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_CARRY, 4, 1): // CARRY src,bitnum + flags = (flags & ~FLAG_C) | ((PARAM0 >> (PARAM1 & 31)) & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_MOV, 4, 1): // MOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_MOV, 4, 0): + PARAM0 = PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SET, 4, 1): // SET dst,c + PARAM0 = OPCODE_FAIL_CONDITION(opcode, flags) ? 0 : 1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 4, 0): // SEXT1 dst,src + PARAM0 = (INT8)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 4, 1): + temp32 = (INT8)PARAM1; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 4, 0): // SEXT2 dst,src + PARAM0 = (INT16)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 4, 1): + temp32 = (INT16)PARAM1; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 4, 0): // ROLAND dst,src,count,mask[,f] + shift = PARAM2 & 31; + PARAM0 = ((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 4, 1): + shift = PARAM2 & 31; + temp32 = ((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 4, 0): // ROLINS dst,src,count,mask[,f] + shift = PARAM2 & 31; + PARAM0 = (PARAM0 & ~PARAM3) | (((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3); + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 4, 1): + shift = PARAM2 & 31; + temp32 = (PARAM0 & ~PARAM3) | (((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3); + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 4, 0): // ADD dst,src1,src2[,f] + PARAM0 = PARAM1 + PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 4, 1): + temp32 = PARAM1 + PARAM2; + flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 4, 0): // ADDC dst,src1,src2[,f] + PARAM0 = PARAM1 + PARAM2 + (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 4, 1): + temp32 = PARAM1 + PARAM2 + (flags & FLAG_C); + if (PARAM2 + 1 != 0) + flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2 + (flags & FLAG_C)); + else + flags = FLAGS32_NZCV_ADD(temp32, PARAM1 + (flags & FLAG_C), PARAM2); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 4, 0): // SUB dst,src1,src2[,f] + PARAM0 = PARAM1 - PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 4, 1): + temp32 = PARAM1 - PARAM2; + flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 4, 0): // SUBB dst,src1,src2[,f] + PARAM0 = PARAM1 - PARAM2 - (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 4, 1): + temp32 = PARAM1 - PARAM2 - (flags & FLAG_C); + if (PARAM2 + 1 != 0) + flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2 + (flags & FLAG_C)); + else + flags = FLAGS32_NZCV_SUB(temp32, PARAM1 - (flags & FLAG_C), PARAM2); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_CMP, 4, 1): // CMP src1,src2[,f] + temp32 = PARAM0 - PARAM1; + flags = FLAGS32_NZCV_SUB(temp32, PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 4, 0): // MULU dst,edst,src1,src2[,f] + temp64 = (UINT64)(UINT32)PARAM2 * (UINT64)(UINT32)PARAM3; + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 4, 1): + temp64 = (UINT64)(UINT32)PARAM2 * (UINT64)(UINT32)PARAM3; + flags = FLAGS64_NZ(temp64); + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + if (temp64 != (UINT32)temp64) + flags |= FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 4, 0): // MULS dst,edst,src1,src2[,f] + temp64 = (INT64)(INT32)PARAM2 * (INT64)(INT32)PARAM3; + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 4, 1): + temp64 = (INT64)(INT32)PARAM2 * (INT64)(INT32)PARAM3; + flags = FLAGS64_NZ(temp64); + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + if (temp64 != (INT32)temp64) + flags |= FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 4, 0): // DIVU dst,edst,src1,src2[,f] + if (PARAM3 != 0) + { + temp32 = (UINT32)PARAM2 / (UINT32)PARAM3; + PARAM1 = (UINT32)PARAM2 % (UINT32)PARAM3; + PARAM0 = temp32; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 4, 1): + if (PARAM3 != 0) + { + temp32 = (UINT32)PARAM2 / (UINT32)PARAM3; + PARAM1 = (UINT32)PARAM2 % (UINT32)PARAM3; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 4, 0): // DIVS dst,edst,src1,src2[,f] + if (PARAM3 != 0) + { + temp32 = (INT32)PARAM2 / (INT32)PARAM3; + PARAM1 = (INT32)PARAM2 % (INT32)PARAM3; + PARAM0 = temp32; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 4, 1): + if (PARAM3 != 0) + { + temp32 = (INT32)PARAM2 / (INT32)PARAM3; + PARAM1 = (INT32)PARAM2 % (INT32)PARAM3; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 4, 0): // AND dst,src1,src2[,f] + PARAM0 = PARAM1 & PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 4, 1): + temp32 = PARAM1 & PARAM2; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_TEST, 4, 1): // TEST src1,src2[,f] + temp32 = PARAM0 & PARAM1; + flags = FLAGS32_NZ(temp32); + break; + + case MAKE_OPCODE_SHORT(OP_OR, 4, 0): // OR dst,src1,src2[,f] + PARAM0 = PARAM1 | PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_OR, 4, 1): + temp32 = PARAM1 | PARAM2; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 4, 0): // XOR dst,src1,src2[,f] + PARAM0 = PARAM1 ^ PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 4, 1): + temp32 = PARAM1 ^ PARAM2; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 4, 0): // LZCNT dst,src + PARAM0 = count_leading_zeros(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 4, 1): + temp32 = count_leading_zeros(PARAM1); + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 4, 0): // BSWAP dst,src + temp32 = PARAM1; + PARAM0 = FLIPENDIAN_INT32(temp32); + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 4, 1): + temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); + PARAM0 = FLIPENDIAN_INT32(temp32); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 4, 0): // SHL dst,src,count[,f] + PARAM0 = PARAM1 << (PARAM2 & 31); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 4, 1): + shift = PARAM2 & 31; + temp32 = PARAM1 << shift; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 4, 0): // SHR dst,src,count[,f] + PARAM0 = PARAM1 >> (PARAM2 & 31); + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 4, 1): + shift = PARAM2 & 31; + temp32 = PARAM1 >> shift; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 4, 0): // SAR dst,src,count[,f] + PARAM0 = (INT32)PARAM1 >> (PARAM2 & 31); + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 4, 1): + shift = PARAM2 & 31; + temp32 = (INT32)PARAM1 >> shift; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 4, 0): // ROL dst,src,count[,f] + shift = PARAM2 & 31; + PARAM0 = (PARAM1 << shift) | (PARAM1 >> ((32 - shift) & 31)); + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 4, 1): + shift = PARAM2 & 31; + temp32 = (PARAM1 << shift) | (PARAM1 >> ((32 - shift) & 31)); + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 4, 0): // ROLC dst,src,count[,f] + shift = PARAM2 & 31; + if (shift > 1) + PARAM0 = (PARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift)); + else if (shift == 1) + PARAM0 = (PARAM1 << shift) | (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 4, 1): + shift = PARAM2 & 31; + if (shift > 1) + temp32 = (PARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift)); + else if (shift == 1) + temp32 = (PARAM1 << shift) | (flags & FLAG_C); + else + temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 4, 0): // ROR dst,src,count[,f] + shift = PARAM2 & 31; + PARAM0 = (PARAM1 >> shift) | (PARAM1 << ((32 - shift) & 31)); + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 4, 1): + shift = PARAM2 & 31; + temp32 = (PARAM1 >> shift) | (PARAM1 << ((32 - shift) & 31)); + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 4, 0): // RORC dst,src,count[,f] + shift = PARAM2 & 31; + if (shift > 1) + PARAM0 = (PARAM1 >> shift) | (((flags & FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift)); + else if (shift == 1) + PARAM0 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31); + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 4, 1): + shift = PARAM2 & 31; + if (shift > 1) + temp32 = (PARAM1 >> shift) | (((flags & FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift)); + else if (shift == 1) + temp32 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31); + else + temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + PARAM0 = temp32; + break; + + + // ----------------------- 64-Bit Integer Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_LOAD1, 8, 0): // DLOAD dst,base,index,BYTE + DPARAM0 = inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x2, 8, 0): // DLOAD dst,base,index,BYTE_x2 + DPARAM0 = *(UINT8 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x4, 8, 0): // DLOAD dst,base,index,BYTE_x4 + DPARAM0 = *(UINT8 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x8, 8, 0): // DLOAD dst,base,index,BYTE_x8 + DPARAM0 = *(UINT8 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x1, 8, 0): // DLOAD dst,base,index,WORD_x1 + DPARAM0 = *(UINT16 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2, 8, 0): // DLOAD dst,base,index,WORD + DPARAM0 = inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x4, 8, 0): // DLOAD dst,base,index,WORD_x4 + DPARAM0 = *(UINT16 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x8, 8, 0): // DLOAD dst,base,index,WORD_x8 + DPARAM0 = *(UINT16 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x1, 8, 0): // DLOAD dst,base,index,DWORD_x1 + DPARAM0 = *(UINT32 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x2, 8, 0): // DLOAD dst,base,index,DWORD_x2 + DPARAM0 = *(UINT32 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4, 8, 0): // DLOAD dst,base,index,DWORD + DPARAM0 = inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x8, 8, 0): // DLOAD dst,base,index,DWORD_x8 + DPARAM0 = *(UINT32 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8x1, 8, 0): // DLOAD dst,base,index,QWORD_x1 + DPARAM0 = *(UINT64 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8x2, 8, 0): // DLOAD dst,base,index,QWORD_x2 + DPARAM0 = *(UINT64 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8x4, 8, 0): // DLOAD dst,base,index,QWORD_x4 + DPARAM0 = *(UINT64 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8, 8, 0): // DLOAD dst,base,index,QWORD + DPARAM0 = inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1, 8, 0): // DLOADS dst,base,index,BYTE + DPARAM0 = inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x2, 8, 0): // DLOADS dst,base,index,BYTE_x2 + DPARAM0 = *(INT8 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x4, 8, 0): // DLOADS dst,base,index,BYTE_x4 + DPARAM0 = *(INT8 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x8, 8, 0): // DLOADS dst,base,index,BYTE_x8 + DPARAM0 = *(INT8 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x1, 8, 0): // DLOADS dst,base,index,WORD_x1 + DPARAM0 = *(INT16 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2, 8, 0): // DLOADS dst,base,index,WORD + DPARAM0 = inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x4, 8, 0): // DLOADS dst,base,index,WORD_x4 + DPARAM0 = *(INT16 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x8, 8, 0): // DLOADS dst,base,index,WORD_x8 + DPARAM0 = *(INT16 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x1, 8, 0): // DLOADS dst,base,index,DWORD_x1 + DPARAM0 = *(INT32 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x2, 8, 0): // DLOADS dst,base,index,DWORD_x2 + DPARAM0 = *(INT32 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4, 8, 0): // DLOADS dst,base,index,DWORD + DPARAM0 = inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x8, 8, 0): // DLOADS dst,base,index,DWORD_x8 + DPARAM0 = *(INT32 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8x1, 8, 0): // DLOADS dst,base,index,QWORD_x1 + DPARAM0 = *(INT64 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8x2, 8, 0): // DLOADS dst,base,index,QWORD_x2 + DPARAM0 = *(INT64 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8x4, 8, 0): // DLOADS dst,base,index,QWORD_x4 + DPARAM0 = *(INT64 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8, 8, 0): // DLOADS dst,base,index,QWORD + DPARAM0 = inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1, 8, 0): // DSTORE dst,base,index,BYTE + inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x2, 8, 0): // DSTORE dst,base,index,BYTE_x2 + *(UINT8 *)&inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x4, 8, 0): // DSTORE dst,base,index,BYTE_x4 + *(UINT8 *)&inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x8, 8, 0): // DSTORE dst,base,index,BYTE_x8 + *(UINT8 *)&inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x1, 8, 0): // DSTORE dst,base,index,WORD_x1 + *(UINT16 *)&inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2, 8, 0): // DSTORE dst,base,index,WORD + inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x4, 8, 0): // DSTORE dst,base,index,WORD_x4 + *(UINT16 *)&inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x8, 8, 0): // DSTORE dst,base,index,WORD_x8 + *(UINT16 *)&inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x1, 8, 0): // DSTORE dst,base,index,DWORD_x1 + *(UINT32 *)&inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x2, 8, 0): // DSTORE dst,base,index,DWORD_x2 + *(UINT32 *)&inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4, 8, 0): // DSTORE dst,base,index,DWORD + inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x8, 8, 0): // DSTORE dst,base,index,DWORD_x8 + *(UINT32 *)&inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8x1, 8, 0): // DSTORE dst,base,index,QWORD_x1 + *(UINT64 *)&inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8x2, 8, 0): // DSTORE dst,base,index,QWORD_x2 + *(UINT64 *)&inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8x4, 8, 0): // DSTORE dst,base,index,QWORD_x4 + *(UINT64 *)&inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8, 8, 0): // DSTORE dst,base,index,QWORD + inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_READ1, 8, 0): // DREAD dst,src1,space_BYTE + DPARAM0 = m_space[PARAM2]->read_byte(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ2, 8, 0): // DREAD dst,src1,space_WORD + DPARAM0 = m_space[PARAM2]->read_word(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ4, 8, 0): // DREAD dst,src1,space_DWORD + DPARAM0 = m_space[PARAM2]->read_dword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ8, 8, 0): // DREAD dst,src1,space_QOWRD + DPARAM0 = m_space[PARAM2]->read_qword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READM2, 8, 0): // DREADM dst,src1,mask,space_WORD + DPARAM0 = m_space[PARAM3]->read_word(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_READM4, 8, 0): // DREADM dst,src1,mask,space_DWORD + DPARAM0 = m_space[PARAM3]->read_dword(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_READM8, 8, 0): // DREADM dst,src1,mask,space_QWORD + DPARAM0 = m_space[PARAM3]->read_qword(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE1, 8, 0): // DWRITE dst,src1,space_BYTE + m_space[PARAM2]->write_byte(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE2, 8, 0): // DWRITE dst,src1,space_WORD + m_space[PARAM2]->write_word(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE4, 8, 0): // DWRITE dst,src1,space_DWORD + m_space[PARAM2]->write_dword(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE8, 8, 0): // DWRITE dst,src1,space_QWORD + m_space[PARAM2]->write_qword(PARAM0, DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM2, 8, 0): // DWRITEM dst,src1,mask,space_WORD + m_space[PARAM3]->write_word(PARAM0, DPARAM1, DPARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM4, 8, 0): // DWRITEM dst,src1,mask,space_DWORD + m_space[PARAM3]->write_dword(PARAM0, DPARAM1, DPARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM8, 8, 0): // DWRITEM dst,src1,mask,space_QWORD + m_space[PARAM3]->write_qword(PARAM0, DPARAM1, DPARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_CARRY, 8, 0): // DCARRY src,bitnum + flags = (flags & ~FLAG_C) | ((DPARAM0 >> (DPARAM1 & 63)) & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_MOV, 8, 1): // DMOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_MOV, 8, 0): + DPARAM0 = DPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SET, 8, 1): // DSET dst,c + DPARAM0 = OPCODE_FAIL_CONDITION(opcode, flags) ? 0 : 1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 8, 0): // DSEXT dst,src,BYTE + DPARAM0 = (INT8)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 8, 1): + temp64 = (INT8)PARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 8, 0): // DSEXT dst,src,WORD + DPARAM0 = (INT16)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 8, 1): + temp64 = (INT16)PARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT4, 8, 0): // DSEXT dst,src,DWORD + DPARAM0 = (INT32)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT4, 8, 1): + temp64 = (INT32)PARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 8, 0): // DROLAND dst,src,count,mask[,f] + shift = DPARAM2 & 63; + DPARAM0 = ((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 8, 1): + shift = DPARAM2 & 63; + temp64 = ((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 8, 0): // DROLINS dst,src,count,mask[,f] + shift = DPARAM2 & 63; + DPARAM0 = (DPARAM0 & ~DPARAM3) | (((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3); + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 8, 1): + shift = DPARAM2 & 63; + temp64 = (DPARAM0 & ~DPARAM3) | (((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3); + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 8, 0): // DADD dst,src1,src2[,f] + DPARAM0 = DPARAM1 + DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 8, 1): + temp64 = DPARAM1 + DPARAM2; + flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 8, 0): // DADDC dst,src1,src2[,f] + DPARAM0 = DPARAM1 + DPARAM2 + (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 8, 1): + temp64 = DPARAM1 + DPARAM2 + (flags & FLAG_C); + if (DPARAM2 + 1 != 0) + flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2 + (flags & FLAG_C)); + else + flags = FLAGS64_NZCV_ADD(temp64, DPARAM1 + (flags & FLAG_C), DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 8, 0): // DSUB dst,src1,src2[,f] + DPARAM0 = DPARAM1 - DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 8, 1): + temp64 = DPARAM1 - DPARAM2; + flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 8, 0): // DSUBB dst,src1,src2[,f] + DPARAM0 = DPARAM1 - DPARAM2 - (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 8, 1): + temp64 = DPARAM1 - DPARAM2 - (flags & FLAG_C); + if (DPARAM2 + 1 != 0) + flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2 + (flags & FLAG_C)); + else + flags = FLAGS64_NZCV_SUB(temp64, DPARAM1 - (flags & FLAG_C), DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_CMP, 8, 1): // DCMP src1,src2[,f] + temp64 = DPARAM0 - DPARAM1; + flags = FLAGS64_NZCV_SUB(temp64, DPARAM0, DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 8, 0): // DMULU dst,edst,src1,src2[,f] + dmulu(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, FALSE); + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 8, 1): + flags = dmulu(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, TRUE); + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 8, 0): // DMULS dst,edst,src1,src2[,f] + dmuls(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, FALSE); + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 8, 1): + flags = dmuls(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, TRUE); + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 8, 0): // DDIVU dst,edst,src1,src2[,f] + if (DPARAM3 != 0) + { + temp64 = (UINT64)DPARAM2 / (UINT64)DPARAM3; + DPARAM1 = (UINT64)DPARAM2 % (UINT64)DPARAM3; + DPARAM0 = temp64; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 8, 1): + if (DPARAM3 != 0) + { + temp64 = (UINT64)DPARAM2 / (UINT64)DPARAM3; + DPARAM1 = (UINT64)DPARAM2 % (UINT64)DPARAM3; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 8, 0): // DDIVS dst,edst,src1,src2[,f] + if (DPARAM3 != 0) + { + temp64 = (INT64)DPARAM2 / (INT64)DPARAM3; + DPARAM1 = (INT64)DPARAM2 % (INT64)DPARAM3; + DPARAM0 = temp64; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 8, 1): + if (DPARAM3 != 0) + { + temp64 = (INT64)DPARAM2 / (INT64)DPARAM3; + DPARAM1 = (INT64)DPARAM2 % (INT64)DPARAM3; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 8, 0): // DAND dst,src1,src2[,f] + DPARAM0 = DPARAM1 & DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 8, 1): + temp64 = DPARAM1 & DPARAM2; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_TEST, 8, 1): // DTEST src1,src2[,f] + temp64 = DPARAM1 & DPARAM2; + flags = FLAGS64_NZ(temp64); + break; + + case MAKE_OPCODE_SHORT(OP_OR, 8, 0): // DOR dst,src1,src2[,f] + DPARAM0 = DPARAM1 | DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_OR, 8, 1): + temp64 = DPARAM1 | DPARAM2; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 8, 0): // DXOR dst,src1,src2[,f] + DPARAM0 = DPARAM1 ^ DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 8, 1): + temp64 = DPARAM1 ^ DPARAM2; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 8, 0): // DLZCNT dst,src + if ((UINT32)(DPARAM1 >> 32) != 0) + DPARAM0 = count_leading_zeros(DPARAM1 >> 32); + else + DPARAM0 = 32 + count_leading_zeros(DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 8, 1): + if ((UINT32)(DPARAM1 >> 32) != 0) + temp64 = count_leading_zeros(DPARAM1 >> 32); + else + temp64 = 32 + count_leading_zeros(DPARAM1); + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 8, 0): // DBSWAP dst,src + temp64 = DPARAM1; + DPARAM0 = FLIPENDIAN_INT64(temp64); + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 8, 1): + temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = FLIPENDIAN_INT64(temp64); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 8, 0): // DSHL dst,src,count[,f] + DPARAM0 = DPARAM1 << (DPARAM2 & 63); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 8, 1): + shift = DPARAM2 & 63; + temp64 = DPARAM1 << shift; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 8, 0): // DSHR dst,src,count[,f] + DPARAM0 = DPARAM1 >> (DPARAM2 & 63); + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 8, 1): + shift = DPARAM2 & 63; + temp64 = DPARAM1 >> shift; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 8, 0): // DSAR dst,src,count[,f] + DPARAM0 = (INT64)DPARAM1 >> (DPARAM2 & 63); + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 8, 1): + shift = DPARAM2 & 63; + temp64 = (INT32)DPARAM1 >> shift; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 8, 0): // DROL dst,src,count[,f] + shift = DPARAM2 & 31; + DPARAM0 = (DPARAM1 << shift) | (DPARAM1 >> ((64 - shift) & 63)); + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 8, 1): + shift = DPARAM2 & 63; + temp64 = (DPARAM1 << shift) | (DPARAM1 >> ((64 - shift) & 63)); + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 8, 0): // DROLC dst,src,count[,f] + shift = DPARAM2 & 63; + if (shift > 1) + DPARAM0 = (DPARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift)); + else if (shift == 1) + DPARAM0 = (DPARAM1 << shift) | (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 8, 1): + shift = DPARAM2 & 63; + if (shift > 1) + temp64 = (DPARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift)); + else if (shift == 1) + temp64 = (DPARAM1 << shift) | (flags & FLAG_C); + else + temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 8, 0): // DROR dst,src,count[,f] + shift = DPARAM2 & 63; + DPARAM0 = (DPARAM1 >> shift) | (DPARAM1 << ((64 - shift) & 63)); + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 8, 1): + shift = DPARAM2 & 63; + temp64 = (DPARAM1 >> shift) | (DPARAM1 << ((64 - shift) & 63)); + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 8, 0): // DRORC dst,src,count[,f] + shift = DPARAM2 & 63; + if (shift > 1) + DPARAM0 = (DPARAM1 >> shift) | ((((UINT64)flags & FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift)); + else if (shift == 1) + DPARAM0 = (DPARAM1 >> shift) | (((UINT64)flags & FLAG_C) << 63); + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 8, 1): + shift = DPARAM2 & 63; + if (shift > 1) + temp64 = (DPARAM1 >> shift) | ((((UINT64)flags & FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift)); + else if (shift == 1) + temp64 = (DPARAM1 >> shift) | (((UINT64)flags & FLAG_C) << 63); + else + temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + + // ----------------------- 32-Bit Floating Point Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_FLOAD, 4, 0): // FSLOAD dst,base,index + FSPARAM0 = inst[1].pfloat[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_FSTORE, 4, 0): // FSSTORE dst,base,index + inst[0].pfloat[PARAM1] = FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FREAD, 4, 0): // FSREAD dst,src1,space + PARAM0 = m_space[PARAM2]->read_dword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FWRITE, 4, 0): // FSWRITE dst,src1,space + m_space[PARAM2]->write_dword(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FMOV, 4, 1): // FSMOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_FMOV, 4, 0): + FSPARAM0 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4T, 4, 0): // FSTOI4T dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint32 = floor(FSPARAM1); + else + *inst[0].pint32 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4R, 4, 0): // FSTOI4R dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint32 = floor(FSPARAM1 + 0.5f); + else + *inst[0].pint32 = ceil(FSPARAM1 - 0.5f); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4F, 4, 0): // FSTOI4F dst,src1 + *inst[0].pint32 = floor(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4C, 4, 0): // FSTOI4C dst,src1 + *inst[0].pint32 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4, 4, 0): // FSTOI4 dst,src1 + *inst[0].pint32 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8T, 4, 0): // FSTOI8T dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint64 = floor(FSPARAM1); + else + *inst[0].pint64 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8R, 4, 0): // FSTOI8R dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint64 = floor(FSPARAM1 + 0.5f); + else + *inst[0].pint64 = ceil(FSPARAM1 - 0.5f); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8F, 4, 0): // FSTOI8F dst,src1 + *inst[0].pint64 = floor(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8C, 4, 0): // FSTOI8C dst,src1 + *inst[0].pint64 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8, 4, 0): // FSTOI8 dst,src1 + *inst[0].pint64 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI4, 4, 0): // FSFRI4 dst,src1 + FSPARAM0 = *inst[1].pint32; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI8, 4, 0): // FSFRI8 dst,src1 + FSPARAM0 = *inst[1].pint64; + break; + + case MAKE_OPCODE_SHORT(OP_FFRFD, 4, 0): // FSFRFD dst,src1 + FSPARAM0 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FADD, 4, 0): // FSADD dst,src1,src2 + FSPARAM0 = FSPARAM1 + FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FSUB, 4, 0): // FSSUB dst,src1,src2 + FSPARAM0 = FSPARAM1 - FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FCMP, 4, 1): // FSCMP src1,src2 + if (isnan(FSPARAM0) || isnan(FSPARAM1)) + flags = FLAG_U; + else + flags = (FSPARAM0 < FSPARAM1) | ((FSPARAM0 == FSPARAM1) << 2); + break; + + case MAKE_OPCODE_SHORT(OP_FMUL, 4, 0): // FSMUL dst,src1,src2 + FSPARAM0 = FSPARAM1 * FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FDIV, 4, 0): // FSDIV dst,src1,src2 + FSPARAM0 = FSPARAM1 / FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FNEG, 4, 0): // FSNEG dst,src1 + FSPARAM0 = -FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FABS, 4, 0): // FSABS dst,src1 + FSPARAM0 = fabs(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FSQRT, 4, 0): // FSSQRT dst,src1 + FSPARAM0 = sqrt(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FRECIP, 4, 0): // FSRECIP dst,src1 + FSPARAM0 = 1.0f / FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FRSQRT, 4, 0): // FSRSQRT dst,src1 + FSPARAM0 = 1.0f / sqrt(FSPARAM1); + break; + + + // ----------------------- 64-Bit Floating Point Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_FLOAD, 8, 0): // FDLOAD dst,base,index + FDPARAM0 = inst[1].pdouble[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_FSTORE, 8, 0): // FDSTORE dst,base,index + inst[0].pdouble[PARAM1] = FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FREAD, 8, 0): // FDREAD dst,src1,space + DPARAM0 = m_space[PARAM2]->read_qword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FWRITE, 8, 0): // FDWRITE dst,src1,space + m_space[PARAM2]->write_qword(PARAM0, DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FMOV, 8, 1): // FDMOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_FMOV, 8, 0): + FDPARAM0 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4T, 8, 0): // FDTOI4T dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint32 = floor(FDPARAM1); + else + *inst[0].pint32 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4R, 8, 0): // FDTOI4R dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint32 = floor(FDPARAM1 + 0.5); + else + *inst[0].pint32 = ceil(FDPARAM1 - 0.5); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4F, 8, 0): // FDTOI4F dst,src1 + *inst[0].pint32 = floor(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4C, 8, 0): // FDTOI4C dst,src1 + *inst[0].pint32 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4, 8, 0): // FDTOI4 dst,src1 + *inst[0].pint32 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8T, 8, 0): // FDTOI8T dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint64 = floor(FDPARAM1); + else + *inst[0].pint64 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8R, 8, 0): // FDTOI8R dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint64 = floor(FDPARAM1 + 0.5); + else + *inst[0].pint64 = ceil(FDPARAM1 - 0.5); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8F, 8, 0): // FDTOI8F dst,src1 + *inst[0].pint64 = floor(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8C, 8, 0): // FDTOI8C dst,src1 + *inst[0].pint64 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8, 8, 0): // FDTOI8 dst,src1 + *inst[0].pint64 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI4, 8, 0): // FDFRI4 dst,src1 + FDPARAM0 = *inst[1].pint32; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI8, 8, 0): // FDFRI8 dst,src1 + FDPARAM0 = *inst[1].pint64; + break; + + case MAKE_OPCODE_SHORT(OP_FFRFS, 8, 0): // FDFRFS dst,src1 + FDPARAM0 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FRNDS, 8, 0): // FDRNDS dst,src1 + FDPARAM0 = (float)FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FADD, 8, 0): // FDADD dst,src1,src2 + FDPARAM0 = FDPARAM1 + FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FSUB, 8, 0): // FDSUB dst,src1,src2 + FDPARAM0 = FDPARAM1 - FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FCMP, 8, 1): // FDCMP src1,src2 + if (isnan(FDPARAM0) || isnan(FDPARAM1)) + flags = FLAG_U; + else + flags = (FDPARAM0 < FDPARAM1) | ((FDPARAM0 == FDPARAM1) << 2); + break; + + case MAKE_OPCODE_SHORT(OP_FMUL, 8, 0): // FDMUL dst,src1,src2 + FDPARAM0 = FDPARAM1 * FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FDIV, 8, 0): // FDDIV dst,src1,src2 + FDPARAM0 = FDPARAM1 / FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FNEG, 8, 0): // FDNEG dst,src1 + FDPARAM0 = -FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FABS, 8, 0): // FDABS dst,src1 + FDPARAM0 = fabs(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FSQRT, 8, 0): // FDSQRT dst,src1 + FDPARAM0 = sqrt(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FRECIP, 8, 0): // FDRECIP dst,src1 + FDPARAM0 = 1.0 / FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FRSQRT, 8, 0): // FDRSQRT dst,src1 + FDPARAM0 = 1.0 / sqrt(FDPARAM1); + break; + + default: + fatalerror("Unexpected opcode!"); + break; + } + + // advance past the parameters and immediates + inst += OPCODE_GET_PWORDS(opcode); + } + + return 0; +} + + +//------------------------------------------------- +// output_parameter - output a parameter +//------------------------------------------------- + +void drcbe_c::output_parameter(drcbec_instruction **dstptr, void **immedptr, int size, const parameter ¶m) +{ + drcbec_instruction *dst = *dstptr; + void *immed = *immedptr; + parameter temp_param; + + switch (param.type()) + { + // immediates store a pointer to the immediate data, which is stored at the end of the instruction + case parameter::PTYPE_IMMEDIATE: + if (param.immediate() == 0) + (dst++)->v = &s_immediate_zero; + else + { + (dst++)->v = immed; + if (size == 4) + *(UINT32 *)immed = (UINT32)param.immediate(); + else + *(UINT64 *)immed = (UINT64)param.immediate(); + immed = (UINT8 *)immed + size; + } + break; + + // int registers point to the appropriate part of the integer register state + case parameter::PTYPE_INT_REGISTER: + if (size == 4) + (dst++)->puint32 = &m_state.r[param.ireg() - REG_I0].w.l; + else + (dst++)->puint64 = &m_state.r[param.ireg() - REG_I0].d; + break; + + // float registers point to the appropriate part of the floating point register state + case parameter::PTYPE_FLOAT_REGISTER: + if (size == 4) + (dst++)->pfloat = &m_state.f[param.freg() - REG_F0].s.l; + else + (dst++)->pdouble = &m_state.f[param.freg() - REG_F0].d; + break; + + // convert mapvars to immediates + case parameter::PTYPE_MAPVAR: + temp_param = m_map.get_last_value(param.mapvar()); + return output_parameter(dstptr, immedptr, size, temp_param); + + // memory just points to the memory + case parameter::PTYPE_MEMORY: + (dst++)->v = param.memory(); + break; + + // ignore these parameters: they are directly encoded in the opcode + case parameter::PTYPE_SIZE: + case parameter::PTYPE_SIZE_SCALE: + case parameter::PTYPE_ROUNDING: + case parameter::PTYPE_STRING: + return output_parameter(dstptr, immedptr, size, 0); + + // space/size parameters; sizes are built into our opcodes, but space needs to be encoded + case parameter::PTYPE_SIZE_SPACE: + return output_parameter(dstptr, immedptr, size, param.space()); + + // code handle just points to the handle + case parameter::PTYPE_CODE_HANDLE: + (dst++)->handle = ¶m.handle(); + break; + + // code label just contains the label value + case parameter::PTYPE_CODE_LABEL: + return output_parameter(dstptr, immedptr, size, UINT32(param.label())); + + // c_function just points to the C function + case parameter::PTYPE_C_FUNCTION: + (dst++)->cfunc = param.cfunc(); + break; + + default: + fatalerror("Unexpected param->type"); + break; + } + + *dstptr = dst; + *immedptr = immed; +} + + +//------------------------------------------------- +// fixup_label - callback to fixup forward- +// referenced labels +//------------------------------------------------- + +void drcbe_c::fixup_label(void *parameter, drccodeptr labelcodeptr) +{ + drcbec_instruction *dst = (drcbec_instruction *)parameter; + dst->inst = (drcbec_instruction *)labelcodeptr; +} + + +//------------------------------------------------- +// dmulu - perform a double-wide unsigned multiply +//------------------------------------------------- + +int drcbe_c::dmulu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2, int flags) +{ + // shortcut if we don't care about the high bits or the flags + if (&dstlo == &dsthi && flags == 0) + { + dstlo = src1 * src2; + return 0; + } + + // fetch source values + UINT64 a = src1; + UINT64 b = src2; + if (a == 0 || b == 0) + { + dsthi = dstlo = 0; + return FLAG_Z; + } + + // compute high and low parts first + UINT64 lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0); + UINT64 hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32); + + // compute middle parts + UINT64 prevlo = lo; + UINT64 temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + // store the results + dsthi = hi; + dstlo = lo; + return ((hi >> 60) & FLAG_S) | ((dsthi != 0) << 1); +} + + +//------------------------------------------------- +// dmuls - perform a double-wide signed multiply +//------------------------------------------------- + +int drcbe_c::dmuls(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2, int flags) +{ + // shortcut if we don't care about the high bits or the flags + if (&dstlo == &dsthi && flags == 0) + { + dstlo = src1 * src2; + return 0; + } + + // fetch absolute source values + UINT64 a = src1; if ((INT64)a < 0) a = -a; + UINT64 b = src2; if ((INT64)b < 0) b = -b; + if (a == 0 || b == 0) + { + dsthi = dstlo = 0; + return FLAG_Z; + } + + // compute high and low parts first + UINT64 lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0); + UINT64 hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32); + + // compute middle parts + UINT64 prevlo = lo; + UINT64 temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + // adjust for signage + if ((INT64)(src1 ^ src2) < 0) + { + hi = ~hi + (lo == 0); + lo = ~lo + 1; + } + + // store the results + dsthi = hi; + dstlo = lo; + return ((hi >> 60) & FLAG_S) | ((dsthi != ((INT64)lo >> 63)) << 1); +} |