mips3: X64 dynamic recompiler
This commit is contained in:
parent
707e583576
commit
3131b359c4
|
@ -45,6 +45,11 @@ GEN = $$SRC/dep/generated
|
|||
FBA_LD = ld
|
||||
#DEFINES += FBA_DEBUG
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Dynamic recompilers
|
||||
#-------------------------------------------------------------------------------
|
||||
DRC_MIPS3_X64 = true
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Additional include paths
|
||||
#-------------------------------------------------------------------------------
|
||||
|
@ -717,7 +722,8 @@ SOURCES += \
|
|||
../../src/cpu/mips3/cop1.cpp \
|
||||
../../src/cpu/mips3/dasm.cpp \
|
||||
../../src/cpu/mips3/mips3.cpp \
|
||||
../../src/cpu/mips3_intf.cpp
|
||||
../../src/cpu/mips3_intf.cpp \
|
||||
|
||||
|
||||
|
||||
HEADERS += \
|
||||
|
@ -900,7 +906,38 @@ HEADERS += \
|
|||
../../src/cpu/mips3/mips3_rw.h \
|
||||
../../src/cpu/mips3/mips3_shift.h \
|
||||
../../src/cpu/mips3/mipsdef.h \
|
||||
../../src/cpu/mips3_intf.h
|
||||
../../src/cpu/mips3_intf.h \
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# MIPS3 x64 recompiler
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
$$DRC_MIPS3_X64 {
|
||||
message("MIPS3 x64 dynarec enabled")
|
||||
DEFINES += \
|
||||
XBYAK_NO_OP_NAMES \
|
||||
MIPS3_X64_DRC
|
||||
|
||||
HEADERS += \
|
||||
../../src/cpu/mips3/x64/mips3_x64.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_arithm.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_bitops.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_branch.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_cop0.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_cop1.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_defs.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_misc.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_rw.h \
|
||||
../../src/cpu/mips3/x64/mips3_x64_shift.h \
|
||||
../../src/cpu/mips3/x64/xbyak/xbyak.h \
|
||||
../../src/cpu/mips3/x64/xbyak/xbyak_bin2hex.h \
|
||||
../../src/cpu/mips3/x64/xbyak/xbyak_mnemonic.h \
|
||||
../../src/cpu/mips3/x64/xbyak/xbyak_util.h
|
||||
|
||||
SOURCES += \
|
||||
../../src/cpu/mips3/x64/mips3_x64.cpp
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ALIGN_DECL(n) __attribute__ ((aligned (n)))
|
||||
#elif __MSVC__
|
||||
#else
|
||||
#define ALIGN_DECL(n) __declspec(align(n))
|
||||
#endif
|
||||
namespace mips
|
||||
{
|
||||
using namespace std;
|
||||
|
|
|
@ -19,41 +19,7 @@ const char *mips3::cop0_reg_names[32] = {
|
|||
"ECC", "CacheErr", "TagLo", "TagHi", "ErrorEPC", "--"
|
||||
};
|
||||
|
||||
enum {
|
||||
INDEX = 0,
|
||||
RANDOM,
|
||||
ENTRYLO0,
|
||||
ENTRYLO1,
|
||||
CONTEXT,
|
||||
PAGEMASK,
|
||||
WIRED,
|
||||
__COP0_UNUSED0,
|
||||
BADVADDR,
|
||||
COUNT,
|
||||
ENTRYHI,
|
||||
COMPARE,
|
||||
SR,
|
||||
CAUSE,
|
||||
EPC,
|
||||
PRId,
|
||||
CONFIG,
|
||||
LLADDR,
|
||||
WATCHLO,
|
||||
WATCHHI,
|
||||
XCONTEXT,
|
||||
__COP0_UNUSED1,
|
||||
__COP0_UNUSED2,
|
||||
__COP0_UNUSED3,
|
||||
__COP0_UNUSED4,
|
||||
__COP0_UNUSED5,
|
||||
ECC,
|
||||
CACHEERR,
|
||||
TAGLO,
|
||||
TAGHI,
|
||||
ERROREPC
|
||||
} ;
|
||||
|
||||
#define COP0_R(x) m_state.cpr[0][x]
|
||||
#define CR(x) m_state.cpr[0][x]
|
||||
|
||||
void mips3::tlb_init()
|
||||
{
|
||||
|
@ -74,7 +40,9 @@ void mips3::cop0_execute(uint32_t opcode)
|
|||
switch (RSNUM) {
|
||||
// MFC
|
||||
case 0x00:
|
||||
RT = COP0_R(RDNUM & 0x1F);
|
||||
if (RTNUM) {
|
||||
RT = CR(RDNUM);
|
||||
}
|
||||
break;
|
||||
|
||||
// MTC
|
||||
|
@ -84,16 +52,16 @@ void mips3::cop0_execute(uint32_t opcode)
|
|||
|
||||
// TLBWI
|
||||
case 0x10: {
|
||||
unsigned char idx = COP0_R(INDEX);
|
||||
unsigned char idx = CR(COP0_Index);
|
||||
if (idx >= 48) {
|
||||
cout << "TLBWI index > 48" << endl;
|
||||
return;
|
||||
}
|
||||
tlb_entry *e = &m_tlb[idx];
|
||||
e->b.even_lo = COP0_R(ENTRYLO0);
|
||||
e->b.odd_lo = COP0_R(ENTRYLO1);
|
||||
e->b.hi = COP0_R(ENTRYHI);
|
||||
e->b.pagemask = COP0_R(PAGEMASK);
|
||||
e->b.even_lo = CR(COP0_EntryLo0);
|
||||
e->b.odd_lo = CR(COP0_EntryLo1);
|
||||
e->b.hi = CR(COP0_EntryHi);
|
||||
e->b.pagemask = CR(COP0_PageMask);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ const char *mips3::reg_names[32] = {
|
|||
mips3::mips3() : m_tlb_entries(48)
|
||||
{
|
||||
tlb_init();
|
||||
m_state.total_cycles = 0;
|
||||
}
|
||||
|
||||
mips3::~mips3()
|
||||
|
@ -48,6 +49,7 @@ void mips3::reset()
|
|||
cop1_reset();
|
||||
tlb_flush();
|
||||
m_counter = 0;
|
||||
m_state.reset_cycle = m_state.total_cycles;
|
||||
}
|
||||
|
||||
|
||||
|
@ -336,7 +338,7 @@ bool mips3::run(int cycles, bool skip_bps)
|
|||
|
||||
// COP1 (FPU) > TODO
|
||||
case 0x11:
|
||||
if (m_state.cpr[0][12] & (1 << 26))
|
||||
if (m_state.cpr[0][COP0_SR] & (1 << 26))
|
||||
cop1_execute_32(opcode);
|
||||
else
|
||||
cop1_execute_16(opcode);
|
||||
|
@ -414,11 +416,12 @@ bool mips3::run(int cycles, bool skip_bps)
|
|||
}
|
||||
|
||||
// Increment COP0 Count
|
||||
m_state.cpr[0][9] += 20;
|
||||
m_state.cpr[0][COP0_Count] += 20;
|
||||
m_counter++;
|
||||
if (!skip_bps && check_breakpoint())
|
||||
return true;
|
||||
}
|
||||
m_state.total_cycles += m_counter;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,40 @@
|
|||
namespace mips
|
||||
{
|
||||
|
||||
enum COP0_Registers {
|
||||
COP0_Index = 0,
|
||||
COP0_Random,
|
||||
COP0_EntryLo0,
|
||||
COP0_EntryLo1,
|
||||
COP0_Context,
|
||||
COP0_PageMask,
|
||||
COP0_Wired,
|
||||
COP0_Unused0,
|
||||
COP0_BadVAddr,
|
||||
COP0_Count,
|
||||
COP0_EntryHi,
|
||||
COP0_Compare,
|
||||
COP0_SR,
|
||||
COP0_Cause,
|
||||
COP0_EPC,
|
||||
COP0_PRId,
|
||||
COP0_Config,
|
||||
COP0_LLAddr,
|
||||
COP0_WatchLo,
|
||||
COP0_WatchHi,
|
||||
COP0_XContext,
|
||||
COP0_Unused1,
|
||||
COP0_Unused2,
|
||||
COP0_Unused3,
|
||||
COP0_Unused4,
|
||||
COP0_Unused5,
|
||||
COP0_ECC,
|
||||
COP0_CacheErr,
|
||||
COP0_TagLo,
|
||||
COP0_TagHi,
|
||||
COP0_ErrorEPC
|
||||
};
|
||||
|
||||
#ifdef MIPS3_X64_DRC
|
||||
class mips3_x64;
|
||||
#endif
|
||||
|
@ -62,7 +96,10 @@ public:
|
|||
uint64_t cpr[3][32];
|
||||
// fpu control registers (FCR)
|
||||
uint64_t fcr[32];
|
||||
} __attribute__ ((aligned (16))) m_state;
|
||||
uint64_t reset_cycle;
|
||||
uint64_t total_cycles;
|
||||
};
|
||||
ALIGN_DECL(16) cpu_state m_state;
|
||||
addr_t m_prev_pc;
|
||||
|
||||
static const char *reg_names[];
|
||||
|
|
|
@ -0,0 +1,506 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#include <cstdio>
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
#include "../mips3.h"
|
||||
#include "../mipsdef.h"
|
||||
#include "../memory.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64_rw.h"
|
||||
#include "mips3_x64_branch.h"
|
||||
#include "mips3_x64_bitops.h"
|
||||
#include "mips3_x64_arithm.h"
|
||||
#include "mips3_x64_shift.h"
|
||||
#include "mips3_x64_misc.h"
|
||||
#include "mips3_x64_cop0.h"
|
||||
#include "mips3_x64_cop1.h"
|
||||
|
||||
#ifdef HAS_UDIS86
|
||||
#include "udis86/udis86.h"
|
||||
#endif
|
||||
|
||||
#define LOG_DYNAREC 0
|
||||
#define LOG_DYNAREC_DASM 0
|
||||
#define FULL_FALLBACK 0
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
mips3_x64::mips3_x64(mips3 *interpreter) : CodeGenerator(1024 * 1024 * 16)
|
||||
{
|
||||
m_core = interpreter;
|
||||
m_blocks.clear();
|
||||
|
||||
#ifdef HAS_UDIS86
|
||||
ud_init(&m_udobj);
|
||||
ud_set_mode(&m_udobj, 64);
|
||||
ud_set_syntax(&m_udobj, UD_SYN_INTEL);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void *mips3_x64::get_block(addr_t pc)
|
||||
{
|
||||
if (m_blocks.find(pc) == m_blocks.end())
|
||||
return nullptr;
|
||||
return m_blocks[pc];
|
||||
}
|
||||
|
||||
|
||||
void mips3_x64::run(int cycles)
|
||||
{
|
||||
m_icounter = cycles;
|
||||
m_stop_translation = false;
|
||||
m_translate_failed = false;
|
||||
m_is_delay_slot = false;
|
||||
|
||||
void *recompiled_code;
|
||||
while (m_icounter > 0) {
|
||||
recompiled_code = get_block(m_core->m_state.pc);
|
||||
|
||||
if (recompiled_code == nullptr) {
|
||||
try {
|
||||
auto ptr = compile_block(m_core->m_state.pc);
|
||||
if (m_translate_failed)
|
||||
break;
|
||||
|
||||
m_blocks[m_core->m_state.pc] = ptr;
|
||||
recompiled_code = ptr;
|
||||
} catch(Xbyak::Error& e) {
|
||||
// code flush
|
||||
if (e == Xbyak::ERR_CODE_IS_TOO_BIG) {
|
||||
drc_log("Flushing recompiler cache...\n");
|
||||
m_blocks.clear();
|
||||
reset();
|
||||
recompiled_code = nullptr;
|
||||
} else {
|
||||
drc_log("%s", e.what());
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (recompiled_code)
|
||||
Xbyak::CastTo<void(*)()>(recompiled_code)();
|
||||
}
|
||||
|
||||
if (m_translate_failed)
|
||||
drc_log_error("Translation failed at PC: %X", m_drc_pc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mips3_x64::prolog()
|
||||
{
|
||||
// R15 = cycle counter
|
||||
// RBX = cpu_state base
|
||||
push(rbp);
|
||||
push(rbx);
|
||||
push(r15);
|
||||
mov(rbp, rsp);
|
||||
sub(rsp, 16);
|
||||
mov(rbx, ADR(m_core->m_state));
|
||||
mov(r15, ADR(m_icounter));
|
||||
mov(r15, ptr[r15]);
|
||||
|
||||
check_icounter();
|
||||
}
|
||||
|
||||
void mips3_x64::epilog(bool do_ret)
|
||||
{
|
||||
add(rsp, 16);
|
||||
mov(rax, ADR(m_icounter));
|
||||
mov(ptr[rax], r15);
|
||||
pop(r15);
|
||||
pop(rbx);
|
||||
pop(rbp);
|
||||
if (do_ret)
|
||||
ret();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *mips3_x64::compile_block(addr_t pc)
|
||||
{
|
||||
static int depth = 0;
|
||||
m_drc_pc = pc;
|
||||
|
||||
#if LOG_DYNAREC
|
||||
drc_log("Recompile block at %X\n", m_drc_pc);
|
||||
#endif
|
||||
|
||||
uint32_t opcode;
|
||||
addr_t eaddr;
|
||||
bool do_recompile = true;
|
||||
|
||||
void *block_ptr = Xbyak::CastTo<void*>(getCurr());
|
||||
|
||||
prolog();
|
||||
|
||||
m_block_icounter = 0;
|
||||
|
||||
while (do_recompile) {
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
opcode = mem::read_word(eaddr);
|
||||
m_drc_pc += 4;
|
||||
m_block_icounter++;
|
||||
if (compile_instruction(opcode)) {
|
||||
// Jump Instr
|
||||
do_recompile = false;
|
||||
}
|
||||
}
|
||||
|
||||
ready();
|
||||
|
||||
#if LOG_DYNAREC && defined(HAS_UDIS86)
|
||||
if (!depth) {
|
||||
drc_log("=======================================\n");
|
||||
drc_log("Generated code for %x\n", pc);
|
||||
drc_log("=======================================\n");
|
||||
// show recompiled code
|
||||
ud_set_input_buffer(&m_udobj, (unsigned char *) block_ptr,
|
||||
(Xbyak::CastTo<uint8_t*>(getCurr()) - Xbyak::CastTo<uint8_t*>(block_ptr)));
|
||||
ud_set_pc(&m_udobj, (uint64_t) block_ptr);
|
||||
uint64_t dasm_pc = (uint64_t) block_ptr;
|
||||
unsigned k;
|
||||
while ((k = ud_disassemble(&m_udobj))) {
|
||||
drc_log("%08X %s\n", dasm_pc, ud_insn_asm(&m_udobj));
|
||||
dasm_pc += k;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return block_ptr;
|
||||
}
|
||||
|
||||
|
||||
bool mips3_x64::compile_instruction(uint32_t opcode)
|
||||
{
|
||||
#if LOG_DYNAREC_DASM
|
||||
drc_log("%s\n", m_core->dasm(opcode, m_drc_pc - 4).c_str());
|
||||
#endif
|
||||
|
||||
bool result = false;
|
||||
switch (opcode >> 26) {
|
||||
// SPECIAL
|
||||
case 0x00:
|
||||
{
|
||||
switch (opcode & 0x3F) {
|
||||
|
||||
|
||||
#if !FULL_FALLBACK
|
||||
case 0x00: result = SLL(opcode); break;
|
||||
case 0x02: result = SRL(opcode); break;
|
||||
case 0x03: result = SRA(opcode); break;
|
||||
case 0x04: result = SLLV(opcode); break;
|
||||
case 0x06: result = SRLV(opcode); break;
|
||||
case 0x07: result = SRAV(opcode); break;
|
||||
case 0x14: result = DSLLV(opcode); break;
|
||||
case 0x16: result = DSLRV(opcode); break;
|
||||
case 0x17: result = DSRAV(opcode); break;
|
||||
case 0x38: result = DSLL(opcode); break;
|
||||
case 0x3A: result = DSRL(opcode); break;
|
||||
case 0x3B: result = DSRA(opcode); break;
|
||||
case 0x3C: result = DSLL32(opcode); break;
|
||||
case 0x3E: result = DSRL32(opcode); break;
|
||||
case 0x3F: result = DSRA32(opcode); break;
|
||||
|
||||
case 0x10: result = MFHI(opcode); break;
|
||||
case 0x11: result = MTHI(opcode); break;
|
||||
case 0x12: result = MFLO(opcode); break;
|
||||
case 0x13: result = MTLO(opcode); break;
|
||||
|
||||
case 0x18: result = MULT(opcode); break;
|
||||
case 0x19: result = MULTU(opcode); break;
|
||||
case 0x1A: result = DIV(opcode); break;
|
||||
case 0x1B: result = DIVU(opcode); break;
|
||||
case 0x1C: result = DMULT(opcode); break;
|
||||
case 0x1E: result = DDIV(opcode); break;
|
||||
case 0x1F: result = DDIVU(opcode); break;
|
||||
|
||||
case 0x20: result = ADD(opcode); break;
|
||||
case 0x21: result = ADDU(opcode); break;
|
||||
case 0x22: result = SUB(opcode); break;
|
||||
case 0x23: result = SUBU(opcode); break;
|
||||
case 0x2C: result = DADD(opcode); break;
|
||||
case 0x2D: result = DADDU(opcode); break;
|
||||
case 0x2F: result = DSUBU(opcode); break;
|
||||
|
||||
case 0x24: result = AND(opcode); break;
|
||||
case 0x25: result = OR(opcode); break;
|
||||
case 0x26: result = XOR(opcode); break;
|
||||
case 0x27: result = NOR(opcode); break;
|
||||
|
||||
case 0x2A: result = SLT(opcode); break;
|
||||
case 0x2B: result = SLTU(opcode); break;
|
||||
|
||||
#else
|
||||
case 0x00: fallback(opcode, &mips3::SLL); break;
|
||||
case 0x02: fallback(opcode, &mips3::SRL); break;
|
||||
case 0x03: fallback(opcode, &mips3::SRA); break;
|
||||
case 0x04: fallback(opcode, &mips3::SLLV); break;
|
||||
case 0x06: fallback(opcode, &mips3::SRLV); break;
|
||||
case 0x07: fallback(opcode, &mips3::SRAV); break;
|
||||
case 0x14: fallback(opcode, &mips3::DSLLV); break;
|
||||
case 0x16: fallback(opcode, &mips3::DSLRV); break;
|
||||
case 0x38: fallback(opcode, &mips3::DSLL); break;
|
||||
case 0x3A: fallback(opcode, &mips3::DSRL); break;
|
||||
case 0x3B: fallback(opcode, &mips3::DSRA); break;
|
||||
case 0x3C: fallback(opcode, &mips3::DSLL32); break;
|
||||
case 0x3E: fallback(opcode, &mips3::DSRL32); break;
|
||||
case 0x3F: fallback(opcode, &mips3::DSRA32); break;
|
||||
|
||||
case 0x10: fallback(opcode, &mips3::MFHI); break;
|
||||
case 0x11: fallback(opcode, &mips3::MTHI); break;
|
||||
case 0x12: fallback(opcode, &mips3::MFLO); break;
|
||||
case 0x13: fallback(opcode, &mips3::MTLO); break;
|
||||
|
||||
case 0x18: fallback(opcode, &mips3::MULT); break;
|
||||
case 0x19: fallback(opcode, &mips3::MULTU); break;
|
||||
case 0x1A: fallback(opcode, &mips3::DIV); break;
|
||||
case 0x1B: fallback(opcode, &mips3::DIVU); break;
|
||||
case 0x1C: fallback(opcode, &mips3::DMULT); break;
|
||||
case 0x1E: fallback(opcode, &mips3::DDIV); break;
|
||||
case 0x1F: fallback(opcode, &mips3::DDIVU); break;
|
||||
case 0x20: fallback(opcode, &mips3::ADD); break;
|
||||
case 0x21: fallback(opcode, &mips3::ADDU); break;
|
||||
case 0x22: fallback(opcode, &mips3::SUB); break;
|
||||
case 0x23: fallback(opcode, &mips3::SUBU); break;
|
||||
case 0x2D: fallback(opcode, &mips3::DADDU); break;
|
||||
case 0x2F: fallback(opcode, &mips3::DSUBU); break;
|
||||
|
||||
case 0x24: fallback(opcode, &mips3::AND); break;
|
||||
case 0x25: fallback(opcode, &mips3::OR); break;
|
||||
case 0x26: fallback(opcode, &mips3::XOR); break;
|
||||
case 0x27: fallback(opcode, &mips3::NOR); break;
|
||||
|
||||
case 0x2A: fallback(opcode, &mips3::SLT); break;
|
||||
case 0x2B: fallback(opcode, &mips3::SLTU); break;
|
||||
|
||||
#endif
|
||||
|
||||
case 0x08: result = JR(opcode); break;
|
||||
case 0x09: result = JALR(opcode); break;
|
||||
case 0x0C: drc_log("syscall %08X\n", m_drc_pc); break;
|
||||
case 0x0D: drc_log("break %08X\n", m_drc_pc); break;
|
||||
default:
|
||||
drc_log_error("%08X %X [special]\n", m_drc_pc, opcode & 0x3F);
|
||||
translate_failed();
|
||||
result = true;
|
||||
exit(-3);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// REGIMM
|
||||
case 0x01:
|
||||
{
|
||||
switch ((opcode >> 16) & 0x1F) {
|
||||
case 0x00: result = BLTZ(opcode); break;
|
||||
case 0x01: result = BGEZ(opcode); break;
|
||||
case 0x10: result = BLTZAL(opcode); break;
|
||||
case 0x11: result = BGEZAL(opcode); break;
|
||||
default:
|
||||
drc_log_error("%08X %X [regimm]\n", m_drc_pc, (opcode >> 16) & 0x1F);
|
||||
translate_failed();
|
||||
result = true;
|
||||
exit(-3);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x02: result = J(opcode); break;
|
||||
case 0x03: result = JAL(opcode); break;
|
||||
case 0x04: result = BEQ(opcode); break;
|
||||
case 0x05: result = BNE(opcode); break;
|
||||
case 0x06: result = BLEZ(opcode); break;
|
||||
case 0x07: result = BGTZ(opcode); break;
|
||||
|
||||
#if !FULL_FALLBACK
|
||||
case 0x08: result = ADDI(opcode); break;
|
||||
case 0x09: result = ADDIU(opcode); break;
|
||||
case 0x0A: result = SLTI(opcode); break;
|
||||
case 0x0B: result = SLTIU(opcode); break;
|
||||
case 0x0C: result = ANDI(opcode); break;
|
||||
case 0x0D: result = ORI(opcode); break;
|
||||
case 0x0E: result = XORI(opcode); break;
|
||||
case 0x0F: result = LUI(opcode); break;
|
||||
#else
|
||||
case 0x08: fallback(opcode, &mips3::ADDI); break;
|
||||
case 0x09: fallback(opcode, &mips3::ADDIU); break;
|
||||
case 0x0A: fallback(opcode, &mips3::SLTI); break;
|
||||
case 0x0B: fallback(opcode, &mips3::SLTIU); break;
|
||||
case 0x0C: fallback(opcode, &mips3::ANDI); break;
|
||||
case 0x0D: fallback(opcode, &mips3::ORI); break;
|
||||
case 0x0E: fallback(opcode, &mips3::XORI); break;
|
||||
case 0x0F: fallback(opcode, &mips3::LUI); break;
|
||||
#endif
|
||||
case 0x10: result = compile_cop0(opcode); break;
|
||||
#if !FULL_FALLBACK
|
||||
case 0x11: result = compile_cop1(opcode); break;
|
||||
case 0x18: result = DADDI(opcode); break;
|
||||
case 0x19: result = DADDIU(opcode); break;
|
||||
#else
|
||||
case 0x11: fallback(opcode, &mips3::cop1_execute_32); break;
|
||||
case 0x18: fallback(opcode, &mips3::DADDI); break;
|
||||
case 0x19: fallback(opcode, &mips3::DADDIU); break;
|
||||
#endif
|
||||
|
||||
case 0x2F: break;
|
||||
|
||||
// Load & Store fallbacks
|
||||
#if 0 /* !FULL_FALLBACK */ /* Use fallbacks */
|
||||
case 0x20: LB(opcode); break;
|
||||
case 0x24: LBU(opcode); break;
|
||||
case 0x21: LH(opcode); break;
|
||||
case 0x25: LHU(opcode); break;
|
||||
case 0x23: LW(opcode); break;
|
||||
case 0x27: LWU(opcode); break;
|
||||
case 0x37: LD(opcode); break;
|
||||
|
||||
case 0x28: SB(opcode); break;
|
||||
case 0x29: SH(opcode); break;
|
||||
case 0x2B: SW(opcode); break;
|
||||
case 0x3F: SD(opcode); break;
|
||||
|
||||
case 0x22: LWL(opcode); break;
|
||||
case 0x26: LWR(opcode); break;
|
||||
|
||||
case 0x1A: fallback(opcode, &mips3::LDL); break;
|
||||
case 0x1B: fallback(opcode, &mips3::LDR); break;
|
||||
|
||||
case 0x2C: fallback(opcode, &mips3::SDL); break;
|
||||
case 0x2D: fallback(opcode, &mips3::SDR); break;
|
||||
|
||||
case 0x31: fallback(opcode, &mips3::LWC1); break;
|
||||
case 0x39: fallback(opcode, &mips3::SWC1); break;
|
||||
|
||||
#else
|
||||
case 0x20: fallback(opcode, &mips3::LB); break;
|
||||
case 0x24: fallback(opcode, &mips3::LBU); break;
|
||||
case 0x21: fallback(opcode, &mips3::LH); break;
|
||||
case 0x25: fallback(opcode, &mips3::LHU); break;
|
||||
case 0x23: fallback(opcode, &mips3::LW); break;
|
||||
case 0x27: fallback(opcode, &mips3::LWU); break;
|
||||
case 0x37: fallback(opcode, &mips3::LD); break;
|
||||
|
||||
case 0x28: fallback(opcode, &mips3::SB); break;
|
||||
case 0x29: fallback(opcode, &mips3::SH); break;
|
||||
case 0x2B: fallback(opcode, &mips3::SW); break;
|
||||
case 0x3F: fallback(opcode, &mips3::SD); break;
|
||||
|
||||
case 0x22: fallback(opcode, &mips3::LWL); break;
|
||||
case 0x26: fallback(opcode, &mips3::LWR); break;
|
||||
|
||||
case 0x1A: fallback(opcode, &mips3::LDL); break;
|
||||
case 0x1B: fallback(opcode, &mips3::LDR); break;
|
||||
|
||||
case 0x2C: fallback(opcode, &mips3::SDL); break;
|
||||
case 0x2D: fallback(opcode, &mips3::SDR); break;
|
||||
|
||||
case 0x31: fallback(opcode, &mips3::LWC1); break;
|
||||
case 0x39: fallback(opcode, &mips3::SWC1); break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
drc_log_error("%08X Op %X\n", m_drc_pc, opcode >> 26);
|
||||
translate_failed();
|
||||
result = true;
|
||||
exit(-3);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void mips3_x64::check_icounter()
|
||||
{
|
||||
inLocalLabel();
|
||||
cmp(r15, 0);
|
||||
jg(".l");
|
||||
set_next_pc(m_drc_pc);
|
||||
epilog();
|
||||
L(".l");
|
||||
outLocalLabel();
|
||||
}
|
||||
|
||||
bool mips3_x64::cop1_fallback(uint32_t opcode)
|
||||
{
|
||||
inLocalLabel();
|
||||
mov(rax, COP0_x(COP0_SR));
|
||||
|
||||
mov(rcx, 1 << 26);
|
||||
test(rax, rcx);
|
||||
jne(".fr0");
|
||||
fallback(opcode, &mips3::cop1_execute_32);
|
||||
jmp(".end");
|
||||
L(".fr0");
|
||||
fallback(opcode, &mips3::cop1_execute_16);
|
||||
L(".end");
|
||||
|
||||
outLocalLabel();
|
||||
return false;
|
||||
}
|
||||
|
||||
void mips3_x64::set_next_pc(addr_t addr)
|
||||
{
|
||||
mov(PC_q, addr);
|
||||
}
|
||||
|
||||
void mips3_x64::fallback(uint32_t opcode, void (mips3::*f)(uint32_t))
|
||||
{
|
||||
// SysV AMD64 ABI - GNU
|
||||
mov(rdi, (size_t) m_core);
|
||||
mov(esi, opcode);
|
||||
mov(rax, (size_t) (void*)f);
|
||||
call(rax);
|
||||
}
|
||||
|
||||
void mips3_x64::update_icounter()
|
||||
{
|
||||
sub(r15, m_block_icounter);
|
||||
mov(rax, ADR(m_core->m_state.total_cycles));
|
||||
add(qword[rax], m_block_icounter);
|
||||
m_block_icounter = 0;
|
||||
}
|
||||
|
||||
void mips3_x64::jmp_to_block(uint64_t addr)
|
||||
{
|
||||
// Simple block linking
|
||||
void *next_ptr = get_block(addr);
|
||||
if (next_ptr) {
|
||||
#if LOG_DYNAREC
|
||||
drc_log("Block link: %08X to %08X\n", CORE_PC, addr);
|
||||
#endif
|
||||
epilog(false);
|
||||
mov(rax, (size_t) next_ptr);
|
||||
jmp(rax);
|
||||
return;
|
||||
} else {
|
||||
set_next_pc(addr);
|
||||
}
|
||||
epilog();
|
||||
}
|
||||
|
||||
void mips3_x64::jmp_to_register(int reg)
|
||||
{
|
||||
mov(ecx, Rn_x(reg));
|
||||
mov(PC_x, rcx);
|
||||
epilog();
|
||||
}
|
||||
|
||||
void mips3_x64::translate_failed()
|
||||
{
|
||||
m_translate_failed = true;
|
||||
update_icounter();
|
||||
epilog();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64
|
||||
#define MIPS3_X64
|
||||
|
||||
#include <unordered_map>
|
||||
#include "xbyak/xbyak.h"
|
||||
#include "../mips3.h"
|
||||
|
||||
#ifdef HAS_UDIS86
|
||||
#include "udis86/udis86.h"
|
||||
#endif
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
|
||||
class mips3_x64 : public Xbyak::CodeGenerator
|
||||
{
|
||||
public:
|
||||
mips3_x64(mips3 *interpreter);
|
||||
void run(int cycles);
|
||||
|
||||
private:
|
||||
int64_t m_icounter;
|
||||
addr_t m_drc_pc;
|
||||
bool m_is_delay_slot;
|
||||
void run_this(void *ptr);
|
||||
void *compile_block(addr_t pc);
|
||||
void *get_block(addr_t pc);
|
||||
bool compile_special(uint32_t opcode);
|
||||
bool compile_regimm(uint32_t opcode);
|
||||
bool compile_instruction(uint32_t opcode);
|
||||
bool compile_cop0(uint32_t opcode);
|
||||
bool compile_cop1(uint32_t opcode);
|
||||
void check_icounter();
|
||||
bool cop1_fallback(uint32_t opcode);
|
||||
void set_next_pc(addr_t addr);
|
||||
void fallback(uint32_t opcode, void (mips3::*f)(uint32_t));
|
||||
void update_icounter();
|
||||
void jmp_to_block(uint64_t addr);
|
||||
void jmp_to_register(int reg);
|
||||
void translate_failed();
|
||||
void update_cp0_count();
|
||||
void prolog();
|
||||
void epilog(bool do_ret=true);
|
||||
|
||||
uint8_t *m_cache;
|
||||
mips3 *m_core;
|
||||
void *m_current_block;
|
||||
uint64_t m_block_icounter;
|
||||
bool m_translate_failed;
|
||||
bool m_stop_translation;
|
||||
unordered_map<addr_t, void(*)> m_blocks;
|
||||
#ifdef HAS_UDIS86
|
||||
ud_t m_udobj;
|
||||
#endif
|
||||
|
||||
// COP1 branch
|
||||
bool BC1F(uint32_t opcode);
|
||||
bool BC1FL(uint32_t opcode);
|
||||
bool BC1T(uint32_t opcode);
|
||||
bool BC1TL(uint32_t opcode);
|
||||
|
||||
// Arithmetic
|
||||
bool ADD(uint32_t opcode);
|
||||
bool SUB(uint32_t opcode);
|
||||
bool MULT(uint32_t opcode);
|
||||
bool DIV(uint32_t opcode);
|
||||
bool ADDU(uint32_t opcode);
|
||||
bool SUBU(uint32_t opcode);
|
||||
bool MULTU(uint32_t opcode);
|
||||
bool DIVU(uint32_t opcode);
|
||||
|
||||
bool ADDI(uint32_t opcode);
|
||||
bool ADDIU(uint32_t opcode);
|
||||
bool DADDI(uint32_t opcode);
|
||||
bool DADDIU(uint32_t opcode);
|
||||
|
||||
bool DADD(uint32_t opcode);
|
||||
bool DSUB(uint32_t opcode);
|
||||
bool DMULT(uint32_t opcode);
|
||||
bool DDIV(uint32_t opcode);
|
||||
bool DADDU(uint32_t opcode);
|
||||
bool DSUBU(uint32_t opcode);
|
||||
bool DMULTU(uint32_t opcode);
|
||||
bool DDIVU(uint32_t opcode);
|
||||
|
||||
// Bitwise
|
||||
bool AND(uint32_t opcode);
|
||||
bool XOR(uint32_t opcode);
|
||||
bool OR(uint32_t opcode);
|
||||
bool NOR(uint32_t opcode);
|
||||
bool ANDI(uint32_t opcode);
|
||||
bool XORI(uint32_t opcode);
|
||||
bool ORI(uint32_t opcode);
|
||||
|
||||
// Shifts
|
||||
bool SLL(uint32_t opcode);
|
||||
bool SRL(uint32_t opcode);
|
||||
bool SRA(uint32_t opcode);
|
||||
bool SLLV(uint32_t opcode);
|
||||
bool SRLV(uint32_t opcode);
|
||||
bool SRAV(uint32_t opcode);
|
||||
bool DSLLV(uint32_t opcode);
|
||||
bool DSLRV(uint32_t opcode);
|
||||
bool SLT(uint32_t opcode);
|
||||
bool SLTU(uint32_t opcode);
|
||||
bool DSLL(uint32_t opcode);
|
||||
bool DSRL(uint32_t opcode);
|
||||
bool DSRA(uint32_t opcode);
|
||||
bool DSRAV(uint32_t opcode);
|
||||
bool DSLL32(uint32_t opcode);
|
||||
bool DSRL32(uint32_t opcode);
|
||||
bool DSRA32(uint32_t opcode);
|
||||
|
||||
// Jump & Branchs
|
||||
bool J(uint32_t opcode);
|
||||
bool JR(uint32_t opcode);
|
||||
bool JAL(uint32_t opcode);
|
||||
bool JALR(uint32_t opcode);
|
||||
bool BLTZ(uint32_t opcode);
|
||||
bool BLTZAL(uint32_t opcode);
|
||||
bool BGEZ(uint32_t opcode);
|
||||
bool BGEZAL(uint32_t opcode);
|
||||
bool BEQ(uint32_t opcode);
|
||||
bool BNE(uint32_t opcode);
|
||||
bool BLEZ(uint32_t opcode);
|
||||
bool BGTZ(uint32_t opcode);
|
||||
|
||||
// Load & Store
|
||||
bool LUI(uint32_t opcode);
|
||||
bool SB(uint32_t opcode);
|
||||
bool SH(uint32_t opcode);
|
||||
bool SW(uint32_t opcode);
|
||||
bool SD(uint32_t opcode);
|
||||
bool SDL(uint32_t opcode);
|
||||
bool SDR(uint32_t opcode);
|
||||
bool LWL(uint32_t opcode);
|
||||
bool LWR(uint32_t opcode);
|
||||
bool LDL(uint32_t opcode);
|
||||
bool LDR(uint32_t opcode);
|
||||
bool LB(uint32_t opcode);
|
||||
bool LBU(uint32_t opcode);
|
||||
bool LH(uint32_t opcode);
|
||||
bool LHU(uint32_t opcode);
|
||||
bool LW(uint32_t opcode);
|
||||
bool LWU(uint32_t opcode);
|
||||
bool LD(uint32_t opcode);
|
||||
bool LL(uint32_t opcode);
|
||||
bool LWC1(uint32_t opcode);
|
||||
bool SWC1(uint32_t opcode);
|
||||
|
||||
// Misc
|
||||
bool SLTI(uint32_t opcode);
|
||||
bool SLTIU(uint32_t opcode);
|
||||
bool MFHI(uint32_t opcode);
|
||||
bool MTHI(uint32_t opcode);
|
||||
bool MFLO(uint32_t opcode);
|
||||
bool MTLO(uint32_t opcode);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_ARITHM
|
||||
#define MIPS3_X64_ARITHM
|
||||
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
inline bool mips3_x64::ADD(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RS_x);
|
||||
add(eax, RT_x);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::ADDU(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RS_x);
|
||||
add(eax, RT_x);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Overflow exception
|
||||
inline bool mips3_x64::ADDI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(eax, RS_x);
|
||||
add(eax, (int32_t)SIMM);
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::ADDIU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(eax, RS_x);
|
||||
add(eax, (int32_t)SIMM);
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DADDI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
add(rax, (size_t)(int32_t)SIMM);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DADDIU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
add(rax, (size_t)(int32_t)SIMM);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Overflow exception
|
||||
inline bool mips3_x64::DADD(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
add(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DADDU(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
add(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Overflow exception
|
||||
inline bool mips3_x64::SUB(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RS_x);
|
||||
sub(eax, RT_x);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SUBU(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RS_x);
|
||||
sub(eax, RT_x);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Overflow exception
|
||||
inline bool mips3_x64::DSUB(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
sub(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool mips3_x64::DSUBU(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
sub(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::MULT(uint32_t opcode)
|
||||
{
|
||||
mov(eax, RS_x);
|
||||
mov(ecx, RT_x);
|
||||
imul(ecx);
|
||||
movsxd(rdx, edx);
|
||||
movsxd(rax, eax);
|
||||
mov(HI_x, rdx);
|
||||
mov(LO_x, rax);
|
||||
|
||||
m_block_icounter += 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::MULTU(uint32_t opcode)
|
||||
{
|
||||
mov(eax, RS_x);
|
||||
mov(ecx, RT_x);
|
||||
mul(ecx);
|
||||
movsxd(rdx, edx);
|
||||
movsxd(rax, eax);
|
||||
mov(HI_x, rdx);
|
||||
mov(LO_x, rax);
|
||||
|
||||
m_block_icounter += 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool mips3_x64::DIV(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
inLocalLabel();
|
||||
mov(rcx, RT_x);
|
||||
cmp(rcx, 0);
|
||||
je(".end");
|
||||
|
||||
mov(eax, RS_x);
|
||||
cdq();
|
||||
idiv(ecx);
|
||||
cdqe();
|
||||
|
||||
mov(LO_x, rax);
|
||||
movsxd(rcx, edx);
|
||||
mov(HI_x, rdx);
|
||||
L(".end");
|
||||
outLocalLabel();
|
||||
|
||||
}
|
||||
m_block_icounter += 34;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool mips3_x64::DIVU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
inLocalLabel();
|
||||
mov(ecx, RT_x);
|
||||
cmp(ecx, 0);
|
||||
je(".end");
|
||||
|
||||
mov(eax, RS_x);
|
||||
xor_(edx, edx);
|
||||
div(ecx);
|
||||
cdqe();
|
||||
|
||||
mov(LO_x, rax);
|
||||
movsxd(rcx, edx);
|
||||
mov(HI_x, rdx);
|
||||
L(".end");
|
||||
outLocalLabel();
|
||||
|
||||
}
|
||||
m_block_icounter += 34;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DMULT(uint32_t opcode)
|
||||
{
|
||||
mov(rax, RS_x);
|
||||
mov(rcx, RT_x);
|
||||
imul(rcx);
|
||||
mov(HI_x, rdx);
|
||||
mov(LO_x, rax);
|
||||
m_block_icounter += 6;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DDIV(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
inLocalLabel();
|
||||
mov(rcx, RT_x);
|
||||
cmp(rcx, 0);
|
||||
je(".end");
|
||||
|
||||
mov(rax, RS_x);
|
||||
cqo();
|
||||
idiv(rcx);
|
||||
|
||||
mov(LO_x, rax);
|
||||
mov(HI_x, rdx);
|
||||
L(".end");
|
||||
outLocalLabel();
|
||||
|
||||
}
|
||||
m_block_icounter += 66;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DMULTU(uint32_t opcode)
|
||||
{
|
||||
mov(rax, RS_x);
|
||||
mov(rcx, RT_x);
|
||||
mul(rcx);
|
||||
mov(HI_x, rdx);
|
||||
mov(LO_x, rax);
|
||||
m_block_icounter += 6;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DDIVU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
inLocalLabel();
|
||||
mov(rcx, RT_x);
|
||||
cmp(rcx, 0);
|
||||
je(".end");
|
||||
|
||||
mov(rax, RS_x);
|
||||
cqo();
|
||||
div(rcx);
|
||||
|
||||
mov(LO_x, rax);
|
||||
mov(HI_x, rdx);
|
||||
L(".end");
|
||||
outLocalLabel();
|
||||
|
||||
}
|
||||
m_block_icounter += 66;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_ARITHM
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef MIPS3_X64_BITOPS
|
||||
#define MIPS3_X64_BITOPS
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
|
||||
inline bool mips3_x64::AND(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
and_(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::XOR(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
xor_(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::OR(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
or_(rax, RT_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::NOR(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
or_(rax, RT_x);
|
||||
not_(rax);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::ANDI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
and_(rax, IMM);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::XORI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
xor_(rax, IMM);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::ORI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
or_(rax, IMM);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_BITOPS
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_BRANCH
|
||||
#define MIPS3_X64_BRANCH
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "../memory.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
bool mips3_x64::J(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t eaddr = 0;
|
||||
addr_t nextpc = (m_drc_pc & 0xF0000000) | (TARGET << 2);
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
m_is_delay_slot = true;
|
||||
if (compile_instruction(next_opcode)) {
|
||||
drc_log("Branch on delay slot!!! aborting...");
|
||||
exit(-1);
|
||||
}
|
||||
m_is_delay_slot = false;
|
||||
|
||||
update_icounter();
|
||||
|
||||
jmp_to_block(nextpc);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::JR(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t eaddr;
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
m_is_delay_slot = true;
|
||||
if (compile_instruction(next_opcode)) {
|
||||
drc_log("Branch on delay slot!!! aborting...");
|
||||
exit(-1);
|
||||
}
|
||||
m_is_delay_slot = false;
|
||||
|
||||
update_icounter();
|
||||
|
||||
jmp_to_register(RSNUM);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::JAL(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t eaddr = 0;
|
||||
addr_t nextpc = (m_drc_pc & 0xF0000000) | (TARGET << 2);
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
m_is_delay_slot = true;
|
||||
if (compile_instruction(next_opcode)) {
|
||||
drc_log("Branch on delay slot!!! aborting...");
|
||||
exit(-1);
|
||||
}
|
||||
m_is_delay_slot = false;
|
||||
|
||||
update_icounter();
|
||||
|
||||
mov(eax, (uint32_t)m_drc_pc);
|
||||
cdqe();
|
||||
mov(rcx, R_ref(31));
|
||||
mov(ptr[rcx], rax);
|
||||
|
||||
jmp_to_block(nextpc);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::JALR(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t eaddr;
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
m_is_delay_slot = true;
|
||||
if (compile_instruction(next_opcode)) {
|
||||
drc_log("Branch on delay slot!!! aborting...");
|
||||
exit(-1);
|
||||
}
|
||||
m_is_delay_slot = false;
|
||||
|
||||
update_icounter();
|
||||
|
||||
mov(eax, (uint32_t)m_drc_pc);
|
||||
cdqe();
|
||||
mov(rcx, R_ref(31));
|
||||
mov(ptr[rcx], rax);
|
||||
|
||||
jmp_to_register(RSNUM);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::BLTZ(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
|
||||
cmp(RS_q, 0);
|
||||
jge(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::BLTZAL(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
|
||||
cmp(RS_q, 0);
|
||||
jge(".false");
|
||||
{
|
||||
mov(eax, (uint32_t)m_drc_pc);
|
||||
cdqe();
|
||||
mov(Rn_x(31), rax);
|
||||
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool mips3_x64::BGEZ(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
cmp(RS_q, 0);
|
||||
jl(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::BGEZAL(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
cmp(RS_q, 0);
|
||||
jl(".false");
|
||||
{
|
||||
mov(eax, (uint32_t)m_drc_pc);
|
||||
cdqe();
|
||||
mov(Rn_x(31), rax);
|
||||
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::BEQ(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
mov(rax, RS_x);
|
||||
cmp(rax, RT_x);
|
||||
jne(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool mips3_x64::BNE(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
mov(rax, RS_x);
|
||||
cmp(rax, RT_x);
|
||||
je(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::BLEZ(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
cmp(RS_q, 0);
|
||||
jg(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::BGTZ(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
cmp(RS_q, 0);
|
||||
jle(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_BRANCH
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_COP1
|
||||
#define MIPS3_X64_COP1
|
||||
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
bool mips3_x64::BC1F(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
mov(rcx, FCR_ref(31));
|
||||
mov(rcx, ptr[rcx]);
|
||||
not_(ecx);
|
||||
and_(ecx, 0x800000);
|
||||
test(ecx, ecx);
|
||||
je(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool mips3_x64::BC1FL(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
mov(rcx, FCR_ref(31));
|
||||
mov(rcx, ptr[rcx]);
|
||||
not_(ecx);
|
||||
and_(ecx, 0x800000);
|
||||
test(ecx, ecx);
|
||||
je(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::BC1T(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
mov(rcx, FCR_ref(31));
|
||||
mov(rcx, ptr[rcx]);
|
||||
and_(ecx, 0x800000);
|
||||
test(ecx, ecx);
|
||||
je(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
compile_instruction(next_opcode);
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool mips3_x64::BC1TL(uint32_t opcode)
|
||||
{
|
||||
if (m_is_delay_slot)
|
||||
return true;
|
||||
|
||||
addr_t nextpc = m_drc_pc + ((int32_t)(SIMM) << 2);
|
||||
addr_t eaddr = 0;
|
||||
|
||||
m_core->translate(m_drc_pc, &eaddr);
|
||||
uint32_t next_opcode = mem::read_word(eaddr);
|
||||
|
||||
m_drc_pc += 4;
|
||||
|
||||
update_icounter();
|
||||
|
||||
inLocalLabel();
|
||||
mov(rcx, FCR_ref(31));
|
||||
mov(rcx, ptr[rcx]);
|
||||
and_(ecx, 0x800000);
|
||||
test(ecx, ecx);
|
||||
je(".false");
|
||||
{
|
||||
m_is_delay_slot = true;
|
||||
compile_instruction(next_opcode);
|
||||
m_is_delay_slot = false;
|
||||
jmp_to_block(nextpc);
|
||||
}
|
||||
|
||||
L(".false");
|
||||
outLocalLabel();
|
||||
check_icounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::compile_cop1(uint32_t opcode)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (RSNUM) {
|
||||
// MFC1 rt, rd
|
||||
case 0x00:
|
||||
if (RTNUM) {
|
||||
mov(rax, FPR_ref(RDNUM));
|
||||
mov(rcx, RT_ref);
|
||||
mov(eax, ptr[rax]);
|
||||
cdqe();
|
||||
mov(ptr[rcx], rax);
|
||||
}
|
||||
break;
|
||||
|
||||
// DMFC1 rt, rd
|
||||
case 0x01:
|
||||
if (RTNUM) {
|
||||
mov(rax, FPR_ref(RDNUM));
|
||||
mov(rcx, RT_ref);
|
||||
mov(rax, ptr[rax]);
|
||||
mov(ptr[rcx], rax);
|
||||
}
|
||||
break;
|
||||
|
||||
// CFC1 rt, fs
|
||||
case 0x02:
|
||||
if (RTNUM) {
|
||||
mov(rax, FCR_ref(FSNUM));
|
||||
mov(rcx, RT_ref);
|
||||
mov(eax, ptr[rax]);
|
||||
cdqe();
|
||||
mov(ptr[rcx], rax);
|
||||
}
|
||||
break;
|
||||
|
||||
// MTC1 rt, fs
|
||||
case 0x04:
|
||||
mov(rax, FPR_ref(FSNUM));
|
||||
mov(rcx, RT_ref);
|
||||
mov(ecx, ptr[rcx]);
|
||||
mov(ptr[rax], rcx);
|
||||
break;
|
||||
|
||||
// DMTC1 rt, fs
|
||||
case 0x05:
|
||||
mov(rax, FPR_ref(FSNUM));
|
||||
mov(rcx, RT_ref);
|
||||
mov(rcx, ptr[rcx]);
|
||||
mov(ptr[rax], rcx);
|
||||
break;
|
||||
|
||||
// CTC1 rt, fs
|
||||
case 0x06:
|
||||
mov(rcx, FCR_ref(FSNUM));
|
||||
mov(rax, RT_ref);
|
||||
mov(eax, ptr[rax]);
|
||||
cdqe();
|
||||
mov(ptr[rcx], rax);
|
||||
break;
|
||||
|
||||
// BC
|
||||
case 0x08:
|
||||
{
|
||||
switch ((opcode >> 16) & 3) {
|
||||
// BC1F offset
|
||||
case 0x00: result = BC1F(opcode); break;
|
||||
|
||||
// BC1FL offset
|
||||
case 0x02: result = BC1FL(opcode); break;
|
||||
|
||||
// BC1T offset
|
||||
case 0x01: result = BC1T(opcode); break;
|
||||
break;
|
||||
|
||||
// BC1TL offset
|
||||
case 0x03: result = BC1TL(opcode); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fallback(opcode, &mips3::cop1_execute_32);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_COP1
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_DEFS
|
||||
#define MIPS3_X64_DEFS
|
||||
|
||||
#include <stddef.h>
|
||||
#include "../mipsdef.h"
|
||||
|
||||
#define DEBUG_DRC 1
|
||||
|
||||
#if DEBUG_DRC
|
||||
# define drc_log(...) printf("drc: " __VA_ARGS__); fflush(stdout)
|
||||
#else
|
||||
# define drc_log(...)
|
||||
#endif
|
||||
|
||||
#define drc_log_error(...) printf("drc_err: " __VA_ARGS__); fflush(stdout)
|
||||
|
||||
#define DEBUG_CALL(f) \
|
||||
mov(rax, (size_t)(void*)&f); \
|
||||
call(rax);
|
||||
|
||||
#define CORE_PC (m_core->m_state.pc)
|
||||
#define RS_ref ((size_t)&m_core->m_state.r[RSNUM])
|
||||
#define RD_ref ((size_t)&m_core->m_state.r[RDNUM])
|
||||
#define RT_ref ((size_t)&m_core->m_state.r[RTNUM])
|
||||
#define LO_ref ((size_t)&m_core->m_state.lo)
|
||||
#define HI_ref ((size_t)&m_core->m_state.hi)
|
||||
#define R_ref(n) ((size_t)&m_core->m_state.r[n])
|
||||
#define ADR(n) ((size_t)&n)
|
||||
#define F_ADR(f) ((size_t)(void*)&f)
|
||||
|
||||
#define FPR_ref(n) ((size_t)&m_core->m_state.cpr[1][n])
|
||||
#define FCR_ref(n) ((size_t)&m_core->m_state.fcr[n])
|
||||
|
||||
#define Rn_x(n) ptr[rbx + ((size_t)offsetof(mips3::cpu_state, r[n]))]
|
||||
#define RS_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, r[RSNUM]))]
|
||||
#define RD_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, r[RDNUM]))]
|
||||
#define RT_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, r[RTNUM]))]
|
||||
#define LO_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, lo))]
|
||||
#define HI_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, hi))]
|
||||
#define PC_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, pc))]
|
||||
|
||||
#define COP0_x(n) ptr[rbx + ((size_t)offsetof(mips3::cpu_state, cpr[0][n]))]
|
||||
#define COP1_x(n) ptr[rbx + ((size_t)offsetof(mips3::cpu_state, cpr[1][n]))]
|
||||
|
||||
#define TOTAL_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, total_cycles))]
|
||||
#define RSTCYC_x ptr[rbx + ((size_t)offsetof(mips3::cpu_state, reset_cycle))]
|
||||
|
||||
#define RS_q qword[rbx + ((size_t)offsetof(mips3::cpu_state, r[RSNUM]))]
|
||||
#define RD_q qword[rbx + ((size_t)offsetof(mips3::cpu_state, r[RDNUM]))]
|
||||
#define RT_q qword[rbx + ((size_t)offsetof(mips3::cpu_state, r[RTNUM]))]
|
||||
#define PC_q qword[rbx + ((size_t)offsetof(mips3::cpu_state, pc))]
|
||||
|
||||
#define COP0_q(n) qword[rbx + ((size_t)offsetof(mips3::cpu_state, cpr[0][n]))]
|
||||
#define COP1_q(n) qword[rbx + ((size_t)offsetof(mips3::cpu_state, cpr[1][n]))]
|
||||
|
||||
#define TOTAL_q qword[rbx + ((size_t)offsetof(mips3::cpu_state, total_cycles))]
|
||||
#define RSTCYC_q qword[rbx + ((size_t)offsetof(mips3::cpu_state, reset_cycle))]
|
||||
|
||||
#endif // MIPS3_X64_DEFS
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_MISC
|
||||
#define MIPS3_X64_MISC
|
||||
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
inline bool mips3_x64::SLT(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
cmp(rax, RT_x);
|
||||
setl(dl);
|
||||
movzx(edx, dl);
|
||||
mov(RD_x, rdx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SLTU(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RS_x);
|
||||
cmp(rax, RT_x);
|
||||
setb(dl);
|
||||
movzx(edx, dl);
|
||||
mov(RD_x, rdx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SLTI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
cmp(rax, IMM_s64);
|
||||
setl(dl);
|
||||
movzx(edx, dl);
|
||||
mov(RT_x, rdx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SLTIU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
mov(rax, RS_x);
|
||||
cmp(rax, IMM);
|
||||
setb(dl);
|
||||
movzx(edx, dl);
|
||||
mov(RT_x, rdx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::MFHI(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, HI_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::MTHI(uint32_t opcode)
|
||||
{
|
||||
mov(rax, RS_x);
|
||||
mov(HI_x, rax);
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::MFLO(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, LO_x);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::MTLO(uint32_t opcode)
|
||||
{
|
||||
mov(rax, RS_x);
|
||||
mov(LO_x, rax);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_MISC
|
||||
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_RW
|
||||
#define MIPS3_X64_RW
|
||||
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
#include "../memory.h"
|
||||
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
#define GET_EADDR_IN_RDX(ignore) \
|
||||
do { \
|
||||
auto eaddr = ptr[rbp-8];\
|
||||
mov(rdi, (size_t) m_core);\
|
||||
mov(rsi, (int64_t)(int32_t)SIMM);\
|
||||
add(rsi, RS_x);\
|
||||
and_(rsi, ~((uint64_t)ignore));\
|
||||
lea(rdx, eaddr);\
|
||||
mov(rax, F_ADR(mips3::translate));\
|
||||
call(rax);\
|
||||
mov(rdx, eaddr);\
|
||||
} while (0)
|
||||
|
||||
#define GET_EA_RDX_VA_RCX(ignore) \
|
||||
do { \
|
||||
auto eaddr = ptr[rbp-8];\
|
||||
auto vaddr = ptr[rbp-16];\
|
||||
mov(rdi, (size_t) m_core);\
|
||||
mov(rsi, (int64_t)(int32_t)SIMM);\
|
||||
add(rsi, RS_x);\
|
||||
and_(rsi, ~((uint64_t)ignore));\
|
||||
lea(rdx, eaddr);\
|
||||
mov(vaddr, rsi);\
|
||||
mov(rax, F_ADR(mips3::translate));\
|
||||
call(rax);\
|
||||
mov(rdx, eaddr);\
|
||||
mov(rcx, vaddr);\
|
||||
} while (0)
|
||||
|
||||
bool mips3_x64::LUI(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
int64_t value = (int32_t)(IMM << 16);
|
||||
mov(RT_q, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::SB(uint32_t opcode)
|
||||
{
|
||||
GET_EADDR_IN_RDX(0);
|
||||
mov(rdi, rdx);
|
||||
mov(rsi, RT_x);
|
||||
mov(rax, F_ADR(mem::write_byte));
|
||||
call(rax);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::SH(uint32_t opcode)
|
||||
{
|
||||
GET_EADDR_IN_RDX(1);
|
||||
mov(rdi, rdx);
|
||||
mov(rsi, RT_x);
|
||||
mov(rax, F_ADR(mem::write_half));
|
||||
call(rax);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::SW(uint32_t opcode)
|
||||
{
|
||||
GET_EADDR_IN_RDX(3);
|
||||
mov(rdi, rdx);
|
||||
mov(rsi, RT_x);
|
||||
mov(rax, F_ADR(mem::write_word));
|
||||
call(rax);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::SD(uint32_t opcode)
|
||||
{
|
||||
GET_EADDR_IN_RDX(7);
|
||||
mov(rdi, rdx);
|
||||
mov(rsi, RT_x);
|
||||
mov(rax, F_ADR(mem::write_dword));
|
||||
call(rax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: FIX IT
|
||||
bool mips3_x64::SDL(uint32_t opcode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: FIX IT
|
||||
bool mips3_x64::SDR(uint32_t opcode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool mips3_x64::LWL(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EA_RDX_VA_RCX(3);
|
||||
auto shift = ptr[rbp-8];
|
||||
auto mask = ptr[rbp-16];
|
||||
|
||||
mov(rax, rcx);
|
||||
and_(rax, 3);
|
||||
xor_(rax, 3);
|
||||
shl(rax, 3);
|
||||
mov(shift, rax);
|
||||
|
||||
mov(rax, 0);
|
||||
not_(rax);
|
||||
mov(rcx, shift);
|
||||
shl(rax, cl);
|
||||
mov(mask, rax);
|
||||
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_dword));
|
||||
call(rax);
|
||||
|
||||
mov(rcx, shift);
|
||||
shl(rax, cl);
|
||||
|
||||
mov(rcx, RT_x);
|
||||
mov(rdi, mask);
|
||||
not_(rdi);
|
||||
and_(rcx, rdi);
|
||||
or_(rax, rcx);
|
||||
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool mips3_x64::LWR(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EA_RDX_VA_RCX(3);
|
||||
|
||||
auto shift = ptr[rbp-8];
|
||||
auto mask = ptr[rbp-16];
|
||||
|
||||
mov(rax, rcx);
|
||||
and_(rax, 3);
|
||||
shl(rax, 3);
|
||||
mov(shift, rax);
|
||||
|
||||
xor_(rax, rax);
|
||||
not_(rax);
|
||||
mov(rcx, shift);
|
||||
shr(rax, cl);
|
||||
mov(mask, rax);
|
||||
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_word));
|
||||
call(rax);
|
||||
|
||||
mov(rcx, shift);
|
||||
shr(rax, cl);
|
||||
|
||||
mov(rcx, RT_x);
|
||||
mov(rdi, mask);
|
||||
not_(rdi);
|
||||
and_(rcx, rdi);
|
||||
or_(rax, rcx);
|
||||
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Válido apenas para little endian.
|
||||
bool mips3_x64::LDL(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EA_RDX_VA_RCX(7);
|
||||
auto shift = ptr[rbp-8];
|
||||
auto mask = ptr[rbp-16];
|
||||
|
||||
mov(rax, rcx);
|
||||
and_(rax, 7);
|
||||
xor_(rax, 7);
|
||||
shl(rax, 3);
|
||||
mov(shift, rax);
|
||||
|
||||
mov(rax, 0);
|
||||
not_(rax);
|
||||
mov(rcx, shift);
|
||||
shl(rax, cl);
|
||||
mov(mask, rax);
|
||||
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_dword));
|
||||
call(rax);
|
||||
|
||||
mov(rcx, shift);
|
||||
shl(rax, cl);
|
||||
|
||||
mov(rcx, RT_x);
|
||||
mov(rdi, mask);
|
||||
not_(rdi);
|
||||
and_(rcx, rdi);
|
||||
or_(rax, rcx);
|
||||
|
||||
mov(RT_x, rax);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Válido apenas para little endian.
|
||||
/*
|
||||
uint32_t vaddr = ((int32_t)SIMM) + RS;
|
||||
|
||||
int shift = (vaddr & 7) * 8;
|
||||
uint64_t mask = (0xFFFFFFFFFFFFFFFFULL >> shift);
|
||||
|
||||
addr_t eaddr;
|
||||
if (translate(vaddr & ~7, &eaddr)) {
|
||||
}
|
||||
//d18
|
||||
auto data = mem::read_dword(eaddr);
|
||||
|
||||
if (RTNUM)
|
||||
RT = (RT & ~mask) | (data >> shift);*/
|
||||
bool mips3_x64::LDR(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EA_RDX_VA_RCX(7);
|
||||
|
||||
auto shift = ptr[rbp-8];
|
||||
auto mask = ptr[rbp-16];
|
||||
|
||||
mov(rax, rcx);
|
||||
and_(rax, 7);
|
||||
shl(rax, 3);
|
||||
mov(shift, rax);
|
||||
|
||||
xor_(rax, rax);
|
||||
not_(rax);
|
||||
mov(rcx, shift);
|
||||
shr(rax, cl);
|
||||
mov(mask, rax);
|
||||
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_dword));
|
||||
call(rax);
|
||||
|
||||
mov(rcx, shift);
|
||||
shr(rax, cl);
|
||||
|
||||
mov(rcx, RT_x);
|
||||
mov(rdi, mask);
|
||||
not_(rdi);
|
||||
and_(rcx, rdi);
|
||||
or_(rax, rcx);
|
||||
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool mips3_x64::LW(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(3);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_word));
|
||||
call(rax);
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LWU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(3);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_word));
|
||||
call(rax);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LD(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(7);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_dword));
|
||||
call(rax);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LL(uint32_t opcode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: FIX IT
|
||||
bool mips3_x64::LWC1(uint32_t opcode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: FIX IT
|
||||
bool mips3_x64::SWC1(uint32_t opcode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LB(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(0);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_byte));
|
||||
call(rax);
|
||||
movsx(eax, al);
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LBU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(0);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_byte));
|
||||
call(rax);
|
||||
movzx(eax, al);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LH(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(1);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_half));
|
||||
call(rax);
|
||||
movsx(eax, ax);
|
||||
cdqe();
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mips3_x64::LHU(uint32_t opcode)
|
||||
{
|
||||
if (RTNUM) {
|
||||
GET_EADDR_IN_RDX(1);
|
||||
mov(rdi, rdx);
|
||||
mov(rax, F_ADR(mem::read_half));
|
||||
call(rax);
|
||||
movzx(eax, ax);
|
||||
mov(RT_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_RW
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Marcos Medeiros
|
||||
* Licensed under BSD 3-clause.
|
||||
*/
|
||||
#ifndef MIPS3_X64_SHIFT
|
||||
#define MIPS3_X64_SHIFT
|
||||
|
||||
|
||||
#include "../mips3.h"
|
||||
#include "mips3_x64_defs.h"
|
||||
#include "mips3_x64.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
|
||||
namespace mips
|
||||
{
|
||||
|
||||
inline bool mips3_x64::SLL(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM && SHAMT) {
|
||||
mov(eax, RT_x);
|
||||
shl(eax, SHAMT);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SRL(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM && SHAMT) {
|
||||
mov(eax, RT_x);
|
||||
shr(eax, SHAMT);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SRA(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RT_x);
|
||||
sar(eax, SHAMT);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool mips3_x64::SLLV(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RT_x);
|
||||
mov(ecx, RS_x);
|
||||
and_(ecx, 31);
|
||||
shl(eax, cl);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SRLV(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RT_x);
|
||||
mov(ecx, RS_x);
|
||||
and_(ecx, 31);
|
||||
shr(eax, cl);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::SRAV(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(eax, RT_x);
|
||||
mov(ecx, RS_x);
|
||||
and_(ecx, 31);
|
||||
sar(eax, cl);
|
||||
cdqe();
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSLLV(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
mov(rcx, RS_x);
|
||||
and_(rcx, 63);
|
||||
shl(rax, cl);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSLRV(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
mov(rcx, RS_x);
|
||||
and_(rcx, 63);
|
||||
shr(rax, cl);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSRAV(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
mov(rcx, RS_x);
|
||||
and_(rcx, 63);
|
||||
sar(rax, cl);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSLL(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
shl(rax, SHAMT);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSRL(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
shr(rax, SHAMT);
|
||||
mov(RD_x, rax);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSRA(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
sar(rax, SHAMT & 63);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSLL32(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
shl(rax, SHAMT + 32);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSRL32(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
shr(rax, SHAMT + 32);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool mips3_x64::DSRA32(uint32_t opcode)
|
||||
{
|
||||
if (RDNUM) {
|
||||
mov(rax, RT_x);
|
||||
sar(rax, SHAMT + 32);
|
||||
mov(RD_x, rax);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // MIPS3_X64_SHIFT
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,258 @@
|
|||
enum {
|
||||
B00000000= 0,
|
||||
B00000001= 1,
|
||||
B00000010= 2,
|
||||
B00000011= 3,
|
||||
B00000100= 4,
|
||||
B00000101= 5,
|
||||
B00000110= 6,
|
||||
B00000111= 7,
|
||||
B00001000= 8,
|
||||
B00001001= 9,
|
||||
B00001010= 10,
|
||||
B00001011= 11,
|
||||
B00001100= 12,
|
||||
B00001101= 13,
|
||||
B00001110= 14,
|
||||
B00001111= 15,
|
||||
B00010000= 16,
|
||||
B00010001= 17,
|
||||
B00010010= 18,
|
||||
B00010011= 19,
|
||||
B00010100= 20,
|
||||
B00010101= 21,
|
||||
B00010110= 22,
|
||||
B00010111= 23,
|
||||
B00011000= 24,
|
||||
B00011001= 25,
|
||||
B00011010= 26,
|
||||
B00011011= 27,
|
||||
B00011100= 28,
|
||||
B00011101= 29,
|
||||
B00011110= 30,
|
||||
B00011111= 31,
|
||||
B00100000= 32,
|
||||
B00100001= 33,
|
||||
B00100010= 34,
|
||||
B00100011= 35,
|
||||
B00100100= 36,
|
||||
B00100101= 37,
|
||||
B00100110= 38,
|
||||
B00100111= 39,
|
||||
B00101000= 40,
|
||||
B00101001= 41,
|
||||
B00101010= 42,
|
||||
B00101011= 43,
|
||||
B00101100= 44,
|
||||
B00101101= 45,
|
||||
B00101110= 46,
|
||||
B00101111= 47,
|
||||
B00110000= 48,
|
||||
B00110001= 49,
|
||||
B00110010= 50,
|
||||
B00110011= 51,
|
||||
B00110100= 52,
|
||||
B00110101= 53,
|
||||
B00110110= 54,
|
||||
B00110111= 55,
|
||||
B00111000= 56,
|
||||
B00111001= 57,
|
||||
B00111010= 58,
|
||||
B00111011= 59,
|
||||
B00111100= 60,
|
||||
B00111101= 61,
|
||||
B00111110= 62,
|
||||
B00111111= 63,
|
||||
B01000000= 64,
|
||||
B01000001= 65,
|
||||
B01000010= 66,
|
||||
B01000011= 67,
|
||||
B01000100= 68,
|
||||
B01000101= 69,
|
||||
B01000110= 70,
|
||||
B01000111= 71,
|
||||
B01001000= 72,
|
||||
B01001001= 73,
|
||||
B01001010= 74,
|
||||
B01001011= 75,
|
||||
B01001100= 76,
|
||||
B01001101= 77,
|
||||
B01001110= 78,
|
||||
B01001111= 79,
|
||||
B01010000= 80,
|
||||
B01010001= 81,
|
||||
B01010010= 82,
|
||||
B01010011= 83,
|
||||
B01010100= 84,
|
||||
B01010101= 85,
|
||||
B01010110= 86,
|
||||
B01010111= 87,
|
||||
B01011000= 88,
|
||||
B01011001= 89,
|
||||
B01011010= 90,
|
||||
B01011011= 91,
|
||||
B01011100= 92,
|
||||
B01011101= 93,
|
||||
B01011110= 94,
|
||||
B01011111= 95,
|
||||
B01100000= 96,
|
||||
B01100001= 97,
|
||||
B01100010= 98,
|
||||
B01100011= 99,
|
||||
B01100100= 100,
|
||||
B01100101= 101,
|
||||
B01100110= 102,
|
||||
B01100111= 103,
|
||||
B01101000= 104,
|
||||
B01101001= 105,
|
||||
B01101010= 106,
|
||||
B01101011= 107,
|
||||
B01101100= 108,
|
||||
B01101101= 109,
|
||||
B01101110= 110,
|
||||
B01101111= 111,
|
||||
B01110000= 112,
|
||||
B01110001= 113,
|
||||
B01110010= 114,
|
||||
B01110011= 115,
|
||||
B01110100= 116,
|
||||
B01110101= 117,
|
||||
B01110110= 118,
|
||||
B01110111= 119,
|
||||
B01111000= 120,
|
||||
B01111001= 121,
|
||||
B01111010= 122,
|
||||
B01111011= 123,
|
||||
B01111100= 124,
|
||||
B01111101= 125,
|
||||
B01111110= 126,
|
||||
B01111111= 127,
|
||||
B10000000= 128,
|
||||
B10000001= 129,
|
||||
B10000010= 130,
|
||||
B10000011= 131,
|
||||
B10000100= 132,
|
||||
B10000101= 133,
|
||||
B10000110= 134,
|
||||
B10000111= 135,
|
||||
B10001000= 136,
|
||||
B10001001= 137,
|
||||
B10001010= 138,
|
||||
B10001011= 139,
|
||||
B10001100= 140,
|
||||
B10001101= 141,
|
||||
B10001110= 142,
|
||||
B10001111= 143,
|
||||
B10010000= 144,
|
||||
B10010001= 145,
|
||||
B10010010= 146,
|
||||
B10010011= 147,
|
||||
B10010100= 148,
|
||||
B10010101= 149,
|
||||
B10010110= 150,
|
||||
B10010111= 151,
|
||||
B10011000= 152,
|
||||
B10011001= 153,
|
||||
B10011010= 154,
|
||||
B10011011= 155,
|
||||
B10011100= 156,
|
||||
B10011101= 157,
|
||||
B10011110= 158,
|
||||
B10011111= 159,
|
||||
B10100000= 160,
|
||||
B10100001= 161,
|
||||
B10100010= 162,
|
||||
B10100011= 163,
|
||||
B10100100= 164,
|
||||
B10100101= 165,
|
||||
B10100110= 166,
|
||||
B10100111= 167,
|
||||
B10101000= 168,
|
||||
B10101001= 169,
|
||||
B10101010= 170,
|
||||
B10101011= 171,
|
||||
B10101100= 172,
|
||||
B10101101= 173,
|
||||
B10101110= 174,
|
||||
B10101111= 175,
|
||||
B10110000= 176,
|
||||
B10110001= 177,
|
||||
B10110010= 178,
|
||||
B10110011= 179,
|
||||
B10110100= 180,
|
||||
B10110101= 181,
|
||||
B10110110= 182,
|
||||
B10110111= 183,
|
||||
B10111000= 184,
|
||||
B10111001= 185,
|
||||
B10111010= 186,
|
||||
B10111011= 187,
|
||||
B10111100= 188,
|
||||
B10111101= 189,
|
||||
B10111110= 190,
|
||||
B10111111= 191,
|
||||
B11000000= 192,
|
||||
B11000001= 193,
|
||||
B11000010= 194,
|
||||
B11000011= 195,
|
||||
B11000100= 196,
|
||||
B11000101= 197,
|
||||
B11000110= 198,
|
||||
B11000111= 199,
|
||||
B11001000= 200,
|
||||
B11001001= 201,
|
||||
B11001010= 202,
|
||||
B11001011= 203,
|
||||
B11001100= 204,
|
||||
B11001101= 205,
|
||||
B11001110= 206,
|
||||
B11001111= 207,
|
||||
B11010000= 208,
|
||||
B11010001= 209,
|
||||
B11010010= 210,
|
||||
B11010011= 211,
|
||||
B11010100= 212,
|
||||
B11010101= 213,
|
||||
B11010110= 214,
|
||||
B11010111= 215,
|
||||
B11011000= 216,
|
||||
B11011001= 217,
|
||||
B11011010= 218,
|
||||
B11011011= 219,
|
||||
B11011100= 220,
|
||||
B11011101= 221,
|
||||
B11011110= 222,
|
||||
B11011111= 223,
|
||||
B11100000= 224,
|
||||
B11100001= 225,
|
||||
B11100010= 226,
|
||||
B11100011= 227,
|
||||
B11100100= 228,
|
||||
B11100101= 229,
|
||||
B11100110= 230,
|
||||
B11100111= 231,
|
||||
B11101000= 232,
|
||||
B11101001= 233,
|
||||
B11101010= 234,
|
||||
B11101011= 235,
|
||||
B11101100= 236,
|
||||
B11101101= 237,
|
||||
B11101110= 238,
|
||||
B11101111= 239,
|
||||
B11110000= 240,
|
||||
B11110001= 241,
|
||||
B11110010= 242,
|
||||
B11110011= 243,
|
||||
B11110100= 244,
|
||||
B11110101= 245,
|
||||
B11110110= 246,
|
||||
B11110111= 247,
|
||||
B11111000= 248,
|
||||
B11111001= 249,
|
||||
B11111010= 250,
|
||||
B11111011= 251,
|
||||
B11111100= 252,
|
||||
B11111101= 253,
|
||||
B11111110= 254,
|
||||
B11111111= 255
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,529 @@
|
|||
#ifndef XBYAK_XBYAK_UTIL_H_
|
||||
#define XBYAK_XBYAK_UTIL_H_
|
||||
|
||||
/**
|
||||
utility class and functions for Xbyak
|
||||
Xbyak::util::Clock ; rdtsc timer
|
||||
Xbyak::util::Cpu ; detect CPU
|
||||
@note this header is UNDER CONSTRUCTION!
|
||||
*/
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if (_MSC_VER < 1400) && defined(XBYAK32)
|
||||
static inline __declspec(naked) void __cpuid(int[4], int)
|
||||
{
|
||||
__asm {
|
||||
push ebx
|
||||
push esi
|
||||
mov eax, dword ptr [esp + 4 * 2 + 8] // eaxIn
|
||||
cpuid
|
||||
mov esi, dword ptr [esp + 4 * 2 + 4] // data
|
||||
mov dword ptr [esi], eax
|
||||
mov dword ptr [esi + 4], ebx
|
||||
mov dword ptr [esi + 8], ecx
|
||||
mov dword ptr [esi + 12], edx
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <intrin.h> // for __cpuid
|
||||
#endif
|
||||
#else
|
||||
#ifndef __GNUC_PREREQ
|
||||
#define __GNUC_PREREQ(major, minor) ((((__GNUC__) << 16) + (__GNUC_MINOR__)) >= (((major) << 16) + (minor)))
|
||||
#endif
|
||||
#if __GNUC_PREREQ(4, 3) && !defined(__APPLE__)
|
||||
#include <cpuid.h>
|
||||
#else
|
||||
#if defined(__APPLE__) && defined(XBYAK32) // avoid err : can't find a register in class `BREG' while reloading `asm'
|
||||
#define __cpuid(eaxIn, a, b, c, d) __asm__ __volatile__("pushl %%ebx\ncpuid\nmovl %%ebp, %%esi\npopl %%ebx" : "=a"(a), "=S"(b), "=c"(c), "=d"(d) : "0"(eaxIn))
|
||||
#define __cpuid_count(eaxIn, ecxIn, a, b, c, d) __asm__ __volatile__("pushl %%ebx\ncpuid\nmovl %%ebp, %%esi\npopl %%ebx" : "=a"(a), "=S"(b), "=c"(c), "=d"(d) : "0"(eaxIn), "2"(ecxIn))
|
||||
#else
|
||||
#define __cpuid(eaxIn, a, b, c, d) __asm__ __volatile__("cpuid\n" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eaxIn))
|
||||
#define __cpuid_count(eaxIn, ecxIn, a, b, c, d) __asm__ __volatile__("cpuid\n" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eaxIn), "2"(ecxIn))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
extern "C" unsigned __int64 __xgetbv(int);
|
||||
#endif
|
||||
|
||||
namespace Xbyak { namespace util {
|
||||
|
||||
/**
|
||||
CPU detection class
|
||||
*/
|
||||
class Cpu {
|
||||
uint64 type_;
|
||||
unsigned int get32bitAsBE(const char *x) const
|
||||
{
|
||||
return x[0] | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||
}
|
||||
unsigned int mask(int n) const
|
||||
{
|
||||
return (1U << n) - 1;
|
||||
}
|
||||
void setFamily()
|
||||
{
|
||||
unsigned int data[4];
|
||||
getCpuid(1, data);
|
||||
stepping = data[0] & mask(4);
|
||||
model = (data[0] >> 4) & mask(4);
|
||||
family = (data[0] >> 8) & mask(4);
|
||||
// type = (data[0] >> 12) & mask(2);
|
||||
extModel = (data[0] >> 16) & mask(4);
|
||||
extFamily = (data[0] >> 20) & mask(8);
|
||||
if (family == 0x0f) {
|
||||
displayFamily = family + extFamily;
|
||||
} else {
|
||||
displayFamily = family;
|
||||
}
|
||||
if (family == 6 || family == 0x0f) {
|
||||
displayModel = (extModel << 4) + model;
|
||||
} else {
|
||||
displayModel = model;
|
||||
}
|
||||
}
|
||||
public:
|
||||
int model;
|
||||
int family;
|
||||
int stepping;
|
||||
int extModel;
|
||||
int extFamily;
|
||||
int displayFamily; // family + extFamily
|
||||
int displayModel; // model + extModel
|
||||
static inline void getCpuid(unsigned int eaxIn, unsigned int data[4])
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__cpuid(reinterpret_cast<int*>(data), eaxIn);
|
||||
#else
|
||||
__cpuid(eaxIn, data[0], data[1], data[2], data[3]);
|
||||
#endif
|
||||
}
|
||||
static inline void getCpuidEx(unsigned int eaxIn, unsigned int ecxIn, unsigned int data[4])
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__cpuidex(reinterpret_cast<int*>(data), eaxIn, ecxIn);
|
||||
#else
|
||||
__cpuid_count(eaxIn, ecxIn, data[0], data[1], data[2], data[3]);
|
||||
#endif
|
||||
}
|
||||
static inline uint64 getXfeature()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return __xgetbv(0);
|
||||
#else
|
||||
unsigned int eax, edx;
|
||||
// xgetvb is not support on gcc 4.2
|
||||
// __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
|
||||
__asm__ volatile(".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
|
||||
return ((uint64)edx << 32) | eax;
|
||||
#endif
|
||||
}
|
||||
typedef uint64 Type;
|
||||
static const Type NONE = 0;
|
||||
static const Type tMMX = 1 << 0;
|
||||
static const Type tMMX2 = 1 << 1;
|
||||
static const Type tCMOV = 1 << 2;
|
||||
static const Type tSSE = 1 << 3;
|
||||
static const Type tSSE2 = 1 << 4;
|
||||
static const Type tSSE3 = 1 << 5;
|
||||
static const Type tSSSE3 = 1 << 6;
|
||||
static const Type tSSE41 = 1 << 7;
|
||||
static const Type tSSE42 = 1 << 8;
|
||||
static const Type tPOPCNT = 1 << 9;
|
||||
static const Type tAESNI = 1 << 10;
|
||||
static const Type tSSE5 = 1 << 11;
|
||||
static const Type tOSXSAVE = 1 << 12;
|
||||
static const Type tPCLMULQDQ = 1 << 13;
|
||||
static const Type tAVX = 1 << 14;
|
||||
static const Type tFMA = 1 << 15;
|
||||
|
||||
static const Type t3DN = 1 << 16;
|
||||
static const Type tE3DN = 1 << 17;
|
||||
static const Type tSSE4a = 1 << 18;
|
||||
static const Type tRDTSCP = 1 << 19;
|
||||
static const Type tAVX2 = 1 << 20;
|
||||
static const Type tBMI1 = 1 << 21; // andn, bextr, blsi, blsmsk, blsr, tzcnt
|
||||
static const Type tBMI2 = 1 << 22; // bzhi, mulx, pdep, pext, rorx, sarx, shlx, shrx
|
||||
static const Type tLZCNT = 1 << 23;
|
||||
|
||||
static const Type tINTEL = 1 << 24;
|
||||
static const Type tAMD = 1 << 25;
|
||||
|
||||
static const Type tENHANCED_REP = 1 << 26; // enhanced rep movsb/stosb
|
||||
static const Type tRDRAND = 1 << 27;
|
||||
static const Type tADX = 1 << 28; // adcx, adox
|
||||
static const Type tRDSEED = 1 << 29; // rdseed
|
||||
static const Type tSMAP = 1 << 30; // stac
|
||||
static const Type tHLE = uint64(1) << 31; // xacquire, xrelease, xtest
|
||||
static const Type tRTM = uint64(1) << 32; // xbegin, xend, xabort
|
||||
|
||||
Cpu()
|
||||
: type_(NONE)
|
||||
{
|
||||
unsigned int data[4];
|
||||
getCpuid(0, data);
|
||||
const unsigned int maxNum = data[0];
|
||||
static const char intel[] = "ntel";
|
||||
static const char amd[] = "cAMD";
|
||||
if (data[2] == get32bitAsBE(amd)) {
|
||||
type_ |= tAMD;
|
||||
getCpuid(0x80000001, data);
|
||||
if (data[3] & (1U << 31)) type_ |= t3DN;
|
||||
if (data[3] & (1U << 15)) type_ |= tCMOV;
|
||||
if (data[3] & (1U << 30)) type_ |= tE3DN;
|
||||
if (data[3] & (1U << 22)) type_ |= tMMX2;
|
||||
if (data[3] & (1U << 27)) type_ |= tRDTSCP;
|
||||
}
|
||||
if (data[2] == get32bitAsBE(intel)) {
|
||||
type_ |= tINTEL;
|
||||
getCpuid(0x80000001, data);
|
||||
if (data[3] & (1U << 27)) type_ |= tRDTSCP;
|
||||
if (data[2] & (1U << 5)) type_ |= tLZCNT;
|
||||
}
|
||||
getCpuid(1, data);
|
||||
if (data[2] & (1U << 0)) type_ |= tSSE3;
|
||||
if (data[2] & (1U << 9)) type_ |= tSSSE3;
|
||||
if (data[2] & (1U << 19)) type_ |= tSSE41;
|
||||
if (data[2] & (1U << 20)) type_ |= tSSE42;
|
||||
if (data[2] & (1U << 23)) type_ |= tPOPCNT;
|
||||
if (data[2] & (1U << 25)) type_ |= tAESNI;
|
||||
if (data[2] & (1U << 1)) type_ |= tPCLMULQDQ;
|
||||
if (data[2] & (1U << 27)) type_ |= tOSXSAVE;
|
||||
if (data[2] & (1U << 30)) type_ |= tRDRAND;
|
||||
|
||||
if (data[3] & (1U << 15)) type_ |= tCMOV;
|
||||
if (data[3] & (1U << 23)) type_ |= tMMX;
|
||||
if (data[3] & (1U << 25)) type_ |= tMMX2 | tSSE;
|
||||
if (data[3] & (1U << 26)) type_ |= tSSE2;
|
||||
|
||||
if (type_ & tOSXSAVE) {
|
||||
// check XFEATURE_ENABLED_MASK[2:1] = '11b'
|
||||
uint64 bv = getXfeature();
|
||||
if ((bv & 6) == 6) {
|
||||
if (data[2] & (1U << 28)) type_ |= tAVX;
|
||||
if (data[2] & (1U << 12)) type_ |= tFMA;
|
||||
}
|
||||
}
|
||||
if (maxNum >= 7) {
|
||||
getCpuidEx(7, 0, data);
|
||||
if (type_ & tAVX && data[1] & 0x20) type_ |= tAVX2;
|
||||
if (data[1] & (1U << 3)) type_ |= tBMI1;
|
||||
if (data[1] & (1U << 8)) type_ |= tBMI2;
|
||||
if (data[1] & (1U << 9)) type_ |= tENHANCED_REP;
|
||||
if (data[1] & (1U << 18)) type_ |= tRDSEED;
|
||||
if (data[1] & (1U << 19)) type_ |= tADX;
|
||||
if (data[1] & (1U << 20)) type_ |= tSMAP;
|
||||
if (data[1] & (1U << 4)) type_ |= tHLE;
|
||||
if (data[1] & (1U << 11)) type_ |= tRTM;
|
||||
}
|
||||
setFamily();
|
||||
}
|
||||
void putFamily()
|
||||
{
|
||||
printf("family=%d, model=%X, stepping=%d, extFamily=%d, extModel=%X\n",
|
||||
family, model, stepping, extFamily, extModel);
|
||||
printf("display:family=%X, model=%X\n", displayFamily, displayModel);
|
||||
}
|
||||
bool has(Type type) const
|
||||
{
|
||||
return (type & type_) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Clock {
|
||||
public:
|
||||
static inline uint64 getRdtsc()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return __rdtsc();
|
||||
#else
|
||||
unsigned int eax, edx;
|
||||
__asm__ volatile("rdtsc" : "=a"(eax), "=d"(edx));
|
||||
return ((uint64)edx << 32) | eax;
|
||||
#endif
|
||||
}
|
||||
Clock()
|
||||
: clock_(0)
|
||||
, count_(0)
|
||||
{
|
||||
}
|
||||
void begin()
|
||||
{
|
||||
clock_ -= getRdtsc();
|
||||
}
|
||||
void end()
|
||||
{
|
||||
clock_ += getRdtsc();
|
||||
count_++;
|
||||
}
|
||||
int getCount() const { return count_; }
|
||||
uint64 getClock() const { return clock_; }
|
||||
void clear() { count_ = 0; clock_ = 0; }
|
||||
private:
|
||||
uint64 clock_;
|
||||
int count_;
|
||||
};
|
||||
|
||||
#ifdef XBYAK64
|
||||
const int UseRCX = 1 << 6;
|
||||
const int UseRDX = 1 << 7;
|
||||
|
||||
class Pack {
|
||||
static const size_t maxTblNum = 10;
|
||||
const Xbyak::Reg64 *tbl_[maxTblNum];
|
||||
size_t n_;
|
||||
public:
|
||||
Pack() : n_(0) {}
|
||||
Pack(const Xbyak::Reg64 *tbl, size_t n) { init(tbl, n); }
|
||||
Pack(const Pack& rhs)
|
||||
: n_(rhs.n_)
|
||||
{
|
||||
if (n_ > maxTblNum) throw Error(ERR_INTERNAL);
|
||||
for (size_t i = 0; i < n_; i++) tbl_[i] = rhs.tbl_[i];
|
||||
}
|
||||
Pack(const Xbyak::Reg64& t0)
|
||||
{ n_ = 1; tbl_[0] = &t0; }
|
||||
Pack(const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 2; tbl_[0] = &t0; tbl_[1] = &t1; }
|
||||
Pack(const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 3; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; }
|
||||
Pack(const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 4; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; }
|
||||
Pack(const Xbyak::Reg64& t4, const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 5; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; tbl_[4] = &t4; }
|
||||
Pack(const Xbyak::Reg64& t5, const Xbyak::Reg64& t4, const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 6; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; tbl_[4] = &t4; tbl_[5] = &t5; }
|
||||
Pack(const Xbyak::Reg64& t6, const Xbyak::Reg64& t5, const Xbyak::Reg64& t4, const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 7; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; tbl_[4] = &t4; tbl_[5] = &t5; tbl_[6] = &t6; }
|
||||
Pack(const Xbyak::Reg64& t7, const Xbyak::Reg64& t6, const Xbyak::Reg64& t5, const Xbyak::Reg64& t4, const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 8; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; tbl_[4] = &t4; tbl_[5] = &t5; tbl_[6] = &t6; tbl_[7] = &t7; }
|
||||
Pack(const Xbyak::Reg64& t8, const Xbyak::Reg64& t7, const Xbyak::Reg64& t6, const Xbyak::Reg64& t5, const Xbyak::Reg64& t4, const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 9; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; tbl_[4] = &t4; tbl_[5] = &t5; tbl_[6] = &t6; tbl_[7] = &t7; tbl_[8] = &t8; }
|
||||
Pack(const Xbyak::Reg64& t9, const Xbyak::Reg64& t8, const Xbyak::Reg64& t7, const Xbyak::Reg64& t6, const Xbyak::Reg64& t5, const Xbyak::Reg64& t4, const Xbyak::Reg64& t3, const Xbyak::Reg64& t2, const Xbyak::Reg64& t1, const Xbyak::Reg64& t0)
|
||||
{ n_ = 10; tbl_[0] = &t0; tbl_[1] = &t1; tbl_[2] = &t2; tbl_[3] = &t3; tbl_[4] = &t4; tbl_[5] = &t5; tbl_[6] = &t6; tbl_[7] = &t7; tbl_[8] = &t8; tbl_[9] = &t9; }
|
||||
Pack& append(const Xbyak::Reg64& t)
|
||||
{
|
||||
if (n_ == 10) {
|
||||
fprintf(stderr, "ERR Pack::can't append\n");
|
||||
throw Error(ERR_BAD_PARAMETER);
|
||||
}
|
||||
tbl_[n_++] = &t;
|
||||
return *this;
|
||||
}
|
||||
void init(const Xbyak::Reg64 *tbl, size_t n)
|
||||
{
|
||||
if (n > maxTblNum) {
|
||||
fprintf(stderr, "ERR Pack::init bad n=%d\n", (int)n);
|
||||
throw Error(ERR_BAD_PARAMETER);
|
||||
}
|
||||
n_ = n;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
tbl_[i] = &tbl[i];
|
||||
}
|
||||
}
|
||||
const Xbyak::Reg64& operator[](size_t n) const
|
||||
{
|
||||
if (n >= n_) {
|
||||
fprintf(stderr, "ERR Pack bad n=%d\n", (int)n);
|
||||
throw Error(ERR_BAD_PARAMETER);
|
||||
}
|
||||
return *tbl_[n];
|
||||
}
|
||||
size_t size() const { return n_; }
|
||||
/*
|
||||
get tbl[pos, pos + num)
|
||||
*/
|
||||
Pack sub(size_t pos, size_t num = size_t(-1)) const
|
||||
{
|
||||
if (num == size_t(-1)) num = n_ - pos;
|
||||
if (pos + num > n_) {
|
||||
fprintf(stderr, "ERR Pack::sub bad pos=%d, num=%d\n", (int)pos, (int)num);
|
||||
throw Error(ERR_BAD_PARAMETER);
|
||||
}
|
||||
Pack pack;
|
||||
pack.n_ = num;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
pack.tbl_[i] = tbl_[pos + i];
|
||||
}
|
||||
return pack;
|
||||
}
|
||||
void put() const
|
||||
{
|
||||
for (size_t i = 0; i < n_; i++) {
|
||||
printf("%s ", tbl_[i]->toString());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
};
|
||||
|
||||
class StackFrame {
|
||||
#ifdef XBYAK64_WIN
|
||||
static const int noSaveNum = 6;
|
||||
static const int rcxPos = 0;
|
||||
static const int rdxPos = 1;
|
||||
#else
|
||||
static const int noSaveNum = 8;
|
||||
static const int rcxPos = 3;
|
||||
static const int rdxPos = 2;
|
||||
#endif
|
||||
Xbyak::CodeGenerator *code_;
|
||||
int pNum_;
|
||||
int tNum_;
|
||||
bool useRcx_;
|
||||
bool useRdx_;
|
||||
int saveNum_;
|
||||
int P_;
|
||||
bool makeEpilog_;
|
||||
Xbyak::Reg64 pTbl_[4];
|
||||
Xbyak::Reg64 tTbl_[10];
|
||||
Pack p_;
|
||||
Pack t_;
|
||||
StackFrame(const StackFrame&);
|
||||
void operator=(const StackFrame&);
|
||||
public:
|
||||
const Pack& p;
|
||||
const Pack& t;
|
||||
/*
|
||||
make stack frame
|
||||
@param sf [in] this
|
||||
@param pNum [in] num of function parameter(0 <= pNum <= 4)
|
||||
@param tNum [in] num of temporary register(0 <= tNum <= 10, with UseRCX, UseRDX)
|
||||
@param stackSizeByte [in] local stack size
|
||||
@param makeEpilog [in] automatically call close() if true
|
||||
|
||||
you can use
|
||||
rax
|
||||
gp0, ..., gp(pNum - 1)
|
||||
gt0, ..., gt(tNum-1)
|
||||
rcx if tNum & UseRCX
|
||||
rdx if tNum & UseRDX
|
||||
rsp[0..stackSizeByte - 1]
|
||||
*/
|
||||
StackFrame(Xbyak::CodeGenerator *code, int pNum, int tNum = 0, int stackSizeByte = 0, bool makeEpilog = true)
|
||||
: code_(code)
|
||||
, pNum_(pNum)
|
||||
, tNum_(tNum & ~(UseRCX | UseRDX))
|
||||
, useRcx_((tNum & UseRCX) != 0)
|
||||
, useRdx_((tNum & UseRDX) != 0)
|
||||
, saveNum_(0)
|
||||
, P_(0)
|
||||
, makeEpilog_(makeEpilog)
|
||||
, p(p_)
|
||||
, t(t_)
|
||||
{
|
||||
using namespace Xbyak;
|
||||
if (pNum < 0 || pNum > 4) throw Error(ERR_BAD_PNUM);
|
||||
const int allRegNum = pNum + tNum_ + (useRcx_ ? 1 : 0) + (useRdx_ ? 1 : 0);
|
||||
if (allRegNum < pNum || allRegNum > 14) throw Error(ERR_BAD_TNUM);
|
||||
const Reg64& _rsp = code->rsp;
|
||||
const AddressFrame& _ptr = code->ptr;
|
||||
saveNum_ = (std::max)(0, allRegNum - noSaveNum);
|
||||
const int *tbl = getOrderTbl() + noSaveNum;
|
||||
P_ = saveNum_ + (stackSizeByte + 7) / 8;
|
||||
if (P_ > 0 && (P_ & 1) == 0) P_++; // here (rsp % 16) == 8, then increment P_ for 16 byte alignment
|
||||
P_ *= 8;
|
||||
if (P_ > 0) code->sub(_rsp, P_);
|
||||
#ifdef XBYAK64_WIN
|
||||
for (int i = 0; i < (std::min)(saveNum_, 4); i++) {
|
||||
code->mov(_ptr [_rsp + P_ + (i + 1) * 8], Reg64(tbl[i]));
|
||||
}
|
||||
for (int i = 4; i < saveNum_; i++) {
|
||||
code->mov(_ptr [_rsp + P_ - 8 * (saveNum_ - i)], Reg64(tbl[i]));
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < saveNum_; i++) {
|
||||
code->mov(_ptr [_rsp + P_ - 8 * (saveNum_ - i)], Reg64(tbl[i]));
|
||||
}
|
||||
#endif
|
||||
int pos = 0;
|
||||
for (int i = 0; i < pNum; i++) {
|
||||
pTbl_[i] = Xbyak::Reg64(getRegIdx(pos));
|
||||
}
|
||||
for (int i = 0; i < tNum_; i++) {
|
||||
tTbl_[i] = Xbyak::Reg64(getRegIdx(pos));
|
||||
}
|
||||
if (useRcx_ && rcxPos < pNum) code_->mov(code_->r10, code_->rcx);
|
||||
if (useRdx_ && rdxPos < pNum) code_->mov(code_->r11, code_->rdx);
|
||||
p_.init(pTbl_, pNum);
|
||||
t_.init(tTbl_, tNum_);
|
||||
}
|
||||
/*
|
||||
make epilog manually
|
||||
@param callRet [in] call ret() if true
|
||||
*/
|
||||
void close(bool callRet = true)
|
||||
{
|
||||
using namespace Xbyak;
|
||||
const Reg64& _rsp = code_->rsp;
|
||||
const AddressFrame& _ptr = code_->ptr;
|
||||
const int *tbl = getOrderTbl() + noSaveNum;
|
||||
#ifdef XBYAK64_WIN
|
||||
for (int i = 0; i < (std::min)(saveNum_, 4); i++) {
|
||||
code_->mov(Reg64(tbl[i]), _ptr [_rsp + P_ + (i + 1) * 8]);
|
||||
}
|
||||
for (int i = 4; i < saveNum_; i++) {
|
||||
code_->mov(Reg64(tbl[i]), _ptr [_rsp + P_ - 8 * (saveNum_ - i)]);
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < saveNum_; i++) {
|
||||
code_->mov(Reg64(tbl[i]), _ptr [_rsp + P_ - 8 * (saveNum_ - i)]);
|
||||
}
|
||||
#endif
|
||||
if (P_ > 0) code_->add(_rsp, P_);
|
||||
|
||||
if (callRet) code_->ret();
|
||||
}
|
||||
~StackFrame()
|
||||
{
|
||||
if (!makeEpilog_) return;
|
||||
try {
|
||||
close();
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:StackFrame %s\n", e.what());
|
||||
exit(1);
|
||||
} catch (...) {
|
||||
printf("ERR:StackFrame otherwise\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
private:
|
||||
const int *getOrderTbl() const
|
||||
{
|
||||
using namespace Xbyak;
|
||||
static const int tbl[] = {
|
||||
#ifdef XBYAK64_WIN
|
||||
Operand::RCX, Operand::RDX, Operand::R8, Operand::R9, Operand::R10, Operand::R11, Operand::RDI, Operand::RSI,
|
||||
#else
|
||||
Operand::RDI, Operand::RSI, Operand::RDX, Operand::RCX, Operand::R8, Operand::R9, Operand::R10, Operand::R11,
|
||||
#endif
|
||||
Operand::RBX, Operand::RBP, Operand::R12, Operand::R13, Operand::R14, Operand::R15
|
||||
};
|
||||
return &tbl[0];
|
||||
}
|
||||
int getRegIdx(int& pos) const
|
||||
{
|
||||
assert(pos < 14);
|
||||
using namespace Xbyak;
|
||||
const int *tbl = getOrderTbl();
|
||||
int r = tbl[pos++];
|
||||
if (useRcx_) {
|
||||
if (r == Operand::RCX) { return Operand::R10; }
|
||||
if (r == Operand::R10) { r = tbl[pos++]; }
|
||||
}
|
||||
if (useRdx_) {
|
||||
if (r == Operand::RDX) { return Operand::R11; }
|
||||
if (r == Operand::R11) { return tbl[pos++]; }
|
||||
}
|
||||
return r;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} } // end of util
|
||||
#endif
|
|
@ -3,6 +3,10 @@
|
|||
#include "burnint.h"
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef MIPS3_X64_DRC
|
||||
#include "mips3/x64/mips3_x64.h"
|
||||
#endif
|
||||
|
||||
#define ADDR_BITS 32
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define PAGE_SHIFT 12
|
||||
|
@ -27,9 +31,13 @@ struct Mips3MemoryMap
|
|||
};
|
||||
|
||||
|
||||
static mips::mips3 *g_mips;
|
||||
static Mips3MemoryMap *g_mmap;
|
||||
static mips::mips3 *g_mips = nullptr;
|
||||
static Mips3MemoryMap *g_mmap = nullptr;
|
||||
static bool g_useRecompiler = false;
|
||||
|
||||
#ifdef MIPS3_X64_DRC
|
||||
static mips::mips3_x64 *g_mips_x64 = nullptr;
|
||||
#endif
|
||||
|
||||
static unsigned char DefReadByte(unsigned int a) { return 0; }
|
||||
static unsigned short DefReadHalf(unsigned int a) { return 0; }
|
||||
|
@ -65,11 +73,23 @@ int Mips3Init()
|
|||
g_mips = new mips::mips3();
|
||||
g_mmap = new Mips3MemoryMap();
|
||||
|
||||
#ifdef MIPS3_X64_DRC
|
||||
g_mips_x64 = new mips::mips3_x64(g_mips);
|
||||
#endif
|
||||
|
||||
ResetMemoryMap();
|
||||
}
|
||||
|
||||
int Mips3UseRecompiler(bool use)
|
||||
{
|
||||
g_useRecompiler = use;
|
||||
}
|
||||
|
||||
int Mips3Exit()
|
||||
{
|
||||
#ifdef MIPS3_X64_DRC
|
||||
delete g_mips_x64;
|
||||
#endif
|
||||
delete g_mips;
|
||||
delete g_mmap;
|
||||
g_mips = nullptr;
|
||||
|
@ -85,8 +105,18 @@ void Mips3Reset()
|
|||
|
||||
int Mips3Run(int cycles)
|
||||
{
|
||||
#ifdef MIPS3_X64_DRC
|
||||
if (g_mips) {
|
||||
if (g_useRecompiler && g_mips_x64) {
|
||||
g_mips_x64->run(cycles);
|
||||
} else {
|
||||
g_mips->run(cycles);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (g_mips)
|
||||
g_mips->run(cycles);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ typedef unsigned long long (*pMips3ReadDoubleHandler)(unsigned int a);
|
|||
typedef void (*pMips3WriteDoubleHandler)(unsigned int a, unsigned long long d);
|
||||
|
||||
int Mips3Init();
|
||||
int Mips3UseRecompiler(bool use);
|
||||
int Mips3Exit();
|
||||
void Mips3Reset();
|
||||
int Mips3Run(int cycles);
|
||||
|
|
Loading…
Reference in New Issue