DSPEmitter: Make conditional JIT functions in DSPJitBranch part of the emitter
These quite clearly have a dependency on the emitter itself, so these should be a part of the emitter itself. The template function can be modified to just simply take functions as a parameter.
This commit is contained in:
parent
16aac00b8a
commit
970d969f63
|
@ -259,6 +259,17 @@ public:
|
||||||
DSPJitRegCache m_gpr{*this};
|
DSPJitRegCache m_gpr{*this};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void WriteBranchExit();
|
||||||
|
void WriteBlockLink(u16 dest);
|
||||||
|
|
||||||
|
void ReJitConditional(UDSPInstruction opc, void (DSPEmitter::*conditional_fn)(UDSPInstruction));
|
||||||
|
void r_jcc(UDSPInstruction opc);
|
||||||
|
void r_jmprcc(UDSPInstruction opc);
|
||||||
|
void r_call(UDSPInstruction opc);
|
||||||
|
void r_callr(UDSPInstruction opc);
|
||||||
|
void r_ifcc(UDSPInstruction opc);
|
||||||
|
void r_ret(UDSPInstruction opc);
|
||||||
|
|
||||||
void Update_SR_Register(Gen::X64Reg val = Gen::EAX);
|
void Update_SR_Register(Gen::X64Reg val = Gen::EAX);
|
||||||
|
|
||||||
void get_long_prod(Gen::X64Reg long_prod = Gen::RAX);
|
void get_long_prod(Gen::X64Reg long_prod = Gen::RAX);
|
||||||
|
|
|
@ -18,126 +18,125 @@ namespace JIT
|
||||||
{
|
{
|
||||||
namespace x86
|
namespace x86
|
||||||
{
|
{
|
||||||
template <void (*jitCode)(const UDSPInstruction, DSPEmitter&)>
|
void DSPEmitter::ReJitConditional(const UDSPInstruction opc,
|
||||||
static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter)
|
void (DSPEmitter::*conditional_fn)(UDSPInstruction))
|
||||||
{
|
{
|
||||||
u8 cond = opc & 0xf;
|
u8 cond = opc & 0xf;
|
||||||
if (cond == 0xf) // Always true.
|
if (cond == 0xf) // Always true.
|
||||||
{
|
{
|
||||||
jitCode(opc, emitter);
|
(this->*conditional_fn)(opc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emitter.dsp_op_read_reg(DSP_REG_SR, EAX);
|
dsp_op_read_reg(DSP_REG_SR, EAX);
|
||||||
|
|
||||||
switch (cond)
|
switch (cond)
|
||||||
{
|
{
|
||||||
case 0x0: // GE - Greater Equal
|
case 0x0: // GE - Greater Equal
|
||||||
case 0x1: // L - Less
|
case 0x1: // L - Less
|
||||||
emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0));
|
LEA(16, EDX, MScaled(EAX, SCALE_4, 0));
|
||||||
emitter.XOR(16, R(EAX), R(EDX));
|
XOR(16, R(EAX), R(EDX));
|
||||||
emitter.TEST(16, R(EAX), Imm16(8));
|
TEST(16, R(EAX), Imm16(8));
|
||||||
break;
|
break;
|
||||||
case 0x2: // G - Greater
|
case 0x2: // G - Greater
|
||||||
case 0x3: // LE - Less Equal
|
case 0x3: // LE - Less Equal
|
||||||
emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0));
|
LEA(16, EDX, MScaled(EAX, SCALE_4, 0));
|
||||||
emitter.XOR(16, R(EAX), R(EDX));
|
XOR(16, R(EAX), R(EDX));
|
||||||
emitter.LEA(16, EAX, MScaled(EAX, SCALE_2, 0));
|
LEA(16, EAX, MScaled(EAX, SCALE_2, 0));
|
||||||
emitter.OR(16, R(EAX), R(EDX));
|
OR(16, R(EAX), R(EDX));
|
||||||
emitter.TEST(16, R(EAX), Imm16(0x10));
|
TEST(16, R(EAX), Imm16(0x10));
|
||||||
break;
|
break;
|
||||||
case 0x4: // NZ - Not Zero
|
case 0x4: // NZ - Not Zero
|
||||||
case 0x5: // Z - Zero
|
case 0x5: // Z - Zero
|
||||||
emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO));
|
TEST(16, R(EAX), Imm16(SR_ARITH_ZERO));
|
||||||
break;
|
break;
|
||||||
case 0x6: // NC - Not carry
|
case 0x6: // NC - Not carry
|
||||||
case 0x7: // C - Carry
|
case 0x7: // C - Carry
|
||||||
emitter.TEST(16, R(EAX), Imm16(SR_CARRY));
|
TEST(16, R(EAX), Imm16(SR_CARRY));
|
||||||
break;
|
break;
|
||||||
case 0x8: // ? - Not over s32
|
case 0x8: // ? - Not over s32
|
||||||
case 0x9: // ? - Over s32
|
case 0x9: // ? - Over s32
|
||||||
emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32));
|
TEST(16, R(EAX), Imm16(SR_OVER_S32));
|
||||||
break;
|
break;
|
||||||
case 0xa: // ?
|
case 0xa: // ?
|
||||||
case 0xb: // ?
|
case 0xb: // ?
|
||||||
emitter.LEA(16, EDX, MScaled(EAX, SCALE_2, 0));
|
LEA(16, EDX, MScaled(EAX, SCALE_2, 0));
|
||||||
emitter.OR(16, R(EAX), R(EDX));
|
OR(16, R(EAX), R(EDX));
|
||||||
emitter.LEA(16, EDX, MScaled(EDX, SCALE_8, 0));
|
LEA(16, EDX, MScaled(EDX, SCALE_8, 0));
|
||||||
emitter.NOT(16, R(EAX));
|
NOT(16, R(EAX));
|
||||||
emitter.OR(16, R(EAX), R(EDX));
|
OR(16, R(EAX), R(EDX));
|
||||||
emitter.TEST(16, R(EAX), Imm16(0x20));
|
TEST(16, R(EAX), Imm16(0x20));
|
||||||
break;
|
break;
|
||||||
case 0xc: // LNZ - Logic Not Zero
|
case 0xc: // LNZ - Logic Not Zero
|
||||||
case 0xd: // LZ - Logic Zero
|
case 0xd: // LZ - Logic Zero
|
||||||
emitter.TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO));
|
TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO));
|
||||||
break;
|
break;
|
||||||
case 0xe: // 0 - Overflow
|
case 0xe: // 0 - Overflow
|
||||||
emitter.TEST(16, R(EAX), Imm16(SR_OVERFLOW));
|
TEST(16, R(EAX), Imm16(SR_OVERFLOW));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DSPJitRegCache c1(emitter.m_gpr);
|
DSPJitRegCache c1(m_gpr);
|
||||||
FixupBranch skipCode =
|
FixupBranch skip_code =
|
||||||
cond == 0xe ? emitter.J_CC(CC_E, true) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1)), true);
|
cond == 0xe ? J_CC(CC_E, true) : J_CC((CCFlags)(CC_NE - (cond & 1)), true);
|
||||||
jitCode(opc, emitter);
|
(this->*conditional_fn)(opc);
|
||||||
emitter.m_gpr.FlushRegs(c1);
|
m_gpr.FlushRegs(c1);
|
||||||
emitter.SetJumpTarget(skipCode);
|
SetJumpTarget(skip_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteBranchExit(DSPEmitter& emitter)
|
void DSPEmitter::WriteBranchExit()
|
||||||
{
|
{
|
||||||
DSPJitRegCache c(emitter.m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
emitter.m_gpr.SaveRegs();
|
m_gpr.SaveRegs();
|
||||||
if (Analyzer::GetCodeFlags(emitter.m_start_address) & Analyzer::CODE_IDLE_SKIP)
|
if (Analyzer::GetCodeFlags(m_start_address) & Analyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
emitter.MOV(16, R(EAX), Imm16(0x1000));
|
MOV(16, R(EAX), Imm16(0x1000));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emitter.MOV(16, R(EAX), Imm16(emitter.m_block_size[emitter.m_start_address]));
|
MOV(16, R(EAX), Imm16(m_block_size[m_start_address]));
|
||||||
}
|
}
|
||||||
emitter.JMP(emitter.m_return_dispatcher, true);
|
JMP(m_return_dispatcher, true);
|
||||||
emitter.m_gpr.LoadRegs(false);
|
m_gpr.LoadRegs(false);
|
||||||
emitter.m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteBlockLink(DSPEmitter& emitter, u16 dest)
|
void DSPEmitter::WriteBlockLink(u16 dest)
|
||||||
{
|
{
|
||||||
// Jump directly to the called block if it has already been compiled.
|
// Jump directly to the called block if it has already been compiled.
|
||||||
if (!(dest >= emitter.m_start_address && dest <= emitter.m_compile_pc))
|
if (!(dest >= m_start_address && dest <= m_compile_pc))
|
||||||
{
|
{
|
||||||
if (emitter.m_block_links[dest] != nullptr)
|
if (m_block_links[dest] != nullptr)
|
||||||
{
|
{
|
||||||
emitter.m_gpr.FlushRegs();
|
m_gpr.FlushRegs();
|
||||||
// Check if we have enough cycles to execute the next block
|
// Check if we have enough cycles to execute the next block
|
||||||
emitter.MOV(16, R(ECX), M(&g_cycles_left));
|
MOV(16, R(ECX), M(&g_cycles_left));
|
||||||
emitter.CMP(16, R(ECX), Imm16(emitter.m_block_size[emitter.m_start_address] +
|
CMP(16, R(ECX), Imm16(m_block_size[m_start_address] + m_block_size[dest]));
|
||||||
emitter.m_block_size[dest]));
|
FixupBranch notEnoughCycles = J_CC(CC_BE);
|
||||||
FixupBranch notEnoughCycles = emitter.J_CC(CC_BE);
|
|
||||||
|
|
||||||
emitter.SUB(16, R(ECX), Imm16(emitter.m_block_size[emitter.m_start_address]));
|
SUB(16, R(ECX), Imm16(m_block_size[m_start_address]));
|
||||||
emitter.MOV(16, M(&g_cycles_left), R(ECX));
|
MOV(16, M(&g_cycles_left), R(ECX));
|
||||||
emitter.JMP(emitter.m_block_links[dest], true);
|
JMP(m_block_links[dest], true);
|
||||||
emitter.SetJumpTarget(notEnoughCycles);
|
SetJumpTarget(notEnoughCycles);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The destination has not been compiled yet. Add it to the list
|
// The destination has not been compiled yet. Add it to the list
|
||||||
// of blocks that this block is waiting on.
|
// of blocks that this block is waiting on.
|
||||||
emitter.m_unresolved_jumps[emitter.m_start_address].push_back(dest);
|
m_unresolved_jumps[m_start_address].push_back(dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
void DSPEmitter::r_jcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 dest = dsp_imem_read(emitter.m_compile_pc + 1);
|
u16 dest = dsp_imem_read(m_compile_pc + 1);
|
||||||
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
||||||
|
|
||||||
// If the block is unconditional, attempt to link block
|
// If the block is unconditional, attempt to link block
|
||||||
if (opcode->uncond_branch)
|
if (opcode->uncond_branch)
|
||||||
WriteBlockLink(emitter, dest);
|
WriteBlockLink(dest);
|
||||||
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
|
MOV(16, M(&g_dsp.pc), Imm16(dest));
|
||||||
WriteBranchExit(emitter);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
// Generic jmp implementation
|
// Generic jmp implementation
|
||||||
// Jcc addressA
|
// Jcc addressA
|
||||||
|
@ -149,17 +148,17 @@ static void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
void DSPEmitter::jcc(const UDSPInstruction opc)
|
void DSPEmitter::jcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
MOV(16, M(&(g_dsp.pc)), Imm16(m_compile_pc + 2));
|
MOV(16, M(&(g_dsp.pc)), Imm16(m_compile_pc + 2));
|
||||||
ReJitConditional<r_jcc>(opc, *this);
|
ReJitConditional(opc, &DSPEmitter::r_jcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
void DSPEmitter::r_jmprcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 5) & 0x7;
|
u8 reg = (opc >> 5) & 0x7;
|
||||||
// reg can only be DSP_REG_ARx and DSP_REG_IXx now,
|
// reg can only be DSP_REG_ARx and DSP_REG_IXx now,
|
||||||
// no need to handle DSP_REG_STx.
|
// no need to handle DSP_REG_STx.
|
||||||
emitter.dsp_op_read_reg(reg, RAX);
|
dsp_op_read_reg(reg, RAX);
|
||||||
emitter.MOV(16, M(&g_dsp.pc), R(EAX));
|
MOV(16, M(&g_dsp.pc), R(EAX));
|
||||||
WriteBranchExit(emitter);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
// Generic jmpr implementation
|
// Generic jmpr implementation
|
||||||
// JMPcc $R
|
// JMPcc $R
|
||||||
|
@ -169,21 +168,21 @@ static void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
void DSPEmitter::jmprcc(const UDSPInstruction opc)
|
void DSPEmitter::jmprcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
||||||
ReJitConditional<r_jmprcc>(opc, *this);
|
ReJitConditional(opc, &DSPEmitter::r_jmprcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r_call(const UDSPInstruction opc, DSPEmitter& emitter)
|
void DSPEmitter::r_call(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
emitter.MOV(16, R(DX), Imm16(emitter.m_compile_pc + 2));
|
MOV(16, R(DX), Imm16(m_compile_pc + 2));
|
||||||
emitter.dsp_reg_store_stack(DSP_STACK_C);
|
dsp_reg_store_stack(DSP_STACK_C);
|
||||||
u16 dest = dsp_imem_read(emitter.m_compile_pc + 1);
|
u16 dest = dsp_imem_read(m_compile_pc + 1);
|
||||||
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
||||||
|
|
||||||
// If the block is unconditional, attempt to link block
|
// If the block is unconditional, attempt to link block
|
||||||
if (opcode->uncond_branch)
|
if (opcode->uncond_branch)
|
||||||
WriteBlockLink(emitter, dest);
|
WriteBlockLink(dest);
|
||||||
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
|
MOV(16, M(&g_dsp.pc), Imm16(dest));
|
||||||
WriteBranchExit(emitter);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
// Generic call implementation
|
// Generic call implementation
|
||||||
// CALLcc addressA
|
// CALLcc addressA
|
||||||
|
@ -196,17 +195,17 @@ static void r_call(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
void DSPEmitter::call(const UDSPInstruction opc)
|
void DSPEmitter::call(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
MOV(16, M(&(g_dsp.pc)), Imm16(m_compile_pc + 2));
|
MOV(16, M(&(g_dsp.pc)), Imm16(m_compile_pc + 2));
|
||||||
ReJitConditional<r_call>(opc, *this);
|
ReJitConditional(opc, &DSPEmitter::r_call);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r_callr(const UDSPInstruction opc, DSPEmitter& emitter)
|
void DSPEmitter::r_callr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 5) & 0x7;
|
u8 reg = (opc >> 5) & 0x7;
|
||||||
emitter.MOV(16, R(DX), Imm16(emitter.m_compile_pc + 1));
|
MOV(16, R(DX), Imm16(m_compile_pc + 1));
|
||||||
emitter.dsp_reg_store_stack(DSP_STACK_C);
|
dsp_reg_store_stack(DSP_STACK_C);
|
||||||
emitter.dsp_op_read_reg(reg, RAX);
|
dsp_op_read_reg(reg, RAX);
|
||||||
emitter.MOV(16, M(&g_dsp.pc), R(EAX));
|
MOV(16, M(&g_dsp.pc), R(EAX));
|
||||||
WriteBranchExit(emitter);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
// Generic callr implementation
|
// Generic callr implementation
|
||||||
// CALLRcc $R
|
// CALLRcc $R
|
||||||
|
@ -218,12 +217,12 @@ static void r_callr(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
void DSPEmitter::callr(const UDSPInstruction opc)
|
void DSPEmitter::callr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
||||||
ReJitConditional<r_callr>(opc, *this);
|
ReJitConditional(opc, &DSPEmitter::r_callr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r_ifcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
void DSPEmitter::r_ifcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
emitter.MOV(16, M(&g_dsp.pc), Imm16(emitter.m_compile_pc + 1));
|
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
||||||
}
|
}
|
||||||
// Generic if implementation
|
// Generic if implementation
|
||||||
// IFcc
|
// IFcc
|
||||||
|
@ -236,15 +235,15 @@ void DSPEmitter::ifcc(const UDSPInstruction opc)
|
||||||
const DSPOPCTemplate* const op_template = GetOpTemplate(dsp_imem_read(address));
|
const DSPOPCTemplate* const op_template = GetOpTemplate(dsp_imem_read(address));
|
||||||
|
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(address + op_template->size));
|
MOV(16, M(&g_dsp.pc), Imm16(address + op_template->size));
|
||||||
ReJitConditional<r_ifcc>(opc, *this);
|
ReJitConditional(opc, &DSPEmitter::r_ifcc);
|
||||||
WriteBranchExit(*this);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r_ret(const UDSPInstruction opc, DSPEmitter& emitter)
|
void DSPEmitter::r_ret(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
emitter.dsp_reg_load_stack(DSP_STACK_C);
|
dsp_reg_load_stack(DSP_STACK_C);
|
||||||
emitter.MOV(16, M(&g_dsp.pc), R(DX));
|
MOV(16, M(&g_dsp.pc), R(DX));
|
||||||
WriteBranchExit(emitter);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic ret implementation
|
// Generic ret implementation
|
||||||
|
@ -256,7 +255,7 @@ static void r_ret(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
void DSPEmitter::ret(const UDSPInstruction opc)
|
void DSPEmitter::ret(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
MOV(16, M(&g_dsp.pc), Imm16(m_compile_pc + 1));
|
||||||
ReJitConditional<r_ret>(opc, *this);
|
ReJitConditional(opc, &DSPEmitter::r_ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RTI
|
// RTI
|
||||||
|
@ -352,7 +351,7 @@ void DSPEmitter::loop(const UDSPInstruction opc)
|
||||||
SetJumpTarget(cnt);
|
SetJumpTarget(cnt);
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
||||||
WriteBranchExit(*this);
|
WriteBranchExit();
|
||||||
m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
}
|
}
|
||||||
|
@ -385,7 +384,7 @@ void DSPEmitter::loopi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
||||||
WriteBranchExit(*this);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +421,7 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
|
||||||
// g_dsp.pc = loop_pc;
|
// g_dsp.pc = loop_pc;
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
||||||
WriteBranchExit(*this);
|
WriteBranchExit();
|
||||||
m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
}
|
}
|
||||||
|
@ -458,7 +457,7 @@ void DSPEmitter::bloopi(const UDSPInstruction opc)
|
||||||
// g_dsp.pc = loop_pc;
|
// g_dsp.pc = loop_pc;
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
MOV(16, M(&g_dsp.pc), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
||||||
WriteBranchExit(*this);
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue