Fixed various recompiler issues and added functionality: (#13108)

* cpu/uml.cpp: Added BREAK, SETFLGS, MULSLW and MULULW opcodes.
* cpu/uml.cpp: Limit range of immediate shift count arguments for consistency.
* cpu/uml.cpp: Fix simplification of multiplication and division operations.
* cpu/drcbec.cpp: Added more methods of accessing OP_CARRY.
* cpu/drcbec.cpp: Fixed flag calculation for BSWAP and MULS opcodes.
* cpu/drcbec.cpp: Made calculation for shift and rotation opcodes consistent.
* cpu/drcbec.cpp: Return mapvar register ID instead of value for mapvars.
* cpu/drcbex64.cpp, cpu/drcbex86.cpp: Fixed bugs in various opcodes to make them behave like the C backend.
* cpu/drcbex64.cpp: Fixed SAVE, RESTORE and SETFMOD.
* cpu/powerpc: Implement MULLWx and MULLWOx using the new MULSLW opcode.
This commit is contained in:
987123879113 2024-12-29 00:09:16 +09:00 committed by GitHub
parent ea130bcb8e
commit 2a0ae18957
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 1761 additions and 892 deletions

View File

@ -181,6 +181,7 @@ enum
// compute C and V flags for 32-bit add/subtract
#define FLAGS32_C_ADD(a,b) ((uint32_t)~(a) < (uint32_t)(b))
#define FLAGS32_C_SUB(a,b) ((uint32_t)(b) > (uint32_t)(a))
#define FLAGS32_C_SUBC(a,b,c) (((uint32_t)(c) != 0 && ((uint32_t)(b) + (uint32_t)(c)) == 0) || (uint32_t)(b) + (uint32_t)(c) > (uint32_t)(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)
@ -188,10 +189,12 @@ enum
#define FLAGS32_NZ(v) ((((v) >> 28) & FLAG_S) | (((uint32_t)(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))
#define FLAGS32_NZCV_SUBC(r,a,b,c) (FLAGS32_NZ(r) | FLAGS32_C_SUBC(a,b,c) | FLAGS32_V_SUB(r,a,b))
// compute C and V flags for 64-bit add/subtract
#define FLAGS64_C_ADD(a,b) ((uint64_t)~(a) < (uint64_t)(b))
#define FLAGS64_C_SUB(a,b) ((uint64_t)(b) > (uint64_t)(a))
#define FLAGS64_C_SUBC(a,b,c) (((uint64_t)(c) != 0 && ((uint64_t)(b) + (uint64_t)(c)) == 0) || (uint64_t)(b) + (uint64_t)(c) > (uint64_t)(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)
@ -199,6 +202,7 @@ enum
#define FLAGS64_NZ(v) ((((v) >> 60) & FLAG_S) | (((uint64_t)(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))
#define FLAGS64_NZCV_SUBC(r,a,b,c) (FLAGS64_NZ(r) | FLAGS64_C_SUBC(a,b,c) | FLAGS64_V_SUB(r,a,b))
@ -359,9 +363,10 @@ void drcbe_c::generate(drcuml_block &block, const instruction *instlist, uint32_
m_labels.set_codeptr(inst.param(0).label(), (drccodeptr)dst);
break;
// ignore COMMENT and NOP opcodes
// ignore COMMENT, NOP, and BREAK opcodes
case OP_COMMENT:
case OP_NOP:
case OP_BREAK:
break;
// when we hit a MAPVAR opcode, log the change for the current PC
@ -518,6 +523,10 @@ int drcbe_c::execute(code_handle &entry)
// these opcodes should be processed at compile-time only
fatalerror("Unexpected opcode\n");
case MAKE_OPCODE_SHORT(OP_BREAK, 4, 0):
osd_break_into_debugger("break from drc");
break;
case MAKE_OPCODE_SHORT(OP_DEBUG, 4, 0): // DEBUG pc
if (m_device.machine().debug_flags & DEBUG_FLAG_CALL_HOOK)
m_device.debug()->instruction_hook(PARAM0);
@ -628,6 +637,11 @@ int drcbe_c::execute(code_handle &entry)
PARAM0 = flags & PARAM1;
break;
case MAKE_OPCODE_SHORT(OP_SETFLGS, 4, 0): // SETFLGS src
case MAKE_OPCODE_SHORT(OP_SETFLGS, 4, 1):
flags = PARAM0;
break;
case MAKE_OPCODE_SHORT(OP_SAVE, 4, 0): // SAVE dst
*inst[0].state = m_state;
inst[0].state->flags = flags;
@ -826,7 +840,8 @@ int drcbe_c::execute(code_handle &entry)
m_space[PARAM3]->write_dword(PARAM0, PARAM1, PARAM2);
break;
case MAKE_OPCODE_SHORT(OP_CARRY, 4, 1): // CARRY src,bitnum
case MAKE_OPCODE_SHORT(OP_CARRY, 4, 0): // CARRY src,bitnum
case MAKE_OPCODE_SHORT(OP_CARRY, 4, 1):
flags = (flags & ~FLAG_C) | ((PARAM0 >> (PARAM1 & 31)) & FLAG_C);
break;
@ -930,16 +945,7 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_SUBB, 4, 1):
temp32 = PARAM1 - PARAM2 - (flags & FLAG_C);
temp64 = (uint64_t)PARAM1 - (uint64_t)PARAM2 - (uint64_t)(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);
flags &= ~(FLAG_C | FLAG_V);
flags |= ((temp64>>32) & 1) ? FLAG_C : 0;
flags |= (((PARAM1) ^ (PARAM2)) & ((PARAM1) ^ (temp64)) & 0x80000000) ? FLAG_V : 0;
}
flags = FLAGS32_NZCV_SUBC(temp32, PARAM1, PARAM2, flags & FLAG_C);
PARAM0 = temp32;
break;
@ -964,6 +970,20 @@ int drcbe_c::execute(code_handle &entry)
flags |= FLAG_V;
break;
case MAKE_OPCODE_SHORT(OP_MULULW, 4, 0): // MULULW dst,src1,src2[,f]
temp64 = mulu_32x32(PARAM1, PARAM2);
PARAM0 = (uint32_t)temp64;
break;
case MAKE_OPCODE_SHORT(OP_MULULW, 4, 1):
temp64 = mulu_32x32(PARAM1, PARAM2);
temp32 = (uint32_t)temp64;
flags = FLAGS32_NZ(temp32);
PARAM0 = temp32;
if (temp64 > temp32)
flags |= FLAG_V;
break;
case MAKE_OPCODE_SHORT(OP_MULS, 4, 0): // MULS dst,edst,src1,src2[,f]
temp64 = mul_32x32(PARAM2, PARAM3);
PARAM1 = temp64 >> 32;
@ -972,11 +992,24 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_MULS, 4, 1):
temp64 = mul_32x32(PARAM2, PARAM3);
temp32 = (int32_t)temp64;
flags = FLAGS32_NZ(temp32);
flags = FLAGS64_NZ(temp64);
PARAM1 = temp64 >> 32;
PARAM0 = (uint32_t)temp64;
if (temp64 != (int32_t)temp64)
if ((int64_t)temp64 != (int32_t)temp64)
flags |= FLAG_V;
break;
case MAKE_OPCODE_SHORT(OP_MULSLW, 4, 0): // MULSLW dst,src1,src2[,f]
temp64 = mul_32x32(PARAM1, PARAM2);
PARAM0 = (int32_t)temp64;
break;
case MAKE_OPCODE_SHORT(OP_MULSLW, 4, 1):
temp64 = mul_32x32(PARAM1, PARAM2);
temp32 = (int32_t)temp64;
flags = FLAGS32_NZ(temp32);
PARAM0 = temp32;
if ((int64_t)temp64 != (int32_t)temp64)
flags |= FLAG_V;
break;
@ -1084,8 +1117,8 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_BSWAP, 4, 1):
temp32 = PARAM1;
flags = FLAGS32_NZ(temp32);
PARAM0 = swapendian_int32(temp32);
flags = FLAGS32_NZ(PARAM0);
break;
case MAKE_OPCODE_SHORT(OP_SHL, 4, 0): // SHL dst,src,count[,f]
@ -1154,6 +1187,8 @@ int drcbe_c::execute(code_handle &entry)
PARAM0 = (PARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift));
else if (shift == 1)
PARAM0 = (PARAM1 << shift) | (flags & FLAG_C);
else
PARAM0 = PARAM1;
break;
case MAKE_OPCODE_SHORT(OP_ROLC, 4, 1):
@ -1164,8 +1199,11 @@ int drcbe_c::execute(code_handle &entry)
temp32 = (PARAM1 << shift) | (flags & FLAG_C);
else
temp32 = PARAM1;
flags = FLAGS32_NZ(temp32);
if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C;
if (shift != 0)
{
flags = FLAGS32_NZ(temp32);
flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C;
}
PARAM0 = temp32;
break;
@ -1176,8 +1214,11 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_ROR, 4, 1):
shift = PARAM2 & 31;
temp32 = rotr_32(PARAM1, shift);
flags = FLAGS32_NZ(temp32);
if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C;
if (shift != 0)
{
flags = FLAGS32_NZ(temp32);
flags |= (PARAM1 >> (shift - 1)) & FLAG_C;
}
PARAM0 = temp32;
break;
@ -1187,6 +1228,8 @@ int drcbe_c::execute(code_handle &entry)
PARAM0 = (PARAM1 >> shift) | (((flags & FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift));
else if (shift == 1)
PARAM0 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31);
else
PARAM0 = PARAM1;
break;
case MAKE_OPCODE_SHORT(OP_RORC, 4, 1):
@ -1197,8 +1240,11 @@ int drcbe_c::execute(code_handle &entry)
temp32 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31);
else
temp32 = PARAM1;
flags = FLAGS32_NZ(temp32);
if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C;
if (shift != 0)
{
flags = FLAGS32_NZ(temp32);
flags |= (PARAM1 >> (shift - 1)) & FLAG_C;
}
PARAM0 = temp32;
break;
@ -1454,6 +1500,7 @@ int drcbe_c::execute(code_handle &entry)
break;
case MAKE_OPCODE_SHORT(OP_CARRY, 8, 0): // DCARRY src,bitnum
case MAKE_OPCODE_SHORT(OP_CARRY, 8, 1):
flags = (flags & ~FLAG_C) | ((DPARAM0 >> (DPARAM1 & 63)) & FLAG_C);
break;
@ -1559,10 +1606,7 @@ int drcbe_c::execute(code_handle &entry)
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);
flags = FLAGS64_NZCV_SUBC(temp64, DPARAM1, DPARAM2, flags & FLAG_C);
DPARAM0 = temp64;
break;
@ -1579,6 +1623,15 @@ int drcbe_c::execute(code_handle &entry)
flags = dmulu(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, true);
break;
case MAKE_OPCODE_SHORT(OP_MULULW, 8, 0): // DMULULW dst,src1,src2[,f]
dmulu(*inst[0].puint64, *inst[0].puint64, DPARAM1, DPARAM2, false);
break;
case MAKE_OPCODE_SHORT(OP_MULULW, 8, 1):
flags = dmulu(*inst[0].puint64, *inst[0].puint64, DPARAM1, DPARAM2, true);
flags = FLAGS64_NZ(DPARAM0) | (flags & FLAG_V);
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;
@ -1587,6 +1640,15 @@ int drcbe_c::execute(code_handle &entry)
flags = dmuls(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, true);
break;
case MAKE_OPCODE_SHORT(OP_MULSLW, 8, 0): // DMULSLW dst,src1,src2[,f]
dmuls(*inst[0].puint64, *inst[0].puint64, DPARAM1, DPARAM2, false);
break;
case MAKE_OPCODE_SHORT(OP_MULSLW, 8, 1):
flags = dmuls(*inst[0].puint64, *inst[0].puint64, DPARAM1, DPARAM2, true);
flags = FLAGS64_NZ(DPARAM0) | (flags & FLAG_V);
break;
case MAKE_OPCODE_SHORT(OP_DIVU, 8, 0): // DDIVU dst,edst,src1,src2[,f]
if (DPARAM3 != 0)
{
@ -1691,8 +1753,8 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_BSWAP, 8, 1):
temp64 = DPARAM1;
flags = FLAGS64_NZ(temp64);
DPARAM0 = swapendian_int64(temp64);
flags = FLAGS64_NZ(DPARAM0);
break;
case MAKE_OPCODE_SHORT(OP_SHL, 8, 0): // DSHL dst,src,count[,f]
@ -1702,8 +1764,11 @@ int drcbe_c::execute(code_handle &entry)
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;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -1714,8 +1779,11 @@ int drcbe_c::execute(code_handle &entry)
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;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -1725,9 +1793,12 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_SAR, 8, 1):
shift = DPARAM2 & 63;
temp64 = (int32_t)DPARAM1 >> shift;
flags = FLAGS64_NZ(temp64);
if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
temp64 = (int64_t)DPARAM1 >> shift;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -1738,8 +1809,11 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_ROL, 8, 1):
shift = DPARAM2 & 63;
temp64 = rotl_64(DPARAM1, shift);
flags = FLAGS64_NZ(temp64);
if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -1749,6 +1823,8 @@ int drcbe_c::execute(code_handle &entry)
DPARAM0 = (DPARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift));
else if (shift == 1)
DPARAM0 = (DPARAM1 << shift) | (flags & FLAG_C);
else
DPARAM0 = DPARAM1;
break;
case MAKE_OPCODE_SHORT(OP_ROLC, 8, 1):
@ -1759,8 +1835,11 @@ int drcbe_c::execute(code_handle &entry)
temp64 = (DPARAM1 << shift) | (flags & FLAG_C);
else
temp64 = DPARAM1;
flags = FLAGS64_NZ(temp64);
if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -1771,8 +1850,11 @@ int drcbe_c::execute(code_handle &entry)
case MAKE_OPCODE_SHORT(OP_ROR, 8, 1):
shift = DPARAM2 & 63;
temp64 = rotr_64(DPARAM1, shift);
flags = FLAGS64_NZ(temp64);
if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -1782,6 +1864,8 @@ int drcbe_c::execute(code_handle &entry)
DPARAM0 = (DPARAM1 >> shift) | ((((uint64_t)flags & FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift));
else if (shift == 1)
DPARAM0 = (DPARAM1 >> shift) | (((uint64_t)flags & FLAG_C) << 63);
else
DPARAM0 = DPARAM1;
break;
case MAKE_OPCODE_SHORT(OP_RORC, 8, 1):
@ -1792,8 +1876,11 @@ int drcbe_c::execute(code_handle &entry)
temp64 = (DPARAM1 >> shift) | (((uint64_t)flags & FLAG_C) << 63);
else
temp64 = DPARAM1;
flags = FLAGS64_NZ(temp64);
if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
if (shift != 0)
{
flags = FLAGS64_NZ(temp64);
flags |= (DPARAM1 >> (shift - 1)) & FLAG_C;
}
DPARAM0 = temp64;
break;
@ -2108,7 +2195,6 @@ void drcbe_c::output_parameter(drcbec_instruction **dstptr, void **immedptr, int
{
drcbec_instruction *dst = *dstptr;
void *immed = *immedptr;
parameter temp_param;
switch (param.type())
{
@ -2145,8 +2231,7 @@ void drcbe_c::output_parameter(drcbec_instruction **dstptr, void **immedptr, int
// 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);
return output_parameter(dstptr, immedptr, size, param.mapvar());
// memory just points to the memory
case parameter::PTYPE_MEMORY:
@ -2239,7 +2324,7 @@ int drcbe_c::dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src
// store the results
dsthi = hi;
dstlo = lo;
return ((hi >> 60) & FLAG_S) | ((dsthi != 0) << 1);
return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1);
}
@ -2290,7 +2375,7 @@ int drcbe_c::dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2,
// store the results
dsthi = hi;
dstlo = lo;
return ((hi >> 60) & FLAG_S) | ((dsthi != ((int64_t)lo >> 63)) << 1);
return ((hi >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1);
}
uint32_t drcbe_c::tzcount32(uint32_t value)

File diff suppressed because it is too large Load Diff

View File

@ -135,6 +135,7 @@ private:
void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
@ -149,6 +150,7 @@ private:
void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
@ -171,7 +173,9 @@ private:
void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
@ -208,7 +212,7 @@ private:
// alu and shift operation helpers
static bool ones(u64 const value, unsigned const size) noexcept { return (size == 4) ? u32(value) == 0xffffffffU : value == 0xffffffff'ffffffffULL; }
void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize = [](asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; });
void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param);
void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, bool update_flags);
// parameter helpers
void mov_reg_param(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param, bool const keepflags = false);
@ -225,6 +229,10 @@ private:
void movsd_r128_p64(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
void movsd_p64_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
void calculate_status_flags(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::Operand const &dst, u8 flags);
void calculate_status_flags_mul(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi);
void calculate_status_flags_mul_low(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo);
size_t emit(asmjit::CodeHolder &ch);
// internal state

File diff suppressed because it is too large Load Diff

View File

@ -117,6 +117,7 @@ private:
asmjit::x86::Mem MABS(void const *base, u32 const size = 0) const { return asmjit::x86::Mem(u64(base), size); }
void normalize_commutative(be_parameter &inner, be_parameter &outer);
void emit_combine_z_flags(asmjit::x86::Assembler &a);
void emit_combine_zs_flags(asmjit::x86::Assembler &a);
void emit_combine_z_shl_flags(asmjit::x86::Assembler &a);
void reset_last_upper_lower_reg();
void set_last_lower_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo);
@ -134,6 +135,7 @@ private:
void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
@ -148,6 +150,7 @@ private:
void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
@ -170,7 +173,9 @@ private:
void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
@ -217,7 +222,7 @@ private:
void emit_mov_p32_r32(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize = [](asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; });
void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize);
void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize, bool update_flags);
// 64-bit code emission helpers
void emit_mov_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
@ -246,11 +251,13 @@ private:
void emit_fstp_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
// callback helpers
static int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags);
static int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags);
static int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags, bool halfmul_flags);
static int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags, bool halfmul_flags);
static int ddivu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2);
static int ddivs(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2);
void calculate_status_flags(asmjit::x86::Assembler &a, asmjit::Operand const &dst, u8 flags);
size_t emit(asmjit::CodeHolder &ch);
// internal state

