1mod nums;
2mod registers;
3mod timer;
4
5use core::num::Wrapping;
6
7use nums::{GbBits, GbHalfCarry};
8use thiserror::Error;
9
10use registers::Registers;
11
12use crate::{
13 extern_traits::{GBAllocator, RomReader},
14 isa::*,
15 memcontroller::{
16 interrupts::Interrupts, MemController, MemControllerDecoderErr, ReadError, WriteError,
17 },
18};
19
20pub struct Cpu {
21 timer_cycles: Wrapping<usize>,
22 cycles_remaining: u8,
23 interrupts_master: bool,
24 ei_queued: bool,
26
27 registers: Registers,
28}
29
30#[derive(Debug, Error)]
31pub enum CpuErr {
32 #[error("Error during instruction decoding")]
33 Decode(#[from] MemControllerDecoderErr),
34
35 #[error("Illegal instruction: 0x{:x}", 0)]
36 Illegal(u8),
37
38 #[error("Could not write to memory")]
39 MemWriteError(#[from] WriteError),
40
41 #[error("Could not read from memory")]
42 MemReadError(#[from] ReadError),
43}
44
45macro_rules! instr_todo {
46 ($instr:expr) => {
47 todo!("{}", $instr)
48 };
49}
50
51impl Cpu {
52 pub fn new() -> Self {
53 Cpu {
54 timer_cycles: Wrapping(0),
55 cycles_remaining: 0,
56 interrupts_master: false,
57 ei_queued: false,
58 registers: Registers::new(),
59 }
60 }
61
62 #[inline]
63 const fn get_reg16_value(&self, reg: Reg16) -> u16 {
64 match reg {
65 Reg16::AF => self.registers.af(),
66 Reg16::BC => self.registers.bc(),
67 Reg16::DE => self.registers.de(),
68 Reg16::HL => self.registers.hl(),
69 Reg16::SP => self.registers.sp(),
70 }
71 }
72
73 #[inline]
74 const fn get_reg8_value(&self, reg: Reg8) -> u8 {
75 match reg {
76 Reg8::A => self.registers.a(),
77 Reg8::B => self.registers.b(),
78 Reg8::C => self.registers.c(),
79 Reg8::D => self.registers.d(),
80 Reg8::E => self.registers.e(),
81 Reg8::F => self.registers.f(),
82 Reg8::H => self.registers.h(),
83 Reg8::L => self.registers.l(),
84 }
85 }
86
87 #[inline]
88 fn set_reg8_value(&mut self, reg: Reg8, val: u8) {
89 match reg {
90 Reg8::A => self.registers.set_a(val),
91 Reg8::B => self.registers.set_b(val),
92 Reg8::C => self.registers.set_c(val),
93 Reg8::D => self.registers.set_d(val),
94 Reg8::E => self.registers.set_e(val),
95 Reg8::F => self.registers.set_f(val),
96 Reg8::H => self.registers.set_h(val),
97 Reg8::L => self.registers.set_l(val),
98 }
99 }
100
101 #[inline]
102 fn set_reg16_value(&mut self, reg: Reg16, val: u16) {
103 match reg {
104 Reg16::AF => self.registers.set_af(val),
105 Reg16::BC => self.registers.set_bc(val),
106 Reg16::DE => self.registers.set_de(val),
107 Reg16::HL => self.registers.set_hl(val),
108 Reg16::SP => self.registers.set_sp(val),
109 }
110 }
111
112 fn memloc_to_addr(&self, memloc: MemLoc) -> u16 {
113 match memloc {
114 MemLoc::HighMemReg(reg) => 0xFF00 | (self.get_reg8_value(reg) as u16),
115 MemLoc::Reg(reg) => self.get_reg16_value(reg),
116 MemLoc::HighMemImm(imm) => 0xFF00 | (imm as u16),
117 MemLoc::Imm(imm) => imm,
118 }
119 }
120
121 fn check_condition(&self, cond: Condition) -> bool {
122 match cond {
123 Condition::Zero => self.registers.zero_flag(),
124 Condition::NotZero => !self.registers.zero_flag(),
125 Condition::Carry => self.registers.carry_flag(),
126 Condition::NotCarry => !self.registers.carry_flag(),
127 }
128 }
129
130 fn do_rel_jump(&mut self, base: u16, offset: i8) {
131 let jump_addr = u16::try_from((base as i32) + (offset as i32)).unwrap();
132 self.registers.set_pc(jump_addr);
133 }
134
135 fn do_push8(
136 &mut self,
137 mem: &mut MemController<impl GBAllocator, impl RomReader>,
138 val: u8,
139 ) -> Result<(), WriteError> {
140 self.registers.set_sp(self.registers.sp() - 1);
141 mem.write8(self.registers.sp(), val)
142 }
143
144 fn do_pop8(
145 &mut self,
146 mem: &mut MemController<impl GBAllocator, impl RomReader>,
147 ) -> Result<u8, ReadError> {
148 let val = mem.read8(self.registers.sp());
149
150 self.registers.set_sp(self.registers.sp() + 1);
151
152 val
153 }
154
155 fn do_push16(
156 &mut self,
157 mem: &mut MemController<impl GBAllocator, impl RomReader>,
158 val: u16,
159 ) -> Result<(), WriteError> {
160 self.registers.set_sp(self.registers.sp() - 2);
161 mem.write16(self.registers.sp(), val)
162 }
163
164 fn do_pop16(
165 &mut self,
166 mem: &mut MemController<impl GBAllocator, impl RomReader>,
167 ) -> Result<u16, ReadError> {
168 let val = mem.read16(self.registers.sp());
169
170 self.registers.set_sp(self.registers.sp() + 2);
171
172 val
173 }
174
175 fn do_call(
176 &mut self,
177 mem: &mut MemController<impl GBAllocator, impl RomReader>,
178 return_addr: u16,
179 call_addr: u16,
180 ) -> Result<(), WriteError> {
181 self.do_push16(mem, return_addr)?;
182 self.registers.set_pc(call_addr);
183 Ok(())
184 }
185
186 fn get_arith_src(
187 &self,
188 mem: &MemController<impl GBAllocator, impl RomReader>,
189 src: ArithSrc,
190 ) -> Result<u8, ReadError> {
191 match src {
192 ArithSrc::Reg(reg) => Ok(self.get_reg8_value(reg)),
193 ArithSrc::Imm(imm) => Ok(imm),
194 ArithSrc::Mem(memloc) => mem.read8(self.memloc_to_addr(memloc)),
195 }
196 }
197
198 fn get_prefarith_tgt(
199 &self,
200 mem: &MemController<impl GBAllocator, impl RomReader>,
201 tgt: PrefArithTarget,
202 ) -> Result<u8, ReadError> {
203 match tgt {
204 PrefArithTarget::Reg(reg) => Ok(self.get_reg8_value(reg)),
205 PrefArithTarget::MemHL => mem.read8(self.registers.hl()),
206 }
207 }
208
209 fn set_prefarith_tgt(
210 &mut self,
211 mem: &mut MemController<impl GBAllocator, impl RomReader>,
212 tgt: PrefArithTarget,
213 val: u8,
214 ) -> Result<(), WriteError> {
215 match tgt {
216 PrefArithTarget::Reg(reg) => {
217 self.set_reg8_value(reg, val);
218 Ok(())
219 }
220 PrefArithTarget::MemHL => mem.write8(self.registers.hl(), val),
221 }
222 }
223
224 fn handle_timers(&mut self, mem: &mut MemController<impl GBAllocator, impl RomReader>) {
225 if self.timer_cycles.0 % 256 == 0 {
226 mem.io_registers.timer_div += 1;
227 }
228
229 if let Some(tac_frequency) = timer::get_tac_modulo(mem.io_registers.timer_control) {
230 if self.timer_cycles.0 % tac_frequency == 0 {
231 let (incremented, overflown) = mem.io_registers.timer_counter.overflowing_add(1);
232
233 if overflown {
234 mem.io_registers.timer_counter = mem.io_registers.timer_modulo;
235 mem.io_registers.interrupts_requested.set_timer(true);
236 } else {
237 mem.io_registers.timer_counter = incremented;
238 }
239 }
240 }
241
242 self.timer_cycles += 1;
243 }
244
245 pub fn run_cycle(
246 &mut self,
247 mem: &mut MemController<impl GBAllocator, impl RomReader>,
248 ) -> Result<(), CpuErr> {
249 self.handle_timers(mem);
250
251 if self.cycles_remaining != 0 {
252 self.cycles_remaining -= 1;
254 return Ok(());
255 }
256
257 let instr = decoder::decode(mem, self.registers.pc())?;
258
259 log::trace!("Running 0x{:x}: {}", self.registers.pc(), instr);
260
261 let should_enable_interrupts = self.ei_queued;
262
263 let jumped = match instr {
264 Instruction::Nop => false,
265 Instruction::Stop(_) => instr_todo!(instr),
266 Instruction::Halt => instr_todo!(instr),
267 Instruction::EI => {
268 self.ei_queued = true;
269 false
270 }
271 Instruction::DI => {
272 self.interrupts_master = false;
273 false
274 }
275 Instruction::Add(src) => {
276 let base = self.registers.a();
277 let val = self.get_arith_src(mem, src)?;
278
279 let (res, carry) = base.overflowing_add(val);
280
281 self.registers
282 .set_flags(res == 0, false, base.halfcarry_add(val), carry);
283
284 self.registers.set_a(res);
285
286 false
287 }
288 Instruction::AddCarry(src) => {
289 let base = self.registers.a();
290 let val = self.get_arith_src(mem, src)?;
291 let cur_carry = if self.registers.carry_flag() { 1 } else { 0 };
292
293 let (res, new_carry) = base.overflowing_add(val + cur_carry);
294
295 self.registers.set_flags(
296 res == 0,
297 false,
298 base.halfcarry_add(val + cur_carry),
299 new_carry,
300 );
301
302 self.registers.set_a(res);
303
304 false
305 }
306 Instruction::AddHL(reg) => {
307 let base = self.registers.hl();
308 let val = self.get_reg16_value(reg);
309
310 let (res, carry) = base.overflowing_add(val);
311
312 self.registers
313 .set_flags(res == 0, false, base.halfcarry_add(val), carry);
314
315 self.registers.set_hl(res);
316
317 false
318 }
319 Instruction::AddSP(_) => instr_todo!(instr),
320 Instruction::Sub(src) => {
321 let base = self.registers.a();
322 let val = self.get_arith_src(mem, src)?;
323
324 let (res, carry) = base.overflowing_sub(val);
325
326 self.registers
327 .set_flags(res == 0, true, base.halfcarry_sub(val), carry);
328
329 self.registers.set_a(res);
330
331 false
332 }
333 Instruction::SubCarry(_) => instr_todo!(instr),
334 Instruction::And(src) => {
335 let val = self.get_arith_src(mem, src)?;
336
337 let and = val & self.registers.a();
338
339 self.registers.set_flags(and == 0, false, true, false);
340 self.registers.set_a(and);
341
342 false
343 }
344 Instruction::Or(src) => {
345 let val = self.get_arith_src(mem, src)?;
346
347 let or = val | self.registers.a();
348
349 self.registers.set_flags(or == 0, false, false, false);
350 self.registers.set_a(or);
351
352 false
353 }
354 Instruction::Xor(src) => {
355 let val = self.get_arith_src(mem, src)?;
356
357 let xord = self.registers.a() ^ val;
358
359 self.registers.set_a(xord);
360
361 self.registers.set_flags(xord == 0, false, false, false);
362
363 false
364 }
365 Instruction::Cmp(src) => {
366 let base = self.registers.a();
367 let val = self.get_arith_src(mem, src)?;
368
369 let (res, carry) = base.overflowing_sub(val);
370
371 self.registers
372 .set_flags(res == 0, true, base.halfcarry_sub(val), carry);
373
374 false
375 }
376 Instruction::Inc(tgt) => {
377 match tgt {
378 IncDecTarget::Reg8(reg) => {
379 let val = self.get_reg8_value(reg);
380 let incremented = val.wrapping_add(1);
381
382 self.registers.set_zero_flag(incremented == 0);
383 self.registers.set_subtract_flag(false);
384 self.registers.set_half_carry_flag(val.halfcarry_add(1));
385
386 self.set_reg8_value(reg, incremented);
387 }
388 IncDecTarget::Reg16(reg) => {
389 let val = self.get_reg16_value(reg);
390 let incremented = val.wrapping_add(1);
391
392 self.set_reg16_value(reg, incremented);
393 }
394 IncDecTarget::MemHL => {
395 let addr = self.registers.hl();
396 let val = mem.read8(addr)?;
397 let incremented = val.wrapping_add(1);
398
399 self.registers.set_zero_flag(incremented == 0);
400 self.registers.set_subtract_flag(false);
401 self.registers.set_half_carry_flag(val.halfcarry_add(1));
402
403 mem.write8(addr, incremented)?;
404 }
405 };
406 false
407 }
408 Instruction::Dec(tgt) => {
409 match tgt {
410 IncDecTarget::Reg8(reg) => {
411 let val = self.get_reg8_value(reg);
412 let decremented = val.wrapping_sub(1);
413
414 self.registers.set_zero_flag(decremented == 0);
415 self.registers.set_subtract_flag(true);
416 self.registers.set_half_carry_flag(val.halfcarry_sub(1));
417
418 self.set_reg8_value(reg, decremented);
419 }
420 IncDecTarget::Reg16(reg) => {
421 let val = self.get_reg16_value(reg);
422 let decremented = val.wrapping_sub(1);
423
424 self.set_reg16_value(reg, decremented);
425 }
426 IncDecTarget::MemHL => {
427 let addr = self.registers.hl();
428 let val = mem.read8(addr)?;
429 let decremented = val.wrapping_sub(1);
430
431 self.registers.set_zero_flag(decremented == 0);
432 self.registers.set_subtract_flag(true);
433 self.registers.set_half_carry_flag(val.halfcarry_sub(1));
434
435 mem.write8(addr, decremented)?;
436 }
437 };
438 false
439 }
440 Instruction::RotLeftCircular(_) => instr_todo!(instr),
441 Instruction::RotRightCircular(tgt) => {
442 let pre = self.get_prefarith_tgt(mem, tgt)?;
443
444 self.registers.set_carry_flag(pre.lsb_set());
445
446 self.set_prefarith_tgt(mem, tgt, pre.rotate_right(1))?;
447
448 false
449 }
450 Instruction::RotLeft(tgt) => {
451 let init_val = self.get_prefarith_tgt(mem, tgt)?;
452 let shifted = init_val.wrapping_shl(1);
453 let result = shifted.set_lsb(self.registers.carry_flag());
454
455 self.registers
456 .set_flags(result == 0, false, false, init_val.msb_set());
457
458 self.set_prefarith_tgt(mem, tgt, result)?;
459
460 false
461 }
462 Instruction::RotRight(_) => instr_todo!(instr),
463 Instruction::ShiftLeftArith(tgt) => {
464 let init_val = self.get_prefarith_tgt(mem, tgt)?;
465 let shifted = init_val.wrapping_shl(1);
466
467 self.registers
468 .set_flags(shifted == 0, false, false, init_val.msb_set());
469
470 self.set_prefarith_tgt(mem, tgt, shifted)?;
471
472 false
473 }
474 Instruction::ShiftRightArith(_) => instr_todo!(instr),
475 Instruction::Swap(tgt) => {
476 let val = self.get_prefarith_tgt(mem, tgt)?;
477 let val_lower = val & 0xF;
478 let val_upper = val & 0xF0;
479
480 let swapped = (val_lower << 4) | (val_upper >> 4);
481
482 self.set_prefarith_tgt(mem, tgt, swapped)?;
483
484 self.registers.set_flags(swapped == 0, false, false, false);
485
486 false
487 }
488 Instruction::ShiftRightLogic(tgt) => {
489 let val = self.get_prefarith_tgt(mem, tgt)?;
490
491 let carry = val.lsb_set();
492
493 let res = val.wrapping_shr(1);
494
495 self.registers.set_flags(res == 0, false, false, carry);
496
497 self.set_prefarith_tgt(mem, tgt, res)?;
498
499 false
500 }
501 Instruction::Bit(bit, tgt) => {
502 let val = self.get_prefarith_tgt(mem, tgt)?;
503
504 let is_zero = val & (1 << (bit as usize)) == 0;
505
506 self.registers.set_zero_flag(is_zero);
507 self.registers.set_subtract_flag(false);
508 self.registers.set_half_carry_flag(true);
509
510 false
511 }
512 Instruction::Res(bit, tgt) => {
513 let val = self.get_prefarith_tgt(mem, tgt)?;
514
515 let bit: u8 = 0b1 << bit as usize;
516
517 self.set_prefarith_tgt(mem, tgt, val & (!bit))?;
518
519 false
520 }
521 Instruction::Set(bit, tgt) => {
522 let val = self.get_prefarith_tgt(mem, tgt)?;
523
524 let bit: u8 = 0b1 << bit as usize;
525
526 self.set_prefarith_tgt(mem, tgt, val | bit)?;
527
528 false
529 }
530 Instruction::Load8(dst, src) => {
531 let val = match src {
532 Ld8Src::Reg(reg) => self.get_reg8_value(reg),
533 Ld8Src::Mem(memloc) => mem.read8(self.memloc_to_addr(memloc))?,
534 Ld8Src::Imm(imm) => imm,
535 };
536
537 match dst {
538 Ld8Dst::Mem(memloc) => mem.write8(self.memloc_to_addr(memloc), val)?,
539 Ld8Dst::Reg(reg) => self.set_reg8_value(reg, val),
540 };
541
542 false
543 }
544 Instruction::Load16(dst, src) => {
545 let val = match src {
546 Ld16Src::Reg(reg) => self.get_reg16_value(reg),
547 Ld16Src::Imm(imm) => imm,
548 };
549
550 match dst {
551 Ld16Dst::Mem(memloc) => mem.write16(self.memloc_to_addr(memloc), val)?,
552 Ld16Dst::Reg(reg) => self.set_reg16_value(reg, val),
553 };
554
555 false
556 }
557 Instruction::LoadAtoHLI => {
558 let val = self.registers.a();
559 let addr = self.registers.hl();
560
561 mem.write8(addr, val)?;
562
563 self.registers.set_hl(addr + 1);
564
565 false
566 }
567 Instruction::LoadAtoHLD => {
568 let val = self.registers.a();
569 let addr = self.registers.hl();
570
571 mem.write8(addr, val)?;
572
573 self.registers.set_hl(addr - 1);
574
575 false
576 }
577 Instruction::LoadHLItoA => {
578 let addr = self.registers.hl();
579 let val = mem.read8(addr)?;
580
581 self.registers.set_hl(addr + 1); self.registers.set_a(val);
583
584 false
585 }
586 Instruction::LoadHLDtoA => {
587 let addr = self.registers.hl();
588 let val = mem.read8(addr)?;
589
590 self.registers.set_hl(addr - 1); self.registers.set_a(val);
592
593 false
594 }
595 Instruction::LoadSPi8toHL(_) => instr_todo!(instr),
596 Instruction::Jump(addr) => {
597 self.registers.set_pc(addr);
598 true
599 }
600 Instruction::JumpRel(offset) => {
601 self.do_rel_jump(self.registers.pc() + (instr.len() as u16), offset);
602 true
603 }
604 Instruction::JumpHL => {
605 self.registers.set_pc(self.registers.hl());
606 true
607 }
608 Instruction::JumpIf(addr, cond) => {
609 if self.check_condition(cond) {
610 self.registers.set_pc(addr);
611 true
612 } else {
613 false
614 }
615 }
616 Instruction::JumpRelIf(offset, condition) => {
617 if self.check_condition(condition) {
618 self.do_rel_jump(self.registers.pc() + (instr.len() as u16), offset);
619 true
620 } else {
621 false
622 }
623 }
624 Instruction::Call(addr) => {
625 let curr_addr = self.registers.pc();
626 let return_addr = curr_addr + (instr.len() as u16);
627
628 self.do_call(mem, return_addr, addr)?;
629
630 true
631 }
632 Instruction::CallIf(addr, cond) => {
633 if self.check_condition(cond) {
634 let curr_addr = self.registers.pc();
635 let return_addr = curr_addr + (instr.len() as u16);
636
637 self.do_call(mem, return_addr, addr)?;
638
639 true
640 } else {
641 false
642 }
643 }
644 Instruction::Ret => {
645 let ret_addr = self.do_pop16(mem)?;
646 self.registers.set_pc(ret_addr);
647
648 true
649 }
650 Instruction::Reti => {
651 let ret_addr = self.do_pop16(mem)?;
654 self.registers.set_pc(ret_addr);
655 self.interrupts_master = true; true
658 }
659 Instruction::RetIf(cond) => {
660 if self.check_condition(cond) {
661 let ret_addr = self.do_pop16(mem)?;
662 self.registers.set_pc(ret_addr);
663
664 true
665 } else {
666 false
667 }
668 }
669 Instruction::Pop(reg) => {
670 let val = self.do_pop16(mem)?;
671 self.set_reg16_value(reg, val);
672
673 false
674 }
675 Instruction::Push(reg) => {
676 self.do_push16(mem, self.get_reg16_value(reg))?;
677
678 false
679 }
680 Instruction::DecimalAdjust => {
681 let mut a = self.registers.a();
682 let cflag = self.registers.carry_flag();
683 let hflag = self.registers.half_carry_flag();
684
685 match self.registers.subtract_flag() {
686 false => {
687 if cflag || a > 0x99 {
688 a = a.wrapping_add(0x60);
689 self.registers.set_carry_flag(true);
690 }
691 if hflag || (a & 0x0F) > 0x09 {
692 a = a.wrapping_add(0x6);
693 }
694 }
695 true => {
696 if cflag {
697 a = a.wrapping_sub(0x60);
698 }
699 if hflag {
700 a = a.wrapping_sub(0x6);
701 }
702 }
703 }
704
705 self.registers.set_zero_flag(a == 0);
706 self.registers.set_half_carry_flag(false);
707 self.registers.set_a(a);
708
709 false
710 }
711 Instruction::ComplementAccumulator => {
712 self.registers.set_a(!self.registers.a());
713 self.registers.set_subtract_flag(true);
714 self.registers.set_half_carry_flag(true);
715 false
716 }
717 Instruction::SetCarryFlag => instr_todo!(instr),
718 Instruction::ComplementCarry => instr_todo!(instr),
719 Instruction::Rst(rsvec) => {
720 let curr_addr = self.registers.pc();
721 let return_addr = curr_addr + (instr.len() as u16);
722
723 self.do_call(mem, return_addr, rsvec as u16)?;
724
725 true
726 }
727 Instruction::RotLeftCircularA => {
728 let pre = self.registers.a();
729
730 self.registers.set_carry_flag(pre.msb_set());
731
732 self.registers.set_a(pre.rotate_left(1));
733
734 false
735 }
736 Instruction::RotRightCircularA => {
737 let pre = self.registers.a();
738
739 self.registers.set_carry_flag(pre.lsb_set());
740
741 self.registers.set_a(pre.rotate_right(1));
742
743 false
744 }
745 Instruction::RotLeftA => {
746 let cur_val = self.registers.a();
747 let shifted = cur_val.wrapping_shl(1);
748 let result = shifted.set_lsb(self.registers.carry_flag());
749
750 self.registers
751 .set_flags(false, false, false, cur_val.msb_set());
752
753 self.registers.set_a(result);
754
755 false
756 }
757 Instruction::RotRightA => instr_todo!(instr),
758 Instruction::IllegalInstruction(illegal) => {
759 return Err(CpuErr::Illegal(illegal));
760 }
761 };
762
763 if should_enable_interrupts {
764 self.ei_queued = false;
765 self.interrupts_master = true;
766 }
767
768 if !jumped {
770 let instr_len = instr.len() as u16;
771
772 self.registers.set_pc(self.registers.pc() + instr_len);
773 }
774
775 if self.interrupts_master {
777 let enabled = mem.interrupts_enabled;
778 let requested = mem.io_registers.interrupts_requested;
779 let to_service: Interrupts = (u8::from(enabled) & u8::from(requested)).into();
780
781 if u8::from(to_service) & 0b00011111 != 0 {
786 log::debug!("Handling interrupt! 0b{:b}", u8::from(to_service));
787 self.interrupts_master = false;
788
789 let handler_addr: u16 = if to_service.vblank() {
790 mem.io_registers.interrupts_requested.set_vblank(false);
791 0x40
792 } else if to_service.lcd() {
793 mem.io_registers.interrupts_requested.set_lcd(false);
794 0x48
795 } else if to_service.timer() {
796 mem.io_registers.interrupts_requested.set_timer(false);
797 0x50
798 } else if to_service.serial() {
799 mem.io_registers.interrupts_requested.set_serial(false);
800 0x58
801 } else if to_service.joypad() {
802 mem.io_registers.interrupts_requested.set_joypad(false);
803 0x60
804 } else {
805 unreachable!("Not actually an interrupt");
806 };
807
808 self.do_call(mem, self.registers.pc(), handler_addr)?;
810 self.cycles_remaining = 20; return Ok(());
812 }
813 }
814
815 match instr.cycles() {
817 TCycles::Static(cycles) => self.cycles_remaining = cycles - 1,
818 TCycles::Branching { taken, non_taken } => {
819 let actual_cycles = if jumped { taken } else { non_taken };
820
821 self.cycles_remaining = actual_cycles - 1;
822 }
823 }
824
825 Ok(())
826 }
827}