1use boytacean_common::{
9 data::{read_u16, read_u8, write_u16, write_u8},
10 error::Error,
11 util::SharedThread,
12};
13use std::{
14 fmt::{self, Display, Formatter},
15 io::Cursor,
16 sync::Mutex,
17};
18
19use crate::{
20 apu::Apu,
21 assert_pedantic_gb,
22 consts::LCDC_ADDR,
23 debugln,
24 dma::Dma,
25 gb::GameBoyConfig,
26 inst::{EXTENDED, INSTRUCTIONS},
27 mmu::Mmu,
28 pad::Pad,
29 ppu::Ppu,
30 serial::Serial,
31 state::{StateComponent, StateFormat},
32 timer::Timer,
33};
34
35pub const PREFIX: u8 = 0xcb;
36
37pub type Instruction = &'static (fn(&mut Cpu), u8, &'static str);
38
39pub struct Cpu {
40 pub pc: u16,
41 pub sp: u16,
42 pub a: u8,
43 pub b: u8,
44 pub c: u8,
45 pub d: u8,
46 pub e: u8,
47 pub h: u8,
48 pub l: u8,
49
50 ime: bool,
51 zero: bool,
52 sub: bool,
53 half_carry: bool,
54 carry: bool,
55 halted: bool,
56
57 pub mmu: Mmu,
60
61 pub cycles: u8,
64
65 pub ppc: u16,
69
70 gbc: SharedThread<GameBoyConfig>,
74}
75
76impl Cpu {
77 pub fn new(mmu: Mmu, gbc: SharedThread<GameBoyConfig>) -> Self {
78 Self {
79 pc: 0x0,
80 sp: 0x0,
81 a: 0x0,
82 b: 0x0,
83 c: 0x0,
84 d: 0x0,
85 e: 0x0,
86 h: 0x0,
87 l: 0x0,
88 ime: false,
89 zero: false,
90 sub: false,
91 half_carry: false,
92 carry: false,
93 halted: false,
94 mmu,
95 cycles: 0,
96 ppc: 0x0,
97 gbc,
98 }
99 }
100
101 pub fn reset(&mut self) {
102 self.pc = 0x0;
103 self.sp = 0x0;
104 self.a = 0x0;
105 self.b = 0x0;
106 self.c = 0x0;
107 self.d = 0x0;
108 self.e = 0x0;
109 self.h = 0x0;
110 self.l = 0x0;
111 self.ime = false;
112 self.zero = false;
113 self.sub = false;
114 self.half_carry = false;
115 self.carry = false;
116 self.halted = false;
117 self.cycles = 0;
118 }
119
120 pub fn boot(&mut self) {
126 self.pc = 0x0100;
127 self.sp = 0xfffe;
128 self.a = 0x01;
129 self.b = 0xff;
130 self.c = 0x13;
131 self.d = 0x00;
132 self.e = 0xc1;
133 self.h = 0x84;
134 self.l = 0x03;
135 self.zero = false;
136 self.sub = false;
137 self.half_carry = false;
138 self.carry = false;
139
140 self.mmu.set_boot_active(false);
144 self.mmu.write(LCDC_ADDR, 0x91);
145 }
146
147 pub fn clock(&mut self) -> u8 {
148 let pc = self.pc;
151
152 assert_pedantic_gb!(
155 !(0x8000..=0x9fff).contains(&pc),
156 "Invalid PC area at 0x{:04x}",
157 pc
158 );
159 assert_pedantic_gb!(
160 !self.mmu.boot_active() || pc <= 0x08ff,
161 "Invalid boot address: {:04x}",
162 pc
163 );
164
165 if self.halted
173 && !self.ime
174 && self.mmu.ie != 0x00
175 && (((self.mmu.ie & 0x01 == 0x01) && self.mmu.ppu().int_vblank())
176 || ((self.mmu.ie & 0x02 == 0x02) && self.mmu.ppu().int_stat())
177 || ((self.mmu.ie & 0x04 == 0x04) && self.mmu.timer().int_tima())
178 || ((self.mmu.ie & 0x08 == 0x08) && self.mmu.serial().int_serial())
179 || ((self.mmu.ie & 0x10 == 0x10) && self.mmu.pad().int_pad()))
180 {
181 self.halted = false;
182 }
183
184 if self.ime && self.mmu.ie != 0x00 {
190 if (self.mmu.ie & 0x01 == 0x01) && self.mmu.ppu().int_vblank() {
191 debugln!("Going to run V-Blank interrupt handler (0x40)");
192
193 self.disable_int();
194 self.push_word(pc);
195 self.pc = 0x40;
196
197 self.mmu.vblank();
200
201 self.mmu.ppu().ack_vblank();
204
205 if self.halted {
208 self.halted = false;
209 }
210
211 return 20;
212 } else if (self.mmu.ie & 0x02 == 0x02) && self.mmu.ppu().int_stat() {
213 debugln!("Going to run LCD STAT interrupt handler (0x48)");
214
215 self.disable_int();
216 self.push_word(pc);
217 self.pc = 0x48;
218
219 self.mmu.ppu().ack_stat();
222
223 if self.halted {
226 self.halted = false;
227 }
228
229 return 20;
230 } else if (self.mmu.ie & 0x04 == 0x04) && self.mmu.timer().int_tima() {
231 debugln!("Going to run Timer interrupt handler (0x50)");
232
233 self.disable_int();
234 self.push_word(pc);
235 self.pc = 0x50;
236
237 self.mmu.timer().ack_tima();
240
241 if self.halted {
244 self.halted = false;
245 }
246
247 return 20;
248 } else if (self.mmu.ie & 0x08 == 0x08) && self.mmu.serial().int_serial() {
249 debugln!("Going to run Serial interrupt handler (0x58)");
250
251 self.disable_int();
252 self.push_word(pc);
253 self.pc = 0x58;
254
255 self.mmu.serial().ack_serial();
258
259 if self.halted {
262 self.halted = false;
263 }
264
265 return 20;
266 } else if (self.mmu.ie & 0x10 == 0x10) && self.mmu.pad().int_pad() {
267 debugln!("Going to run JoyPad interrupt handler (0x60)");
268
269 self.disable_int();
270 self.push_word(pc);
271 self.pc = 0x60;
272
273 self.mmu.pad().ack_pad();
276
277 if self.halted {
280 self.halted = false;
281 }
282
283 return 20;
284 }
285 }
286
287 if self.halted {
291 return 4;
292 }
293
294 let (inst, pc) = self.fetch(self.pc);
299 self.ppc = self.pc;
300 self.pc = pc;
301
302 #[allow(unused_variables)]
303 let (inst_fn, inst_time, inst_str) = inst;
304
305 #[cfg(feature = "cpulog")]
306 if *inst_str == "! UNIMP !" || *inst_str == "HALT" {
307 if *inst_str == "HALT" {
308 debugln!("HALT with IE=0x{:02x} IME={}", self.mmu.ie, self.ime);
309 }
310 debugln!(
311 "{}\t(0x{:02x})\t${:04x} {}",
312 inst_str,
313 opcode,
314 pc,
315 is_prefix
316 );
317 }
318
319 #[cfg(feature = "cpulog")]
320 {
321 println!("{}", self.description(inst, self.ppc));
322 }
323
324 self.cycles = 0;
328 inst_fn(self);
329 self.cycles = self.cycles.wrapping_add(*inst_time);
330
331 self.cycles
334 }
335
336 #[inline(always)]
337 fn fetch(&self, pc: u16) -> (Instruction, u16) {
338 let mut pc = pc;
339
340 let mut opcode = self.mmu.read(pc);
343 pc = pc.wrapping_add(1);
344
345 let inst: Instruction;
349 let is_prefix = opcode == PREFIX;
350 if is_prefix {
351 opcode = self.mmu.read(pc);
352 pc = pc.wrapping_add(1);
353 inst = &EXTENDED[opcode as usize];
354 } else {
355 inst = &INSTRUCTIONS[opcode as usize];
356 }
357
358 (inst, pc)
361 }
362
363 #[inline(always)]
364 pub fn mmu(&mut self) -> &mut Mmu {
365 &mut self.mmu
366 }
367
368 #[inline(always)]
369 pub fn mmu_i(&self) -> &Mmu {
370 &self.mmu
371 }
372
373 #[inline(always)]
374 pub fn ppu(&mut self) -> &mut Ppu {
375 self.mmu().ppu()
376 }
377
378 #[inline(always)]
379 pub fn ppu_i(&self) -> &Ppu {
380 self.mmu_i().ppu_i()
381 }
382
383 #[inline(always)]
384 pub fn apu(&mut self) -> &mut Apu {
385 self.mmu().apu()
386 }
387
388 #[inline(always)]
389 pub fn apu_i(&self) -> &Apu {
390 self.mmu_i().apu_i()
391 }
392
393 #[inline(always)]
394 pub fn dma(&mut self) -> &mut Dma {
395 self.mmu().dma()
396 }
397
398 #[inline(always)]
399 pub fn dma_i(&self) -> &Dma {
400 self.mmu_i().dma_i()
401 }
402
403 #[inline(always)]
404 pub fn pad(&mut self) -> &mut Pad {
405 self.mmu().pad()
406 }
407
408 #[inline(always)]
409 pub fn pad_i(&self) -> &Pad {
410 self.mmu_i().pad_i()
411 }
412
413 #[inline(always)]
414 pub fn timer(&mut self) -> &mut Timer {
415 self.mmu().timer()
416 }
417
418 #[inline(always)]
419 pub fn timer_i(&self) -> &Timer {
420 self.mmu_i().timer_i()
421 }
422
423 #[inline(always)]
424 pub fn serial(&mut self) -> &mut Serial {
425 self.mmu().serial()
426 }
427
428 #[inline(always)]
429 pub fn serial_i(&self) -> &Serial {
430 self.mmu_i().serial_i()
431 }
432
433 #[inline(always)]
434 pub fn halted(&self) -> bool {
435 self.halted
436 }
437
438 #[inline(always)]
439 pub fn set_halted(&mut self, value: bool) {
440 self.halted = value
441 }
442
443 #[inline(always)]
444 pub fn cycles(&self) -> u8 {
445 self.cycles
446 }
447
448 #[inline(always)]
449 pub fn pc(&self) -> u16 {
450 self.pc
451 }
452
453 #[inline(always)]
454 pub fn set_pc(&mut self, value: u16) {
455 self.pc = value;
456 }
457
458 #[inline(always)]
459 pub fn sp(&self) -> u16 {
460 self.sp
461 }
462
463 #[inline(always)]
464 pub fn set_sp(&mut self, value: u16) {
465 self.sp = value;
466 }
467
468 #[inline(always)]
469 pub fn af(&self) -> u16 {
470 ((self.a as u16) << 8) | self.f() as u16
471 }
472
473 #[inline(always)]
474 pub fn bc(&self) -> u16 {
475 ((self.b as u16) << 8) | self.c as u16
476 }
477
478 #[inline(always)]
479 pub fn f(&self) -> u8 {
480 let mut f = 0x0u8;
481 if self.zero {
482 f |= 0x80;
483 }
484 if self.sub {
485 f |= 0x40;
486 }
487 if self.half_carry {
488 f |= 0x20;
489 }
490 if self.carry {
491 f |= 0x10;
492 }
493 f
494 }
495
496 #[inline(always)]
497 pub fn set_f(&mut self, value: u8) {
498 self.zero = value & 0x80 == 0x80;
499 self.sub = value & 0x40 == 0x40;
500 self.half_carry = value & 0x20 == 0x20;
501 self.carry = value & 0x10 == 0x10;
502 }
503
504 #[inline(always)]
505 pub fn set_af(&mut self, value: u16) {
506 self.a = (value >> 8) as u8;
507 self.set_f(value as u8);
508 }
509
510 #[inline(always)]
511 pub fn set_bc(&mut self, value: u16) {
512 self.b = (value >> 8) as u8;
513 self.c = value as u8;
514 }
515
516 #[inline(always)]
517 pub fn de(&self) -> u16 {
518 ((self.d as u16) << 8) | self.e as u16
519 }
520
521 #[inline(always)]
522 pub fn set_de(&mut self, value: u16) {
523 self.d = (value >> 8) as u8;
524 self.e = value as u8;
525 }
526
527 #[inline(always)]
528 pub fn hl(&self) -> u16 {
529 ((self.h as u16) << 8) | self.l as u16
530 }
531
532 #[inline(always)]
533 pub fn set_hl(&mut self, value: u16) {
534 self.h = (value >> 8) as u8;
535 self.l = value as u8;
536 }
537
538 #[inline(always)]
539 pub fn ime(&self) -> bool {
540 self.ime
541 }
542
543 #[inline(always)]
544 pub fn set_ime(&mut self, value: bool) {
545 self.ime = value;
546 }
547
548 #[inline(always)]
549 pub fn read_u8(&mut self) -> u8 {
550 let byte = self.mmu.read(self.pc);
551 self.pc = self.pc.wrapping_add(1);
552 byte
553 }
554
555 #[inline(always)]
556 pub fn read_u16(&mut self) -> u16 {
557 let byte1 = self.read_u8();
558 let byte2 = self.read_u8();
559
560 byte1 as u16 | ((byte2 as u16) << 8)
561 }
562
563 #[inline(always)]
564 pub fn push_byte(&mut self, byte: u8) {
565 self.sp = self.sp.wrapping_sub(1);
566 self.mmu.write(self.sp, byte);
567 }
568
569 #[inline(always)]
570 pub fn push_word(&mut self, word: u16) {
571 self.push_byte((word >> 8) as u8);
572 self.push_byte(word as u8);
573 }
574
575 #[inline(always)]
576 pub fn pop_byte(&mut self) -> u8 {
577 let byte = self.mmu.read(self.sp);
578 self.sp = self.sp.wrapping_add(1);
579 byte
580 }
581
582 #[inline(always)]
583 pub fn pop_word(&mut self) -> u16 {
584 self.pop_byte() as u16 | ((self.pop_byte() as u16) << 8)
585 }
586
587 #[inline(always)]
588 pub fn zero(&self) -> bool {
589 self.zero
590 }
591
592 #[inline(always)]
593 pub fn set_zero(&mut self, value: bool) {
594 self.zero = value
595 }
596
597 #[inline(always)]
598 pub fn sub(&self) -> bool {
599 self.sub
600 }
601
602 #[inline(always)]
603 pub fn set_sub(&mut self, value: bool) {
604 self.sub = value;
605 }
606
607 #[inline(always)]
608 pub fn half_carry(&self) -> bool {
609 self.half_carry
610 }
611
612 #[inline(always)]
613 pub fn set_half_carry(&mut self, value: bool) {
614 self.half_carry = value
615 }
616
617 #[inline(always)]
618 pub fn carry(&self) -> bool {
619 self.carry
620 }
621
622 #[inline(always)]
623 pub fn set_carry(&mut self, value: bool) {
624 self.carry = value;
625 }
626
627 #[inline(always)]
628 pub fn halt(&mut self) {
629 self.halted = true;
630 }
631
632 #[inline(always)]
633 pub fn stop(&mut self) {
634 let mmu = self.mmu();
635 if mmu.switching {
636 mmu.switch_speed()
637 }
638 }
639
640 #[inline(always)]
641 pub fn enable_int(&mut self) {
642 self.ime = true;
643 }
644
645 #[inline(always)]
646 pub fn disable_int(&mut self) {
647 self.ime = false;
648 }
649
650 pub fn set_gbc(&mut self, value: SharedThread<GameBoyConfig>) {
651 self.gbc = value;
652 }
653
654 pub fn description(&self, inst: Instruction, inst_pc: u16) -> String {
655 let (_, inst_time, inst_str) = inst;
656 let title_str: String = format!("[0x{inst_pc:04x}] {inst_str}");
657 let inst_time_str = format!("({inst_time} cycles)");
658 let registers_str = format!("[PC=0x{:04x} SP=0x{:04x}] [A=0x{:02x} B=0x{:02x} C=0x{:02x} D=0x{:02x} E=0x{:02x} H=0x{:02x} L=0x{:02x}]",
659 self.pc, self.sp, self.a, self.b, self.c, self.d, self.e, self.h, self.l);
660 format!("{title_str: <24} {inst_time_str: <11} {registers_str: <10}")
661 }
662
663 pub fn description_default(&self) -> String {
664 let (inst, _) = self.fetch(self.ppc);
665 self.description(inst, self.ppc)
666 }
667}
668
669impl StateComponent for Cpu {
670 fn state(&self, _format: Option<StateFormat>) -> Result<Vec<u8>, Error> {
671 let mut cursor = Cursor::new(vec![]);
672 write_u16(&mut cursor, self.pc)?;
673 write_u16(&mut cursor, self.sp)?;
674 write_u8(&mut cursor, self.a)?;
675 write_u8(&mut cursor, self.b)?;
676 write_u8(&mut cursor, self.c)?;
677 write_u8(&mut cursor, self.d)?;
678 write_u8(&mut cursor, self.e)?;
679 write_u8(&mut cursor, self.h)?;
680 write_u8(&mut cursor, self.l)?;
681 write_u8(&mut cursor, self.ime as u8)?;
682 write_u8(&mut cursor, self.zero as u8)?;
683 write_u8(&mut cursor, self.sub as u8)?;
684 write_u8(&mut cursor, self.half_carry as u8)?;
685 write_u8(&mut cursor, self.carry as u8)?;
686 write_u8(&mut cursor, self.halted as u8)?;
687 write_u8(&mut cursor, self.cycles)?;
688 write_u16(&mut cursor, self.ppc)?;
689 Ok(cursor.into_inner())
690 }
691
692 fn set_state(&mut self, data: &[u8], _format: Option<StateFormat>) -> Result<(), Error> {
693 let mut cursor = Cursor::new(data);
694 self.pc = read_u16(&mut cursor)?;
695 self.sp = read_u16(&mut cursor)?;
696 self.a = read_u8(&mut cursor)?;
697 self.b = read_u8(&mut cursor)?;
698 self.c = read_u8(&mut cursor)?;
699 self.d = read_u8(&mut cursor)?;
700 self.e = read_u8(&mut cursor)?;
701 self.h = read_u8(&mut cursor)?;
702 self.l = read_u8(&mut cursor)?;
703 self.ime = read_u8(&mut cursor)? != 0;
704 self.zero = read_u8(&mut cursor)? != 0;
705 self.sub = read_u8(&mut cursor)? != 0;
706 self.half_carry = read_u8(&mut cursor)? != 0;
707 self.carry = read_u8(&mut cursor)? != 0;
708 self.halted = read_u8(&mut cursor)? != 0;
709 self.cycles = read_u8(&mut cursor)?;
710 self.ppc = read_u16(&mut cursor)?;
711 Ok(())
712 }
713}
714
715impl Default for Cpu {
716 fn default() -> Self {
717 let gbc = SharedThread::new(Mutex::new(GameBoyConfig::default()));
718 Cpu::new(Mmu::default(), gbc)
719 }
720}
721
722impl Display for Cpu {
723 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
724 write!(f, "{}", self.description_default())
725 }
726}
727
728#[cfg(test)]
729mod tests {
730 use std::sync::Mutex;
731
732 use boytacean_common::util::SharedThread;
733
734 use crate::{gb::GameBoyConfig, mmu::Mmu, state::StateComponent};
735
736 use super::Cpu;
737
738 #[test]
739 fn test_cpu_clock() {
740 let mut cpu = Cpu::default();
741 cpu.boot();
742 cpu.mmu.allocate_default();
743
744 cpu.pc = 0xc000;
746 cpu.mmu.write(0xc000, 0x00);
747 let cycles = cpu.clock();
748 assert_eq!(cycles, 4);
749 assert_eq!(cpu.pc, 0xc001);
750
751 cpu.pc = 0xc000;
753 cpu.mmu.write(0xc000, 0x3e);
754 cpu.mmu.write(0xc001, 0x42);
755 let cycles = cpu.clock();
756 assert_eq!(cycles, 8);
757 assert_eq!(cpu.pc, 0xc002);
758 assert_eq!(cpu.a, 0x42);
759
760 cpu.pc = 0xc000;
762 cpu.mmu.write(0xc000, 0x22);
763 cpu.set_hl(0xc000);
764 let cycles = cpu.clock();
765 assert_eq!(cycles, 8);
766 assert_eq!(cpu.pc, 0xc001);
767 assert_eq!(cpu.hl(), 0xc001);
768 assert_eq!(cpu.mmu.read(cpu.hl()), 0x42);
769
770 cpu.pc = 0xc000;
772 cpu.mmu.write(0xc000, 0x3c);
773 cpu.a = 0x42;
774 let cycles = cpu.clock();
775 assert_eq!(cycles, 4);
776 assert_eq!(cpu.pc, 0xc001);
777 assert_eq!(cpu.a, 0x43);
778
779 cpu.pc = 0xc000;
781 cpu.mmu.write(0xc000, 0x3d);
782 cpu.a = 0x42;
783 let cycles = cpu.clock();
784 assert_eq!(cycles, 4);
785 assert_eq!(cpu.pc, 0xc001);
786 assert_eq!(cpu.a, 0x41);
787
788 cpu.pc = 0xc000;
790 cpu.mmu.write(0xc000, 0x7e);
791 cpu.set_hl(0xc001);
792 cpu.mmu.write(0xc001, 0x42);
793 let cycles = cpu.clock();
794 assert_eq!(cycles, 8);
795 assert_eq!(cpu.pc, 0xc001);
796 assert_eq!(cpu.a, 0x42);
797 assert_eq!(cpu.hl(), 0xc001);
798
799 cpu.pc = 0xc000;
801 cpu.mmu.write(0xc000, 0x36);
802 cpu.set_hl(0xc000);
803 cpu.mmu.write(0xc001, 0x42);
804 let cycles = cpu.clock();
805 assert_eq!(cycles, 12);
806 assert_eq!(cpu.pc, 0xc002);
807 assert_eq!(cpu.hl(), 0xc000);
808 assert_eq!(cpu.mmu.read(cpu.hl()), 0x42);
809
810 cpu.pc = 0xc000;
812 cpu.mmu.write(0xc000, 0x18);
813 cpu.mmu.write(0xc001, 0x03);
814 let cycles = cpu.clock();
815 assert_eq!(cycles, 12);
816 assert_eq!(cpu.pc, 0xc005);
817
818 cpu.pc = 0xc000;
820 cpu.mmu.write(0xc000, 0xc6);
821 cpu.mmu.write(0xc001, 0x01);
822 cpu.a = 0x42;
823 let cycles = cpu.clock();
824 assert_eq!(cycles, 8);
825 assert_eq!(cpu.pc, 0xc002);
826 assert_eq!(cpu.a, 0x43);
827
828 cpu.pc = 0xc000;
830 cpu.mmu.write(0xc000, 0xd6);
831 cpu.mmu.write(0xc001, 0x01);
832 cpu.a = 0x42;
833 let cycles = cpu.clock();
834 assert_eq!(cycles, 8);
835 assert_eq!(cpu.pc, 0xc002);
836 assert_eq!(cpu.a, 0x41);
837
838 cpu.pc = 0xc000;
840 cpu.mmu.write(0xc000, 0xe6);
841 cpu.mmu.write(0xc001, 0x0f);
842 cpu.a = 0x0a;
843 let cycles = cpu.clock();
844 assert_eq!(cycles, 8);
845 assert_eq!(cpu.pc, 0xc002);
846 assert_eq!(cpu.a, 0x0a & 0x0f);
847
848 cpu.pc = 0xc000;
850 cpu.mmu.write(0xc000, 0xf6);
851 cpu.mmu.write(0xc001, 0x0f);
852 cpu.a = 0x0a;
853 let cycles = cpu.clock();
854 assert_eq!(cycles, 8);
855 assert_eq!(cpu.pc, 0xc002);
856 assert_eq!(cpu.a, 0x0a | 0x0f);
857
858 cpu.pc = 0xc000;
860 cpu.mmu.write(0xc000, 0xee);
861 cpu.mmu.write(0xc001, 0x0f);
862 cpu.a = 0x0a;
863 let cycles = cpu.clock();
864 assert_eq!(cycles, 8);
865 assert_eq!(cpu.pc, 0xc002);
866 assert_eq!(cpu.a, 0x0a ^ 0x0f);
867 }
868
869 #[test]
870 fn test_state_and_set_state() {
871 let cpu = Cpu {
872 pc: 0x1234,
873 sp: 0x5678,
874 a: 0x9a,
875 b: 0xbc,
876 c: 0xde,
877 d: 0xf0,
878 e: 0x12,
879 h: 0x34,
880 l: 0x56,
881 ime: true,
882 zero: true,
883 sub: false,
884 half_carry: true,
885 carry: false,
886 halted: true,
887 mmu: Mmu::default(),
888 cycles: 0x78,
889 ppc: 0x9abc,
890 gbc: SharedThread::new(Mutex::new(GameBoyConfig::default())),
891 };
892
893 let state = cpu.state(None).unwrap();
894 assert_eq!(state.len(), 20);
895
896 let mut new_cpu = Cpu::default();
897 new_cpu.set_state(&state, None).unwrap();
898
899 assert_eq!(new_cpu.pc, 0x1234);
900 assert_eq!(new_cpu.sp, 0x5678);
901 assert_eq!(new_cpu.a, 0x9a);
902 assert_eq!(new_cpu.b, 0xbc);
903 assert_eq!(new_cpu.c, 0xde);
904 assert_eq!(new_cpu.d, 0xf0);
905 assert_eq!(new_cpu.e, 0x12);
906 assert_eq!(new_cpu.h, 0x34);
907 assert_eq!(new_cpu.l, 0x56);
908 assert!(new_cpu.ime);
909 assert!(new_cpu.zero);
910 assert!(!new_cpu.sub);
911 assert!(new_cpu.half_carry);
912 assert!(!new_cpu.carry);
913 assert!(new_cpu.halted);
914 assert_eq!(new_cpu.cycles, 0x78);
915 assert_eq!(new_cpu.ppc, 0x9abc);
916 }
917}