View File

@ -29,6 +29,7 @@
/* ----- Control Flow Operations ----- */
#define UML_NOP(block) do { using namespace uml; block.append().nop(); } while (0)
#define UML_BREAK(block) do { using namespace uml; block.append().break_(); } while (0)
#define UML_DEBUG(block, pc) do { using namespace uml; block.append().debug(pc); } while (0)
#define UML_EXIT(block, param) do { using namespace uml; block.append().exit(param); } while (0)
#define UML_EXITc(block, cond, param) do { using namespace uml; block.append().exit(param, cond); } while (0)
@ -53,6 +54,7 @@
#define UML_GETFMOD(block, dst) do { using namespace uml; block.append().getfmod(dst); } while (0)
#define UML_GETEXP(block, dst) do { using namespace uml; block.append().getexp(dst); } while (0)
#define UML_GETFLGS(block, dst, flags) do { using namespace uml; block.append().getflgs(dst, flags); } while (0)
#define UML_SETFLGS(block, flags) do { using namespace uml; block.append().setflgs(flags); } while (0)
#define UML_SAVE(block, dst) do { using namespace uml; block.append().save(dst); } while (0)
#define UML_RESTORE(block, src) do { using namespace uml; block.append().restore(src); } while (0)
@ -78,7 +80,9 @@
#define UML_SUBB(block, dst, src1, src2) do { using namespace uml; block.append().subb(dst, src1, src2); } while (0)
#define UML_CMP(block, src1, src2) do { using namespace uml; block.append().cmp(src1, src2); } while (0)
#define UML_MULU(block, dst, edst, src1, src2) do { using namespace uml; block.append().mulu(dst, edst, src1, src2); } while (0)
#define UML_MULULW(block, dst, src1, src2) do { using namespace uml; block.append().mululw(dst, src1, src2); } while (0)
#define UML_MULS(block, dst, edst, src1, src2) do { using namespace uml; block.append().muls(dst, edst, src1, src2); } while (0)
#define UML_MULSLW(block, dst, src1, src2) do { using namespace uml; block.append().mulslw(dst, src1, src2); } while (0)
#define UML_DIVU(block, dst, edst, src1, src2) do { using namespace uml; block.append().divu(dst, edst, src1, src2); } while (0)
#define UML_DIVS(block, dst, edst, src1, src2) do { using namespace uml; block.append().divs(dst, edst, src1, src2); } while (0)
#define UML_AND(block, dst, src1, src2) do { using namespace uml; block.append()._and(dst, src1, src2); } while (0)
@ -118,7 +122,9 @@
#define UML_DSUBB(block, dst, src1, src2) do { using namespace uml; block.append().dsubb(dst, src1, src2); } while (0)
#define UML_DCMP(block, src1, src2) do { using namespace uml; block.append().dcmp(src1, src2); } while (0)
#define UML_DMULU(block, dst, edst, src1, src2) do { using namespace uml; block.append().dmulu(dst, edst, src1, src2); } while (0)
#define UML_DMULULW(block, dst, src1, src2) do { using namespace uml; block.append().dmululw(dst, src1, src2); } while (0)
#define UML_DMULS(block, dst, edst, src1, src2) do { using namespace uml; block.append().dmuls(dst, edst, src1, src2); } while (0)
#define UML_DMULSLW(block, dst, src1, src2) do { using namespace uml; block.append().dmulslw(dst, src1, src2); } while (0)
#define UML_DDIVU(block, dst, edst, src1, src2) do { using namespace uml; block.append().ddivu(dst, edst, src1, src2); } while (0)
#define UML_DDIVS(block, dst, edst, src1, src2) do { using namespace uml; block.append().ddivs(dst, edst, src1, src2); } while (0)
#define UML_DAND(block, dst, src1, src2) do { using namespace uml; block.append().dand(dst, src1, src2); } while (0)

