@@ -231,6 +231,7 @@ extern "C" fn run_one_test(_user: *mut c_void, ctx: *const Context, regs: *mut R
231231 let debug = std:: env:: var ( "CPUTEST_DEBUG" ) . is_ok ( ) ;
232232 let mut hle = NoOpHleHandler ;
233233 cpu. last_exception_vector = None ;
234+ regs. cycles = 0 ;
234235 let mut exc = 0u32 ;
235236 let mut excframe = 0u32 ;
236237 for step in 0 ..MAX_STEPS {
@@ -248,15 +249,32 @@ extern "C" fn run_one_test(_user: *mut c_void, ctx: *const Context, regs: *mut R
248249 & cpu. dar[ ..8 ]
249250 ) ;
250251 }
251- let _ = cpu. step_with_hle_handler ( & mut bus, & mut hle) ;
252+ let step_result = cpu. step_with_hle_handler ( & mut bus, & mut hle) ;
253+ let step_cycles = match step_result {
254+ m68k:: StepResult :: Ok { cycles } => cycles as u32 ,
255+ _ => 0 ,
256+ } ;
257+ let _ = step;
252258 if let Some ( v) = cpu. last_exception_vector . take ( ) {
259+ // The generator's cycle counter stops when the terminating
260+ // sentinel exception is recognized, so the final faulting step
261+ // is not added to the measured total (CPUTEST_CYCLES). A trace
262+ // is the one exception the core bundles with a COMPLETED
263+ // instruction's step: count that instruction, not the 34-clock
264+ // trace stacking.
265+ if v == 9 {
266+ regs. cycles = regs
267+ . cycles
268+ . wrapping_add ( step_cycles. saturating_sub ( 34 ) ) ;
269+ }
253270 exc = v;
254271 excframe = cpu. a ( 7 ) ;
255272 if debug {
256273 eprintln ! ( " -> exception {v} frame={excframe:#010X}" ) ;
257274 }
258275 break ;
259276 }
277+ regs. cycles = regs. cycles . wrapping_add ( step_cycles) ;
260278 // If the tested instruction left T1 set (e.g. RTE restoring a traced
261279 // SR), the trace fires after the NEXT instruction: keep stepping so
262280 // the sentinel at endpc executes and raises the expected trace (or
@@ -266,6 +284,13 @@ extern "C" fn run_one_test(_user: *mut c_void, ctx: *const Context, regs: *mut R
266284 && ( cpu. pc == regs. endpc
267285 || ( regs. branchtarget != 0xFFFF_FFFF && cpu. pc == regs. branchtarget ) )
268286 {
287+ // A taken branch stops on ARRIVAL at the target sentinel; the
288+ // generator's cycle counter also includes the target's leading
289+ // NOP (the linear path executes its trailing NOP before the
290+ // stop, so only this side needs the correction).
291+ if cpu. pc != regs. endpc && bus. read_word ( cpu. pc ) == 0x4E71 {
292+ regs. cycles = regs. cycles . wrapping_add ( 4 ) ;
293+ }
269294 break ;
270295 }
271296 }
0 commit comments