@@ -3111,6 +3111,26 @@ static u32 recScaleBlockCycles(u32 raw)
31113111 return (scale_cycles < 1 ) ? 1 : scale_cycles;
31123112}
31133113
3114+ // True for ops that run the interpreter inline AND need a live, current cpuRegs.cycle.
3115+ // COP2 / VU0-macro ops (opcode 0x12, excluding BC2 branches) sync VU state from
3116+ // cpuRegs.cycle, so commit the block's accumulated cycles before executing them.
3117+ static bool recOpNeedsCycleFlush (u32 op)
3118+ {
3119+ return (op >> 26 ) == 0x12 && ((op >> 21 ) & 0x1f ) != 0x08 ;
3120+ }
3121+
3122+ // Emit: cpuRegs.cycle += recScaleBlockCycles(raw). Used mid-block before inline
3123+ // COP2/VU0-macro interpreter calls so they observe current EE time.
3124+ static void recEmitFlushCycles (u32 raw)
3125+ {
3126+ if (raw == 0 )
3127+ return ;
3128+
3129+ armAsm->Ldr (RSCRATCHADDR , a64::MemOperand (RESTATEPTR , EE_CYCLE_OFFSET ));
3130+ armAsm->Add (RSCRATCHADDR , RSCRATCHADDR , recScaleBlockCycles (raw));
3131+ armAsm->Str (RSCRATCHADDR , a64::MemOperand (RESTATEPTR , EE_CYCLE_OFFSET ));
3132+ }
3133+
31143134// Install a freshly-compiled block's self-modifying-code protection and return the pointer
31153135// to record in its recLUT slot. Direct port of x86 memory_protect_recompiled_code
31163136// (iR5900.cpp), adapted to this port's body-first layout: the caller has already emitted
@@ -3463,6 +3483,10 @@ static void recRecompile(u32 startpc)
34633483 u32 pc = startpc;
34643484 u32 endpc = startpc;
34653485 u32 raw_cycles = 0 ;
3486+ const u32 ee_cycle_mult = 2 - ((cpuRegs.CP0 .n .Config >> 18 ) & 0x1 );
3487+ const auto eeOpCycles = [ee_cycle_mult](u32 opc) -> u32 {
3488+ return (opc == 0 ? 9u : static_cast <u32 >(R5900::GetInstruction (opc).cycles )) * ee_cycle_mult;
3489+ };
34663490 u32 compiled = 0 ;
34673491 bool interp_step = false ;
34683492 bool known_dispatch_pc = false ;
@@ -3491,12 +3515,11 @@ static void recRecompile(u32 startpc)
34913515 }
34923516
34933517 const u32 op = memRead32 (pc);
3494- const R5900 ::OPCODE & info = R5900::GetInstruction (op);
34953518
34963519 if (recIsHandledBranch (op))
34973520 {
34983521 // Terminate the block: branch generator + delay slot + dispatch tail.
3499- raw_cycles += info. cycles ;
3522+ raw_cycles += eeOpCycles (op) ;
35003523 branch_tail = true ;
35013524 tail_reason = " branch" ;
35023525 known_dispatch_pc = recGetKnownBranchTarget (op, pc, const_state, &dispatch_pc);
@@ -3506,7 +3529,7 @@ static void recRecompile(u32 startpc)
35063529 recConstApplyBranchLink (op, pc, const_state);
35073530
35083531 const u32 delay_op = memRead32 (pc + 4 );
3509- raw_cycles += R5900::GetInstruction (delay_op). cycles ;
3532+ raw_cycles += eeOpCycles (delay_op);
35103533 recEmitOp (delay_op, const_state, cache_state); // delay slot — must not write cpuRegs.pc
35113534 endpc = pc + 8 ;
35123535
@@ -3543,7 +3566,7 @@ static void recRecompile(u32 startpc)
35433566 // test + PC select, then jump over the delay-slot code when not taken.
35443567 // The cache/const state diverges across the two paths, so it is flushed
35453568 // and discarded inside the taken path before the skip label.
3546- raw_cycles += info. cycles ;
3569+ raw_cycles += eeOpCycles (op) ;
35473570 branch_tail = true ;
35483571 tail_reason = " branch_likely" ;
35493572
@@ -3558,7 +3581,7 @@ static void recRecompile(u32 startpc)
35583581 armAsm->B (&skip_delay, a64::InvertCondition (taken));
35593582
35603583 const u32 delay_op = memRead32 (pc + 4 );
3561- raw_cycles += R5900::GetInstruction (delay_op). cycles ;
3584+ raw_cycles += eeOpCycles (delay_op);
35623585 recEmitOp (delay_op, const_state, cache_state);
35633586 recCacheFlushAll (cache_state);
35643587 recCacheKillAll (cache_state);
@@ -3572,6 +3595,14 @@ static void recRecompile(u32 startpc)
35723595 break ;
35733596 }
35743597
3598+ const bool needs_cycle_flush = recOpNeedsCycleFlush (op);
3599+ if (needs_cycle_flush)
3600+ {
3601+ raw_cycles += eeOpCycles (op);
3602+ recEmitFlushCycles (raw_cycles);
3603+ raw_cycles = 0 ;
3604+ }
3605+
35753606 // Straight-line op we can codegen? (Generators decode from `op` directly;
35763607 // they never read cpuRegs.code, so nothing to set here at compile time.)
35773608 if (recTranslateOpOptimized (op, const_state, cache_state))
@@ -3582,7 +3613,8 @@ static void recRecompile(u32 startpc)
35823613 else
35833614 waitloop_possible = false ;
35843615
3585- raw_cycles += info.cycles ;
3616+ if (!needs_cycle_flush)
3617+ raw_cycles += eeOpCycles (op);
35863618 pc += 4 ;
35873619 endpc = pc;
35883620 if (++compiled >= MAX_BLOCK_INSTS )
0 commit comments