View File

@ -2681,7 +2681,9 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co
case 0x0eb: /* MULLWx */
case 0x2eb: /* MULLWOx */
UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // muls rd,rd,ra,rb
// The flags are calculated based on the resulting 32-bit value from the 32x32=32 multiplication
// reference: example 4 https://www.ibm.com/docs/en/aix/7.2?topic=set-mullw-muls-multiply-low-word-instruction
UML_MULSLW(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // mulslw rd,ra,rb
generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), false);// <update flags>
return true;

View File

@ -137,45 +137,49 @@ opcode_info const instruction::s_opcode_info_table[OP_MAX] =
// Control Flow Operations
OPINFO0(NOP, "nop", 4, false, NONE, NONE, NONE)
OPINFO1(DEBUG, "debug", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY))
OPINFO1(DEBUG, "debug", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY)) // MAME debugger breakpoint
OPINFO0(BREAK, "break", 4, false, NONE, NONE, NONE) // (for debugging) Issues a breakpoint exception to allow for debugging the generated assembly
OPINFO1(EXIT, "exit", 4, true, NONE, NONE, ALL, PINFO(IN, OP, IANY))
OPINFO3(HASHJMP, "hashjmp", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, HANDLE))
OPINFO1(JMP, "jmp", 4, true, NONE, NONE, NONE, PINFO(IN, OP, LABEL))
OPINFO2(EXH, "exh", 4, true, NONE, NONE, ALL, PINFO(IN, OP, HANDLE), PINFO(IN, OP, IANY))
OPINFO1(CALLH, "callh", 4, true, NONE, NONE, ALL, PINFO(IN, OP, HANDLE))
OPINFO2(EXH, "exh", 4, true, NONE, NONE, ALL, PINFO(IN, OP, HANDLE), PINFO(IN, OP, IANY)) // Call exception handler
OPINFO1(CALLH, "callh", 4, true, NONE, NONE, ALL, PINFO(IN, OP, HANDLE)) // Call handle
OPINFO0(RET, "ret", 4, true, NONE, NONE, ALL)
OPINFO2(CALLC, "callc", 4, true, NONE, NONE, ALL, PINFO(IN, OP, CFUNC), PINFO(IN, OP, PTR))
OPINFO2(RECOVER, "recover", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, MVAR))
OPINFO2(CALLC, "callc", 4, true, NONE, NONE, ALL, PINFO(IN, OP, CFUNC), PINFO(IN, OP, PTR)) // Call C function
OPINFO2(RECOVER, "recover", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, MVAR)) // Get value from mapvar
// Internal Register Operations
OPINFO1(SETFMOD, "setfmod", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY))
OPINFO1(GETFMOD, "getfmod", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM))
OPINFO1(GETEXP, "getexp", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM))
OPINFO2(GETFLGS, "getflgs", 4, false, P2, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IMV))
OPINFO1(SAVE, "save", 4, false, ALL, NONE, ALL, PINFO(OUT, OP, STATE))
OPINFO1(RESTORE, "restore", 4, false, NONE, ALL, ALL, PINFO(IN, OP, STATE))
OPINFO1(SETFMOD, "setfmod", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY)) // Set floating point control mode
OPINFO1(GETFMOD, "getfmod", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM)) // Get floating point control mode
OPINFO1(GETEXP, "getexp", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM)) // Get exception parameter value
OPINFO2(GETFLGS, "getflgs", 4, false, P2, NONE, NONE, PINFO(OUT, OP, IRM), PINFO(IN, OP, IMV)) // Get status register flags
OPINFO1(SETFLGS, "setflgs", 4, false, NONE, ALL, ALL, PINFO(IN, OP, IANY)) // (for debugging) Set status register flags
OPINFO1(SAVE, "save", 4, false, ALL, NONE, ALL, PINFO(OUT, OP, STATE)) // Save current state to drcuml_machine_state
OPINFO1(RESTORE, "restore", 4, false, NONE, ALL, ALL, PINFO(IN, OP, STATE)) // Load saved state from drcuml_machine_state
// Integer Operations
OPINFO4(LOAD, "!load", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, SCSIZE))
OPINFO4(LOADS, "!loads", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, SCSIZE))
OPINFO4(STORE, "!store", 4|8, false, NONE, NONE, ALL, PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SCSIZE))
OPINFO3(READ, "!read", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, 4, IANY), PINFO(IN, OP, SPSIZE))
OPINFO4(READM, "!readm", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE))
OPINFO3(WRITE, "!write", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE))
OPINFO4(WRITEM, "!writem", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE))
OPINFO2(CARRY, "!carry", 4|8, false, NONE, C, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO1(SET, "!set", 4|8, true, NONE, NONE, ALL, PINFO(OUT, OP, IRM))
OPINFO4(LOAD, "!load", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, SCSIZE)) // Load unsigned value from specified memory location
OPINFO4(LOADS, "!loads", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, SCSIZE)) // Load signed value from specified memory location
OPINFO4(STORE, "!store", 4|8, false, NONE, NONE, ALL, PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SCSIZE)) // Store value to specified memory location
OPINFO3(READ, "!read", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, 4, IANY), PINFO(IN, OP, SPSIZE)) // Read memory from emulated machine using memory space reader
OPINFO4(READM, "!readm", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE)) // Read memory from emulated machine using memory space reader (masked)
OPINFO3(WRITE, "!write", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE)) // Write to emulated machine's memory using memory space writer
OPINFO4(WRITEM, "!writem", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE)) // Write to emulated machine's memory using memory space writer (masked)
OPINFO2(CARRY, "!carry", 4|8, false, NONE, C, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Set carry status flag on CPU
OPINFO1(SET, "!set", 4|8, true, NONE, NONE, ALL, PINFO(OUT, OP, IRM)) // Get the state of the specified condition (e.g. calling UML_SET with COND_NZ will return 0 if the condition is not met and 1 if the condition is met)
OPINFO2(MOV, "!mov", 4|8, true, NONE, NONE, NONE, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY))
OPINFO3(SEXT, "!sext", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, P3, IANY), PINFO(IN, OP, SIZE))
OPINFO4(ROLAND, "!roland", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO4(ROLINS, "!rolins", 4|8, false, NONE, SZ, ALL, PINFO(INOUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO4(ROLAND, "!roland", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Rotate left + AND (see drcbec.cpp for implementation)
OPINFO4(ROLINS, "!rolins", 4|8, false, NONE, SZ, ALL, PINFO(INOUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Rotate left + OR (see drcbec.cpp for implementation)
OPINFO3(ADD, "!add", 4|8, false, NONE, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO3(ADDC, "!addc", 4|8, false, C, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO3(SUB, "!sub", 4|8, false, NONE, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO3(SUBB, "!subb", 4|8, false, C, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO2(CMP, "!cmp", 4|8, false, NONE, SZVC, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO4(MULU, "!mulu", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO4(MULS, "!muls", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO4(MULU, "!mulu", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Unsigned 32x32=64 and 64x64=128 multiplication
OPINFO3(MULULW, "!mululw", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Unsigned 32x32=32 and 64x64=64 multiplication (overflow set based on 32x32=64 calculation but zero and sign based on 32-bit result)
OPINFO4(MULS, "!muls", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Signed 32x32=64 and 64x64=128 multiplication
OPINFO3(MULSLW, "!mulslw", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) // Signed 32x32=32 and 64x64=64 multiplication (overflow set based on 32x32=64 calculation but zero and sign based on 32-bit result)
OPINFO4(DIVU, "!divu", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO4(DIVS, "!divs", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
OPINFO3(AND, "!and", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
@ -194,18 +198,18 @@ opcode_info const instruction::s_opcode_info_table[OP_MAX] =
OPINFO3(RORC, "!rorc", 4|8, false, C, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY))
// Floating Point Operations
OPINFO3(FLOAD, "f#load", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY))
OPINFO3(FSTORE, "f#store", 4|8, false, NONE, NONE, ALL, PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, FRM))
OPINFO3(FREAD, "f#read", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, 4, IANY), PINFO(IN, OP, SPSIZE))
OPINFO3(FWRITE, "f#write", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, FANY), PINFO(IN, OP, SPSIZE))
OPINFO3(FLOAD, "f#load", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY)) // Load float/double value from specified memory location
OPINFO3(FSTORE, "f#store", 4|8, false, NONE, NONE, ALL, PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, FRM)) // Save float/double value to specified memory location
OPINFO3(FREAD, "f#read", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, 4, IANY), PINFO(IN, OP, SPSIZE)) // Read float/double value from emulated machine using memory space reader
OPINFO3(FWRITE, "f#write", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, FANY), PINFO(IN, OP, SPSIZE)) // Write float/double value to emulated machine using memory space writer
OPINFO2(FMOV, "f#mov", 4|8, true, NONE, NONE, NONE, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY))
OPINFO4(FTOINT, "f#toint", 4|8, false, NONE, NONE, ALL, PINFO(OUT, P3, IRM), PINFO(IN, OP, FANY), PINFO(IN, OP, SIZE), PINFO(IN, OP, ROUND))
OPINFO3(FFRINT, "f#frint", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, IANY), PINFO(IN, OP, SIZE))
OPINFO3(FFRFLT, "f#frflt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, FANY), PINFO(IN, OP, SIZE))
OPINFO2(FRNDS, "f#rnds", 8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, FANY))
OPINFO4(FTOINT, "f#toint", 4|8, false, NONE, NONE, ALL, PINFO(OUT, P3, IRM), PINFO(IN, OP, FANY), PINFO(IN, OP, SIZE), PINFO(IN, OP, ROUND)) // Float/double to integer
OPINFO3(FFRINT, "f#frint", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, IANY), PINFO(IN, OP, SIZE)) // Float/double from integer
OPINFO3(FFRFLT, "f#frflt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, FANY), PINFO(IN, OP, SIZE)) // Convert float to double or double to float
OPINFO2(FRNDS, "f#rnds", 8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, FANY)) // Convert double to float and then back to double, or float to double and back to float
OPINFO3(FADD, "f#add", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY))
OPINFO3(FSUB, "f#sub", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY))
OPINFO2(FCMP, "f#cmp", 4|8, false, NONE, UZC, ALL, PINFO(IN, OP, FANY), PINFO(IN, OP, FANY))
OPINFO2(FCMP, "f#cmp", 4|8, false, NONE, UZC, ALL, PINFO(IN, OP, FANY), PINFO(IN, OP, FANY)) // Note: status flags except FLAG_U are undefined when comparing with NaN
OPINFO3(FMUL, "f#mul", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY))
OPINFO3(FDIV, "f#div", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY))
OPINFO2(FNEG, "f#neg", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY))
@ -213,8 +217,8 @@ opcode_info const instruction::s_opcode_info_table[OP_MAX] =
OPINFO2(FSQRT, "f#sqrt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY))
OPINFO2(FRECIP, "f#recip", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY))
OPINFO2(FRSQRT, "f#rsqrt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY))
OPINFO2(FCOPYI, "f#copyi", 4|8, false, NONE, NONE, NONE, PINFO(OUT, OP, FRM), PINFO(IN, OP, IRM))
OPINFO2(ICOPYF, "icopyf#", 4|8, false, NONE, NONE, NONE, PINFO(OUT, OP, IRM), PINFO(IN, OP, FRM))
OPINFO2(FCOPYI, "f#copyi", 4|8, false, NONE, NONE, NONE, PINFO(OUT, OP, FRM), PINFO(IN, OP, IRM)) // Load float/double value from integer representation (e.g. 0x3f800000 -> 1.0f)
OPINFO2(ICOPYF, "icopyf#", 4|8, false, NONE, NONE, NONE, PINFO(OUT, OP, IRM), PINFO(IN, OP, FRM)) // Store float/double value as integer representation (e.g. 1.0f -> 0x3f800000)
};
@ -504,13 +508,26 @@ void uml::instruction::simplify()
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(u32(u32(m_param[1].immediate()) * u32(m_param[2].immediate())));
convert_to_mov_immediate(u32(u32(m_param[2].immediate()) * u32(m_param[3].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(u64(u64(m_param[1].immediate()) * u64(m_param[2].immediate())));
convert_to_mov_immediate(u64(u64(m_param[2].immediate()) * u64(m_param[3].immediate())));
}
}
break;
// MULULW: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULULW:
if (m_param[1].is_immediate_value(0) || m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(u32(u32(m_param[1].immediate()) * u32(m_param[2].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(u64(u64(m_param[1].immediate()) * u64(m_param[2].immediate())));
}
break;
// MULS: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULS:
if (m_param[0] == m_param[1])
@ -520,13 +537,26 @@ void uml::instruction::simplify()
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(s32(s32(m_param[1].immediate()) * s32(m_param[2].immediate())));
convert_to_mov_immediate(s32(s32(m_param[2].immediate()) * s32(m_param[3].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(s64(s64(m_param[1].immediate()) * s64(m_param[2].immediate())));
convert_to_mov_immediate(s64(s64(m_param[2].immediate()) * s64(m_param[3].immediate())));
}
}
break;
// MULSLW: convert simple form to MOV if immediate, or if multiplying by 0
case OP_MULSLW:
if (m_param[1].is_immediate_value(0) || m_param[2].is_immediate_value(0))
convert_to_mov_immediate(0);
else if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(s32(s32(m_param[1].immediate()) * s32(m_param[2].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(s64(s64(m_param[1].immediate()) * s64(m_param[2].immediate())));
}
break;
// DIVU: convert simple form to MOV if immediate, or if dividing with 0
case OP_DIVU:
if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0))
@ -536,9 +566,9 @@ void uml::instruction::simplify()
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(u32(u32(m_param[1].immediate()) / u32(m_param[2].immediate())));
convert_to_mov_immediate(u32(u32(m_param[2].immediate()) / u32(m_param[3].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(u64(u64(m_param[1].immediate()) / u64(m_param[2].immediate())));
convert_to_mov_immediate(u64(u64(m_param[2].immediate()) / u64(m_param[3].immediate())));
}
}
break;
@ -552,9 +582,9 @@ void uml::instruction::simplify()
else if (m_param[2].is_immediate() && m_param[3].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(s32(s32(m_param[1].immediate()) / s32(m_param[2].immediate())));
convert_to_mov_immediate(s32(s32(m_param[2].immediate()) / s32(m_param[3].immediate())));
else if (m_size == 8)
convert_to_mov_immediate(s64(s64(m_param[1].immediate()) / s64(m_param[2].immediate())));
convert_to_mov_immediate(s64(s64(m_param[2].immediate()) / s64(m_param[3].immediate())));
}
}
break;
@ -624,7 +654,12 @@ void uml::instruction::simplify()
// SHL: convert to MOV if immediate or shifting by 0
case OP_SHL:
if (m_param[1].is_immediate() && m_param[2].is_immediate())
convert_to_mov_immediate(m_param[1].immediate() << m_param[2].immediate());
{
if (m_size == 4)
convert_to_mov_immediate(u32(m_param[1].immediate()) << (m_param[2].immediate() & 31));
else if (m_size == 8)
convert_to_mov_immediate(u64(m_param[1].immediate()) << (m_param[2].immediate() & 63));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
break;
@ -634,9 +669,9 @@ void uml::instruction::simplify()
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(u32(m_param[1].immediate()) >> m_param[2].immediate());
convert_to_mov_immediate(u32(m_param[1].immediate()) >> (m_param[2].immediate() & 31));
else if (m_size == 8)
convert_to_mov_immediate(u64(m_param[1].immediate()) >> m_param[2].immediate());
convert_to_mov_immediate(u64(m_param[1].immediate()) >> (m_param[2].immediate() & 63));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
@ -647,9 +682,9 @@ void uml::instruction::simplify()
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(s32(m_param[1].immediate()) >> m_param[2].immediate());
convert_to_mov_immediate(s32(m_param[1].immediate()) >> (m_param[2].immediate() & 31));
else if (m_size == 8)
convert_to_mov_immediate(s64(m_param[1].immediate()) >> m_param[2].immediate());
convert_to_mov_immediate(s64(m_param[1].immediate()) >> (m_param[2].immediate() & 63));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
@ -660,9 +695,9 @@ void uml::instruction::simplify()
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(rotl_32(m_param[1].immediate(), m_param[2].immediate()));
convert_to_mov_immediate(rotl_32(m_param[1].immediate(), m_param[2].immediate() & 31));
else if (m_size == 8)
convert_to_mov_immediate(rotl_64(m_param[1].immediate(), m_param[2].immediate()));
convert_to_mov_immediate(rotl_64(m_param[1].immediate(), m_param[2].immediate() & 63));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);
@ -673,9 +708,9 @@ void uml::instruction::simplify()
if (m_param[1].is_immediate() && m_param[2].is_immediate())
{
if (m_size == 4)
convert_to_mov_immediate(rotr_32(m_param[1].immediate(), m_param[2].immediate()));
convert_to_mov_immediate(rotr_32(m_param[1].immediate(), m_param[2].immediate() & 31));
else if (m_size == 8)
convert_to_mov_immediate(rotr_64(m_param[1].immediate(), m_param[2].immediate()));
convert_to_mov_immediate(rotr_64(m_param[1].immediate(), m_param[2].immediate() & 63));
}
else if (m_param[2].is_immediate_value(0))
convert_to_mov_param(1);

View File

@ -62,16 +62,16 @@ namespace uml
{
COND_ALWAYS = 0,
COND_Z = 0x80, // requires Z
COND_NZ, // requires Z
COND_S, // requires S
COND_NS, // requires S
COND_C, // requires C
COND_NC, // requires C
COND_V, // requires V
COND_NV, // requires V
COND_U, // requires U
COND_NU, // requires U
COND_Z = 0x80, // requires Z (zero/equal)
COND_NZ, // requires Z (not zero/unequal)
COND_S, // requires S (signed)
COND_NS, // requires S (not signed)
COND_C, // requires C (carry)
COND_NC, // requires C (no carry)
COND_V, // requires V (overflow)
COND_NV, // requires V (no overflow)
COND_U, // requires U (unordered)
COND_NU, // requires U (not unordered)
COND_A, // requires CZ, unsigned
COND_BE, // requires CZ, unsigned
COND_G, // requires SVZ, signed
@ -143,6 +143,7 @@ namespace uml
// control flow operations
OP_NOP, // NOP
OP_DEBUG, // DEBUG pc
OP_BREAK, // BREAK
OP_EXIT, // EXIT src1[,c]
OP_HASHJMP, // HASHJMP mode,pc,handle
OP_JMP, // JMP imm[,c]
@ -157,6 +158,7 @@ namespace uml
OP_GETFMOD, // GETFMOD dst
OP_GETEXP, // GETEXP dst
OP_GETFLGS, // GETFLGS dst[,f]
OP_SETFLGS, // SETFLGS src
OP_SAVE, // SAVE mem
OP_RESTORE, // RESTORE mem
@ -180,7 +182,9 @@ namespace uml
OP_SUBB, // SUBB dst,src1,src2[,f]
OP_CMP, // CMP src1,src2[,f]
OP_MULU, // MULU dst,edst,src1,src2[,f]
OP_MULULW, // MULULW dst,src1,src2[,f]
OP_MULS, // MULS dst,edst,src1,src2[,f]
OP_MULSLW, // MULSLW dst,src1,src2[,f]
OP_DIVU, // DIVU dst,edst,src1,src2[,f]
OP_DIVS, // DIVS dst,edst,src1,src2[,f]
OP_AND, // AND dst,src1,src2[,f]
@ -422,6 +426,7 @@ namespace uml
// control flow operations
void nop() { configure(OP_NOP, 4); }
void break_() { configure(OP_BREAK, 4); }
void debug(u32 pc) { configure(OP_DEBUG, 4, pc); }
void exit(parameter param) { configure(OP_EXIT, 4, param); }
void exit(condition_t cond, parameter param) { configure(OP_EXIT, 4, param, cond); }
@ -443,6 +448,7 @@ namespace uml
void getfmod(parameter dst) { configure(OP_GETFMOD, 4, dst); }
void getexp(parameter dst) { configure(OP_GETEXP, 4, dst); }
void getflgs(parameter dst, u32 flags) { configure(OP_GETFLGS, 4, dst, flags); }
void setflgs(u32 flags) { configure(OP_SETFLGS, 4, flags); }
void save(drcuml_machine_state *dst) { configure(OP_SAVE, 4, parameter::make_memory(dst)); }
void restore(drcuml_machine_state *src) { configure(OP_RESTORE, 4, parameter::make_memory(src)); }
@ -467,7 +473,9 @@ namespace uml
void subb(parameter dst, parameter src1, parameter src2) { configure(OP_SUBB, 4, dst, src1, src2); }
void cmp(parameter src1, parameter src2) { configure(OP_CMP, 4, src1, src2); }
void mulu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULU, 4, dst, edst, src1, src2); }
void mululw(parameter dst, parameter src1, parameter src2) { configure(OP_MULULW, 4, dst, src1, src2); }
void muls(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULS, 4, dst, edst, src1, src2); }
void mulslw(parameter dst, parameter src1, parameter src2) { configure(OP_MULSLW, 4, dst, src1, src2); }
void divu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVU, 4, dst, edst, src1, src2); }
void divs(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVS, 4, dst, edst, src1, src2); }
void _and(parameter dst, parameter src1, parameter src2) { configure(OP_AND, 4, dst, src1, src2); }
@ -506,7 +514,9 @@ namespace uml
void dsubb(parameter dst, parameter src1, parameter src2) { configure(OP_SUBB, 8, dst, src1, src2); }
void dcmp(parameter src1, parameter src2) { configure(OP_CMP, 8, src1, src2); }
void dmulu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULU, 8, dst, edst, src1, src2); }
void dmululw(parameter dst, parameter src1, parameter src2) { configure(OP_MULULW, 8, dst, src1, src2); }
void dmuls(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULS, 8, dst, edst, src1, src2); }
void dmulslw(parameter dst, parameter src1, parameter src2) { configure(OP_MULSLW, 8, dst, src1, src2); }
void ddivu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVU, 8, dst, edst, src1, src2); }
void ddivs(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVS, 8, dst, edst, src1, src2); }
void dand(parameter dst, parameter src1, parameter src2) { configure(OP_AND, 8, dst, src1, src2); }