1use crate::addressing::AddressingMode;
7use crate::bus::{Bus, CpuBus};
8use crate::opcodes::OPCODE_TABLE;
9use crate::state::{CpuState, InstructionType};
10use crate::status::StatusFlags;
11
12#[derive(Debug)]
17#[allow(clippy::struct_excessive_bools)] pub struct Cpu {
19 pub a: u8,
21 pub x: u8,
23 pub y: u8,
25 pub pc: u16,
27 pub sp: u8,
29 pub status: StatusFlags,
31 pub cycles: u64,
33 pub stall: u8,
35 pub(crate) nmi_pending: bool,
37 pub(crate) irq_pending: bool,
39 pub(crate) prev_irq_inhibit: bool,
42 pub(crate) suppress_nmi_next: bool,
46 pub jammed: bool,
48
49 state: CpuState,
52 current_opcode: u8,
54 instr_type: InstructionType,
56 current_addr_mode: AddressingMode,
58 operand_lo: u8,
60 operand_hi: u8,
62 effective_addr: u16,
64 base_addr: u16,
66 temp_value: u8,
68 branch_offset: i8,
70 page_crossed: bool,
72}
73
74impl Cpu {
75 pub fn new() -> Self {
83 Self {
84 a: 0,
85 x: 0,
86 y: 0,
87 pc: 0,
88 sp: 0xFD,
89 status: StatusFlags::from_bits_truncate(0x24), cycles: 0,
91 stall: 0,
92 nmi_pending: false,
93 irq_pending: false,
94 prev_irq_inhibit: true,
95 suppress_nmi_next: false,
96 jammed: false,
97 state: CpuState::default(),
99 current_opcode: 0,
100 instr_type: InstructionType::default(),
101 current_addr_mode: AddressingMode::Implied,
102 operand_lo: 0,
103 operand_hi: 0,
104 effective_addr: 0,
105 base_addr: 0,
106 temp_value: 0,
107 branch_offset: 0,
108 page_crossed: false,
109 }
110 }
111
112 pub fn reset(&mut self, bus: &mut impl Bus) {
120 self.sp = self.sp.wrapping_sub(3);
121 self.status.insert(StatusFlags::INTERRUPT_DISABLE);
122 self.pc = bus.read_u16(0xFFFC);
123 self.cycles += 7;
124 self.nmi_pending = false;
125 self.irq_pending = false;
126 self.prev_irq_inhibit = true;
127 self.jammed = false;
128 self.state = CpuState::FetchOpcode;
130 self.current_opcode = 0;
131 self.instr_type = InstructionType::default();
132 self.current_addr_mode = AddressingMode::Implied;
133 self.operand_lo = 0;
134 self.operand_hi = 0;
135 self.effective_addr = 0;
136 self.base_addr = 0;
137 self.temp_value = 0;
138 self.branch_offset = 0;
139 self.page_crossed = false;
140 }
141
142 #[inline]
147 pub fn step(&mut self, bus: &mut impl Bus) -> u8 {
148 if self.stall > 0 {
150 self.stall -= 1;
151 self.cycles += 1;
152 return 1;
153 }
154
155 if self.jammed {
157 self.cycles += 1;
158 return 1;
159 }
160
161 let current_irq_inhibit = self.status.contains(StatusFlags::INTERRUPT_DISABLE);
163
164 if self.nmi_pending && !self.suppress_nmi_next {
167 self.nmi_pending = false;
168 self.prev_irq_inhibit = true;
170 return self.handle_nmi(bus);
171 }
172
173 if self.suppress_nmi_next {
175 self.suppress_nmi_next = false;
176 }
177
178 if self.irq_pending && !self.prev_irq_inhibit {
183 self.prev_irq_inhibit = true;
185 return self.handle_irq(bus);
186 }
187
188 self.prev_irq_inhibit = current_irq_inhibit;
190
191 let opcode = bus.read(self.pc);
193 self.pc = self.pc.wrapping_add(1);
194
195 let info = &OPCODE_TABLE[opcode as usize];
197
198 let extra_cycles = self.execute_opcode(opcode, info.addr_mode, bus);
200
201 let total_cycles = info.cycles + extra_cycles;
203 self.cycles += u64::from(total_cycles);
204
205 total_cycles
206 }
207
208 pub fn trigger_nmi(&mut self) {
212 self.nmi_pending = true;
213 }
214
215 pub fn set_irq(&mut self, active: bool) {
219 self.irq_pending = active;
220 }
221
222 #[must_use]
224 pub fn irq_pending(&self) -> bool {
225 self.irq_pending
226 }
227
228 pub fn get_cycles(&self) -> u64 {
230 self.cycles
231 }
232
233 pub fn is_jammed(&self) -> bool {
235 self.jammed
236 }
237
238 pub fn get_state(&self) -> CpuState {
240 self.state
241 }
242
243 pub fn tick(&mut self, bus: &mut impl CpuBus) -> bool {
262 if self.stall > 0 {
264 self.stall -= 1;
265 self.cycles += 1;
266 return false;
267 }
268
269 if self.jammed {
271 self.cycles += 1;
272 return false;
273 }
274
275 self.cycles += 1;
276
277 match self.state {
279 CpuState::FetchOpcode => self.tick_fetch_opcode(bus),
280 CpuState::FetchOperandLo => self.tick_fetch_operand_lo(bus),
281 CpuState::FetchOperandHi => self.tick_fetch_operand_hi(bus),
282 CpuState::ResolveAddress => self.tick_resolve_address(bus),
283 CpuState::ReadData => self.tick_read_data(bus),
284 CpuState::WriteData => self.tick_write_data(bus),
285 CpuState::RmwRead => self.tick_rmw_read(bus),
286 CpuState::RmwDummyWrite => self.tick_rmw_dummy_write(bus),
287 CpuState::RmwWrite => self.tick_rmw_write(bus),
288 CpuState::Execute => self.tick_execute(bus),
289 CpuState::FetchIndirectLo => self.tick_fetch_indirect_lo(bus),
290 CpuState::FetchIndirectHi => self.tick_fetch_indirect_hi(bus),
291 CpuState::AddIndex => self.tick_add_index(bus),
292 CpuState::PushHi => self.tick_push_hi(bus),
293 CpuState::PushLo => self.tick_push_lo(bus),
294 CpuState::PushStatus => self.tick_push_status(bus),
295 CpuState::PopLo => self.tick_pop_lo(bus),
296 CpuState::PopHi => self.tick_pop_hi(bus),
297 CpuState::PopStatus => self.tick_pop_status(bus),
298 CpuState::InternalCycle => self.tick_internal_cycle(bus),
299 CpuState::BranchTaken => self.tick_branch_taken(bus),
300 CpuState::BranchPageCross => self.tick_branch_page_cross(bus),
301 CpuState::InterruptPushPcHi => self.tick_interrupt_push_pc_hi(bus),
302 CpuState::InterruptPushPcLo => self.tick_interrupt_push_pc_lo(bus),
303 CpuState::InterruptPushStatus => self.tick_interrupt_push_status(bus),
304 CpuState::InterruptFetchVectorLo => self.tick_interrupt_fetch_vector_lo(bus),
305 CpuState::InterruptFetchVectorHi => self.tick_interrupt_fetch_vector_hi(bus),
306 }
307 }
308
309 fn tick_fetch_opcode(&mut self, bus: &mut impl CpuBus) -> bool {
311 let current_irq_inhibit = self.status.contains(StatusFlags::INTERRUPT_DISABLE);
313
314 if self.nmi_pending && !self.suppress_nmi_next {
317 self.nmi_pending = false;
318 self.prev_irq_inhibit = current_irq_inhibit;
319 self.dummy_cycle(bus, self.pc);
321 self.state = CpuState::InterruptPushPcHi;
322 self.effective_addr = 0xFFFA;
324 return false;
325 }
326
327 if self.suppress_nmi_next {
329 self.suppress_nmi_next = false;
330 }
331
332 if self.irq_pending && !self.prev_irq_inhibit {
335 self.prev_irq_inhibit = current_irq_inhibit;
336 self.dummy_cycle(bus, self.pc);
338 self.state = CpuState::InterruptPushPcHi;
339 self.effective_addr = 0xFFFE;
341 return false;
342 }
343
344 self.prev_irq_inhibit = current_irq_inhibit;
346
347 self.current_opcode = self.read_cycle(bus, self.pc);
349 self.pc = self.pc.wrapping_add(1);
350
351 let info = &OPCODE_TABLE[self.current_opcode as usize];
353 self.current_addr_mode = info.addr_mode;
354 self.instr_type = InstructionType::from_opcode(self.current_opcode);
355
356 self.operand_lo = 0;
358 self.operand_hi = 0;
359 self.effective_addr = 0;
360 self.base_addr = 0;
361 self.temp_value = 0;
362 self.branch_offset = 0;
363 self.page_crossed = false;
364
365 self.state = self.next_state_after_fetch();
367
368 matches!(
370 self.instr_type,
371 InstructionType::Implied | InstructionType::Accumulator
372 ) && self.state == CpuState::Execute
373 }
374
375 fn next_state_after_fetch(&self) -> CpuState {
377 match self.current_addr_mode {
378 AddressingMode::Implied | AddressingMode::Accumulator => CpuState::Execute,
380
381 AddressingMode::Immediate => CpuState::FetchOperandLo,
383
384 AddressingMode::ZeroPage | AddressingMode::ZeroPageX | AddressingMode::ZeroPageY => {
386 CpuState::FetchOperandLo
387 }
388
389 AddressingMode::Absolute | AddressingMode::AbsoluteX | AddressingMode::AbsoluteY => {
391 CpuState::FetchOperandLo
392 }
393
394 AddressingMode::Indirect => CpuState::FetchOperandLo,
396
397 AddressingMode::IndexedIndirectX => CpuState::FetchOperandLo,
399
400 AddressingMode::IndirectIndexedY => CpuState::FetchOperandLo,
402
403 AddressingMode::Relative => CpuState::FetchOperandLo,
405 }
406 }
407
408 fn tick_fetch_operand_lo(&mut self, bus: &mut impl CpuBus) -> bool {
413 self.operand_lo = self.read_cycle(bus, self.pc);
414 self.pc = self.pc.wrapping_add(1);
415
416 match self.current_addr_mode {
417 AddressingMode::Immediate => {
419 self.effective_addr = self.pc.wrapping_sub(1);
420 self.temp_value = self.operand_lo;
421 if matches!(self.instr_type, InstructionType::Read) {
424 self.execute_read_instruction();
425 self.state = CpuState::FetchOpcode;
426 return true;
427 }
428 self.state = self.next_state_for_instruction_type();
429 }
430
431 AddressingMode::ZeroPage => {
433 self.effective_addr = u16::from(self.operand_lo);
434 self.state = self.next_state_for_instruction_type();
435 }
436 AddressingMode::ZeroPageX => {
437 self.base_addr = u16::from(self.operand_lo);
438 self.state = CpuState::AddIndex;
439 }
440 AddressingMode::ZeroPageY => {
441 self.base_addr = u16::from(self.operand_lo);
442 self.state = CpuState::AddIndex;
443 }
444
445 AddressingMode::Absolute
447 | AddressingMode::AbsoluteX
448 | AddressingMode::AbsoluteY
449 | AddressingMode::Indirect => {
450 self.state = CpuState::FetchOperandHi;
451 }
452
453 AddressingMode::IndexedIndirectX => {
455 self.base_addr = u16::from(self.operand_lo);
456 self.state = CpuState::AddIndex;
457 }
458
459 AddressingMode::IndirectIndexedY => {
461 self.base_addr = u16::from(self.operand_lo);
462 self.state = CpuState::FetchIndirectLo;
463 }
464
465 AddressingMode::Relative => {
467 self.branch_offset = self.operand_lo as i8;
468 if self.check_branch_condition() {
470 self.state = CpuState::BranchTaken;
471 } else {
472 self.state = CpuState::FetchOpcode;
474 return true;
475 }
476 }
477
478 _ => {
479 self.state = CpuState::FetchOpcode;
480 }
481 }
482 false
483 }
484
485 fn tick_fetch_operand_hi(&mut self, bus: &mut impl CpuBus) -> bool {
486 self.operand_hi = self.read_cycle(bus, self.pc);
487 self.pc = self.pc.wrapping_add(1);
488
489 let addr = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
490
491 match self.current_addr_mode {
492 AddressingMode::Absolute => {
493 self.effective_addr = addr;
494 match self.instr_type {
495 InstructionType::JumpAbsolute => {
496 self.pc = self.effective_addr;
498 self.state = CpuState::FetchOpcode;
499 return true;
500 }
501 InstructionType::JumpSubroutine => {
502 self.state = CpuState::InternalCycle;
504 }
505 _ => {
506 self.state = self.next_state_for_instruction_type();
507 }
508 }
509 }
510 AddressingMode::AbsoluteX => {
511 self.base_addr = addr;
512 let indexed = addr.wrapping_add(u16::from(self.x));
513 self.effective_addr = indexed;
514 self.page_crossed = (addr & 0xFF00) != (indexed & 0xFF00);
515
516 match self.instr_type {
519 InstructionType::Write | InstructionType::ReadModifyWrite => {
520 self.state = CpuState::ResolveAddress;
521 }
522 _ => {
523 if self.page_crossed {
524 self.state = CpuState::ResolveAddress;
525 } else {
526 self.state = self.next_state_for_instruction_type();
527 }
528 }
529 }
530 }
531 AddressingMode::AbsoluteY => {
532 self.base_addr = addr;
533 let indexed = addr.wrapping_add(u16::from(self.y));
534 self.effective_addr = indexed;
535 self.page_crossed = (addr & 0xFF00) != (indexed & 0xFF00);
536
537 match self.instr_type {
538 InstructionType::Write | InstructionType::ReadModifyWrite => {
539 self.state = CpuState::ResolveAddress;
540 }
541 _ => {
542 if self.page_crossed {
543 self.state = CpuState::ResolveAddress;
544 } else {
545 self.state = self.next_state_for_instruction_type();
546 }
547 }
548 }
549 }
550 AddressingMode::Indirect => {
551 self.base_addr = addr;
553 self.state = CpuState::FetchIndirectLo;
554 }
555 _ => {
556 self.state = CpuState::FetchOpcode;
557 }
558 }
559 false
560 }
561
562 fn tick_resolve_address(&mut self, bus: &mut impl CpuBus) -> bool {
563 let incorrect_addr = (self.base_addr & 0xFF00) | (self.effective_addr & 0x00FF);
566 self.dummy_cycle(bus, incorrect_addr);
567
568 self.state = self.next_state_for_instruction_type();
569 false
570 }
571
572 fn tick_read_data(&mut self, bus: &mut impl CpuBus) -> bool {
573 self.temp_value = self.read_cycle(bus, self.effective_addr);
575 self.execute_read_instruction();
578 self.state = CpuState::FetchOpcode;
579 true }
581
582 fn tick_write_data(&mut self, bus: &mut impl CpuBus) -> bool {
583 let value = self.execute_write_instruction();
585 self.write_cycle(bus, self.effective_addr, value);
586 self.state = CpuState::FetchOpcode;
587 true
588 }
589
590 fn tick_rmw_read(&mut self, bus: &mut impl CpuBus) -> bool {
591 self.temp_value = self.read_cycle(bus, self.effective_addr);
592 self.state = CpuState::RmwDummyWrite;
593 false
594 }
595
596 fn tick_rmw_dummy_write(&mut self, bus: &mut impl CpuBus) -> bool {
597 self.write_cycle(bus, self.effective_addr, self.temp_value);
599 self.state = CpuState::RmwWrite;
600 false
601 }
602
603 fn tick_rmw_write(&mut self, bus: &mut impl CpuBus) -> bool {
604 let result = self.execute_rmw_instruction();
606 self.write_cycle(bus, self.effective_addr, result);
607 self.state = CpuState::FetchOpcode;
608 true
609 }
610
611 fn tick_execute(&mut self, bus: &mut impl CpuBus) -> bool {
612 match self.instr_type {
614 InstructionType::Implied => {
615 self.dummy_cycle(bus, self.pc);
617 self.execute_implied_instruction();
618 }
619 InstructionType::Accumulator => {
620 self.dummy_cycle(bus, self.pc);
621 self.execute_accumulator_instruction();
622 }
623 InstructionType::Read => {
624 self.execute_read_instruction();
625 }
626 _ => {}
627 }
628 self.state = CpuState::FetchOpcode;
629 true
630 }
631
632 fn tick_fetch_indirect_lo(&mut self, bus: &mut impl CpuBus) -> bool {
633 match self.current_addr_mode {
634 AddressingMode::IndirectIndexedY => {
635 self.operand_lo = self.read_cycle(bus, self.base_addr);
637 self.state = CpuState::FetchIndirectHi;
638 }
639 AddressingMode::Indirect => {
640 self.operand_lo = self.read_cycle(bus, self.base_addr);
642 self.state = CpuState::FetchIndirectHi;
643 }
644 AddressingMode::IndexedIndirectX => {
645 let ptr = self.effective_addr as u8;
647 self.operand_lo = self.read_cycle(bus, u16::from(ptr));
648 self.state = CpuState::FetchIndirectHi;
649 }
650 _ => {
651 self.state = CpuState::FetchOpcode;
652 }
653 }
654 false
655 }
656
657 fn tick_fetch_indirect_hi(&mut self, bus: &mut impl CpuBus) -> bool {
658 match self.current_addr_mode {
659 AddressingMode::IndirectIndexedY => {
660 let ptr_hi = self.base_addr.wrapping_add(1) as u8;
662 self.operand_hi = self.read_cycle(bus, u16::from(ptr_hi));
663
664 let ptr_addr = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
665 let indexed = ptr_addr.wrapping_add(u16::from(self.y));
666 self.base_addr = ptr_addr;
667 self.effective_addr = indexed;
668 self.page_crossed = (ptr_addr & 0xFF00) != (indexed & 0xFF00);
669
670 match self.instr_type {
671 InstructionType::Write | InstructionType::ReadModifyWrite => {
672 self.state = CpuState::ResolveAddress;
673 }
674 _ => {
675 if self.page_crossed {
676 self.state = CpuState::ResolveAddress;
677 } else {
678 self.state = self.next_state_for_instruction_type();
679 }
680 }
681 }
682 }
683 AddressingMode::Indirect => {
684 let ptr_lo = self.base_addr as u8;
686 let ptr_hi_addr = (self.base_addr & 0xFF00) | u16::from(ptr_lo.wrapping_add(1));
687 self.operand_hi = self.read_cycle(bus, ptr_hi_addr);
688
689 self.effective_addr = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
690 self.pc = self.effective_addr;
691 self.state = CpuState::FetchOpcode;
692 return true;
693 }
694 AddressingMode::IndexedIndirectX => {
695 let ptr = (self.effective_addr as u8).wrapping_add(1);
697 self.operand_hi = self.read_cycle(bus, u16::from(ptr));
698 self.effective_addr = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
699 self.state = self.next_state_for_instruction_type();
700 }
701 _ => {
702 self.state = CpuState::FetchOpcode;
703 }
704 }
705 false
706 }
707
708 fn tick_add_index(&mut self, bus: &mut impl CpuBus) -> bool {
709 self.dummy_cycle(bus, self.base_addr);
711
712 match self.current_addr_mode {
713 AddressingMode::ZeroPageX => {
714 self.effective_addr = u16::from((self.base_addr as u8).wrapping_add(self.x));
715 self.state = self.next_state_for_instruction_type();
716 }
717 AddressingMode::ZeroPageY => {
718 self.effective_addr = u16::from((self.base_addr as u8).wrapping_add(self.y));
719 self.state = self.next_state_for_instruction_type();
720 }
721 AddressingMode::IndexedIndirectX => {
722 self.effective_addr = u16::from((self.base_addr as u8).wrapping_add(self.x));
724 self.state = CpuState::FetchIndirectLo;
725 }
726 _ => {
727 self.state = CpuState::FetchOpcode;
728 }
729 }
730 false
731 }
732
733 fn tick_push_hi(&mut self, bus: &mut impl CpuBus) -> bool {
734 let value = (self.pc >> 8) as u8;
735 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
736 self.sp = self.sp.wrapping_sub(1);
737 self.state = CpuState::PushLo;
738 false
739 }
740
741 fn tick_push_lo(&mut self, bus: &mut impl CpuBus) -> bool {
742 let value = (self.pc & 0xFF) as u8;
743 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
744 self.sp = self.sp.wrapping_sub(1);
745
746 match self.instr_type {
747 InstructionType::JumpSubroutine => {
748 self.pc = self.effective_addr;
750 self.state = CpuState::FetchOpcode;
751 return true;
752 }
753 InstructionType::Break => {
754 self.state = CpuState::PushStatus;
755 }
756 _ => {
757 self.state = CpuState::FetchOpcode;
758 }
759 }
760 false
761 }
762
763 fn tick_push_status(&mut self, bus: &mut impl CpuBus) -> bool {
764 match self.instr_type {
765 InstructionType::Push => {
766 let value = self.status.to_stack_byte(true);
768 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
769 self.sp = self.sp.wrapping_sub(1);
770 self.state = CpuState::FetchOpcode;
771 return true;
772 }
773 InstructionType::Break => {
774 let nmi_hijack = self.nmi_pending;
780 if nmi_hijack {
781 self.nmi_pending = false;
782 }
783
784 let value = self.status.to_stack_byte(true);
786 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
787 self.sp = self.sp.wrapping_sub(1);
788 self.status.insert(StatusFlags::INTERRUPT_DISABLE);
789
790 self.suppress_nmi_next = true;
794
795 self.effective_addr = if nmi_hijack { 0xFFFA } else { 0xFFFE };
797 self.state = CpuState::InterruptFetchVectorLo;
798 }
799 _ => {
800 self.state = CpuState::FetchOpcode;
801 }
802 }
803 false
804 }
805
806 fn tick_pop_lo(&mut self, bus: &mut impl CpuBus) -> bool {
807 self.sp = self.sp.wrapping_add(1);
809 self.dummy_cycle(bus, 0x0100 | u16::from(self.sp));
810
811 match self.instr_type {
812 InstructionType::Pull => {
813 self.state = CpuState::Execute;
814 }
815 InstructionType::ReturnSubroutine => {
816 self.operand_lo = self.read_cycle(bus, 0x0100 | u16::from(self.sp));
817 self.state = CpuState::PopHi;
818 }
819 InstructionType::ReturnInterrupt => {
820 self.state = CpuState::PopStatus;
822 }
823 _ => {
824 self.state = CpuState::FetchOpcode;
825 }
826 }
827 false
828 }
829
830 fn tick_pop_hi(&mut self, bus: &mut impl CpuBus) -> bool {
831 self.sp = self.sp.wrapping_add(1);
832 self.operand_hi = self.read_cycle(bus, 0x0100 | u16::from(self.sp));
833
834 match self.instr_type {
835 InstructionType::ReturnSubroutine => {
836 self.pc = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
837 self.state = CpuState::InternalCycle;
838 }
839 InstructionType::ReturnInterrupt => {
840 self.pc = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
841 self.state = CpuState::FetchOpcode;
842 return true;
843 }
844 _ => {
845 self.state = CpuState::FetchOpcode;
846 }
847 }
848 false
849 }
850
851 fn tick_pop_status(&mut self, bus: &mut impl CpuBus) -> bool {
852 let value = self.read_cycle(bus, 0x0100 | u16::from(self.sp));
853 self.status = StatusFlags::from_stack_byte(value);
854
855 if self.status.contains(StatusFlags::INTERRUPT_DISABLE) {
858 self.prev_irq_inhibit = true;
859 }
860
861 self.sp = self.sp.wrapping_add(1);
862 self.operand_lo = self.read_cycle(bus, 0x0100 | u16::from(self.sp));
863 self.state = CpuState::PopHi;
864 false
865 }
866
867 fn tick_internal_cycle(&mut self, bus: &mut impl CpuBus) -> bool {
868 self.dummy_cycle(bus, 0x0100 | u16::from(self.sp));
870
871 match self.instr_type {
872 InstructionType::JumpSubroutine => {
873 self.state = CpuState::PushHi;
875 }
876 InstructionType::ReturnSubroutine => {
877 self.pc = self.pc.wrapping_add(1);
879 self.state = CpuState::FetchOpcode;
880 return true;
881 }
882 InstructionType::Push => {
883 match self.current_opcode {
885 0x48 => {
886 self.write_cycle(bus, 0x0100 | u16::from(self.sp), self.a);
888 self.sp = self.sp.wrapping_sub(1);
889 }
890 0x08 => {
891 self.state = CpuState::PushStatus;
893 return false;
894 }
895 _ => {}
896 }
897 self.state = CpuState::FetchOpcode;
898 return true;
899 }
900 InstructionType::Pull => {
901 self.sp = self.sp.wrapping_add(1);
903 self.temp_value = self.read_cycle(bus, 0x0100 | u16::from(self.sp));
904 match self.current_opcode {
905 0x68 => {
906 self.a = self.temp_value;
908 self.set_zn(self.a);
909 }
910 0x28 => {
911 self.status = StatusFlags::from_stack_byte(self.temp_value);
913 }
914 _ => {}
915 }
916 self.state = CpuState::FetchOpcode;
917 return true;
918 }
919 _ => {
920 self.state = CpuState::FetchOpcode;
921 }
922 }
923 false
924 }
925
926 fn tick_branch_taken(&mut self, bus: &mut impl CpuBus) -> bool {
927 self.dummy_cycle(bus, self.pc);
929
930 let old_pc = self.pc;
931 self.pc = self.pc.wrapping_add(self.branch_offset as u16);
932
933 if (old_pc & 0xFF00) == (self.pc & 0xFF00) {
935 self.state = CpuState::FetchOpcode;
936 true
937 } else {
938 self.state = CpuState::BranchPageCross;
939 false
940 }
941 }
942
943 fn tick_branch_page_cross(&mut self, bus: &mut impl CpuBus) -> bool {
944 self.dummy_cycle(
946 bus,
947 (self.pc & 0x00FF) | ((self.pc.wrapping_sub(self.branch_offset as u16)) & 0xFF00),
948 );
949 self.state = CpuState::FetchOpcode;
950 true
951 }
952
953 fn tick_interrupt_push_pc_hi(&mut self, bus: &mut impl CpuBus) -> bool {
954 let value = (self.pc >> 8) as u8;
955 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
956 self.sp = self.sp.wrapping_sub(1);
957 self.state = CpuState::InterruptPushPcLo;
958 false
959 }
960
961 fn tick_interrupt_push_pc_lo(&mut self, bus: &mut impl CpuBus) -> bool {
962 let value = (self.pc & 0xFF) as u8;
963 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
964 self.sp = self.sp.wrapping_sub(1);
965 self.state = CpuState::InterruptPushStatus;
966 false
967 }
968
969 fn tick_interrupt_push_status(&mut self, bus: &mut impl CpuBus) -> bool {
970 let value = self.status.to_stack_byte(false);
972 self.write_cycle(bus, 0x0100 | u16::from(self.sp), value);
973 self.sp = self.sp.wrapping_sub(1);
974 self.status.insert(StatusFlags::INTERRUPT_DISABLE);
975 self.state = CpuState::InterruptFetchVectorLo;
976 false
977 }
978
979 fn tick_interrupt_fetch_vector_lo(&mut self, bus: &mut impl CpuBus) -> bool {
980 self.operand_lo = self.read_cycle(bus, self.effective_addr);
981 self.state = CpuState::InterruptFetchVectorHi;
982 false
983 }
984
985 fn tick_interrupt_fetch_vector_hi(&mut self, bus: &mut impl CpuBus) -> bool {
986 self.operand_hi = self.read_cycle(bus, self.effective_addr.wrapping_add(1));
987 self.pc = u16::from_le_bytes([self.operand_lo, self.operand_hi]);
988 self.state = CpuState::FetchOpcode;
989 true
990 }
991
992 #[inline]
1023 pub fn read_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) -> u8 {
1024 bus.on_cpu_cycle();
1025 bus.read(addr)
1026 }
1027
1028 #[inline]
1047 pub fn write_cycle(&mut self, bus: &mut impl CpuBus, addr: u16, value: u8) {
1048 bus.on_cpu_cycle();
1049 bus.write(addr, value);
1050 }
1051
1052 #[inline]
1070 pub fn dummy_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) {
1071 bus.on_cpu_cycle();
1072 let _ = bus.read(addr);
1073 }
1074
1075 #[inline]
1084 pub fn push_cycle(&mut self, bus: &mut impl CpuBus, value: u8) {
1085 bus.on_cpu_cycle();
1086 bus.write(0x0100 | u16::from(self.sp), value);
1087 self.sp = self.sp.wrapping_sub(1);
1088 }
1089
1090 #[inline]
1102 pub fn pop_cycle(&mut self, bus: &mut impl CpuBus) -> u8 {
1103 self.sp = self.sp.wrapping_add(1);
1104 bus.on_cpu_cycle();
1105 bus.read(0x0100 | u16::from(self.sp))
1106 }
1107
1108 #[inline]
1122 pub fn read_u16_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) -> u16 {
1123 let lo = self.read_cycle(bus, addr) as u16;
1124 let hi = self.read_cycle(bus, addr.wrapping_add(1)) as u16;
1125 (hi << 8) | lo
1126 }
1127
1128 #[inline]
1142 pub fn read_u16_wrap_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) -> u16 {
1143 let lo = self.read_cycle(bus, addr) as u16;
1144
1145 let hi_addr = if addr & 0xFF == 0xFF {
1147 addr & 0xFF00
1148 } else {
1149 addr.wrapping_add(1)
1150 };
1151
1152 let hi = self.read_cycle(bus, hi_addr) as u16;
1153 (hi << 8) | lo
1154 }
1155
1156 #[inline]
1166 pub fn push_u16_cycle(&mut self, bus: &mut impl CpuBus, value: u16) {
1167 self.push_cycle(bus, (value >> 8) as u8);
1168 self.push_cycle(bus, (value & 0xFF) as u8);
1169 }
1170
1171 #[inline]
1184 pub fn pop_u16_cycle(&mut self, bus: &mut impl CpuBus) -> u16 {
1185 let lo = self.pop_cycle(bus);
1186 let hi = self.pop_cycle(bus);
1187 u16::from_le_bytes([lo, hi])
1188 }
1189
1190 fn next_state_for_instruction_type(&self) -> CpuState {
1196 match self.instr_type {
1197 InstructionType::Read => CpuState::ReadData,
1198 InstructionType::Write => CpuState::WriteData,
1199 InstructionType::ReadModifyWrite => CpuState::RmwRead,
1200 InstructionType::Implied | InstructionType::Accumulator => CpuState::Execute,
1201 InstructionType::Push => CpuState::InternalCycle,
1202 InstructionType::Pull => CpuState::InternalCycle,
1203 _ => CpuState::Execute,
1204 }
1205 }
1206
1207 fn check_branch_condition(&self) -> bool {
1209 match self.current_opcode {
1210 0x10 => !self.status.contains(StatusFlags::NEGATIVE), 0x30 => self.status.contains(StatusFlags::NEGATIVE), 0x50 => !self.status.contains(StatusFlags::OVERFLOW), 0x70 => self.status.contains(StatusFlags::OVERFLOW), 0x90 => !self.status.contains(StatusFlags::CARRY), 0xB0 => self.status.contains(StatusFlags::CARRY), 0xD0 => !self.status.contains(StatusFlags::ZERO), 0xF0 => self.status.contains(StatusFlags::ZERO), _ => false,
1219 }
1220 }
1221
1222 fn execute_implied_instruction(&mut self) {
1224 match self.current_opcode {
1225 0xAA => {
1227 self.x = self.a;
1228 self.set_zn(self.x);
1229 } 0xA8 => {
1231 self.y = self.a;
1232 self.set_zn(self.y);
1233 } 0x8A => {
1235 self.a = self.x;
1236 self.set_zn(self.a);
1237 } 0x98 => {
1239 self.a = self.y;
1240 self.set_zn(self.a);
1241 } 0xBA => {
1243 self.a = self.sp;
1244 self.set_zn(self.a);
1245 } 0x9A => {
1247 self.sp = self.x;
1248 } 0xE8 => {
1252 self.x = self.x.wrapping_add(1);
1253 self.set_zn(self.x);
1254 } 0xC8 => {
1256 self.y = self.y.wrapping_add(1);
1257 self.set_zn(self.y);
1258 } 0xCA => {
1260 self.x = self.x.wrapping_sub(1);
1261 self.set_zn(self.x);
1262 } 0x88 => {
1264 self.y = self.y.wrapping_sub(1);
1265 self.set_zn(self.y);
1266 } 0x18 => {
1270 self.status.remove(StatusFlags::CARRY);
1271 } 0x38 => {
1273 self.status.insert(StatusFlags::CARRY);
1274 } 0x58 => {
1276 self.status.remove(StatusFlags::INTERRUPT_DISABLE);
1277 } 0x78 => {
1279 self.status.insert(StatusFlags::INTERRUPT_DISABLE);
1280 } 0xB8 => {
1282 self.status.remove(StatusFlags::OVERFLOW);
1283 } 0xD8 => {
1285 self.status.remove(StatusFlags::DECIMAL);
1286 } 0xF8 => {
1288 self.status.insert(StatusFlags::DECIMAL);
1289 } 0xEA | 0x1A | 0x3A | 0x5A | 0x7A | 0xDA | 0xFA => {}
1293
1294 _ => {}
1295 }
1296 }
1297
1298 fn execute_accumulator_instruction(&mut self) {
1300 match self.current_opcode {
1301 0x0A => {
1302 let carry = (self.a & 0x80) != 0;
1304 self.a <<= 1;
1305 self.status.set(StatusFlags::CARRY, carry);
1306 self.set_zn(self.a);
1307 }
1308 0x4A => {
1309 let carry = (self.a & 0x01) != 0;
1311 self.a >>= 1;
1312 self.status.set(StatusFlags::CARRY, carry);
1313 self.set_zn(self.a);
1314 }
1315 0x2A => {
1316 let old_carry = self.status.contains(StatusFlags::CARRY);
1318 let new_carry = (self.a & 0x80) != 0;
1319 self.a = (self.a << 1) | u8::from(old_carry);
1320 self.status.set(StatusFlags::CARRY, new_carry);
1321 self.set_zn(self.a);
1322 }
1323 0x6A => {
1324 let old_carry = self.status.contains(StatusFlags::CARRY);
1326 let new_carry = (self.a & 0x01) != 0;
1327 self.a = (self.a >> 1) | (u8::from(old_carry) << 7);
1328 self.status.set(StatusFlags::CARRY, new_carry);
1329 self.set_zn(self.a);
1330 }
1331 _ => {}
1332 }
1333 }
1334
1335 #[allow(clippy::too_many_lines)]
1337 fn execute_read_instruction(&mut self) {
1338 let value = self.temp_value;
1339 match self.current_opcode {
1340 0xA9 | 0xA5 | 0xB5 | 0xAD | 0xBD | 0xB9 | 0xA1 | 0xB1 => {
1342 self.a = value;
1343 self.set_zn(self.a);
1344 }
1345 0xA2 | 0xA6 | 0xB6 | 0xAE | 0xBE => {
1347 self.x = value;
1348 self.set_zn(self.x);
1349 }
1350 0xA0 | 0xA4 | 0xB4 | 0xAC | 0xBC => {
1352 self.y = value;
1353 self.set_zn(self.y);
1354 }
1355 0x69 | 0x65 | 0x75 | 0x6D | 0x7D | 0x79 | 0x61 | 0x71 => {
1357 self.do_adc(value);
1358 }
1359 0xE9 | 0xE5 | 0xF5 | 0xED | 0xFD | 0xF9 | 0xE1 | 0xF1 | 0xEB => {
1361 self.do_sbc(value);
1362 }
1363 0x29 | 0x25 | 0x35 | 0x2D | 0x3D | 0x39 | 0x21 | 0x31 => {
1365 self.a &= value;
1366 self.set_zn(self.a);
1367 }
1368 0x09 | 0x05 | 0x15 | 0x0D | 0x1D | 0x19 | 0x01 | 0x11 => {
1370 self.a |= value;
1371 self.set_zn(self.a);
1372 }
1373 0x49 | 0x45 | 0x55 | 0x4D | 0x5D | 0x59 | 0x41 | 0x51 => {
1375 self.a ^= value;
1376 self.set_zn(self.a);
1377 }
1378 0xC9 | 0xC5 | 0xD5 | 0xCD | 0xDD | 0xD9 | 0xC1 | 0xD1 => {
1380 self.do_compare(self.a, value);
1381 }
1382 0xE0 | 0xE4 | 0xEC => {
1384 self.do_compare(self.x, value);
1385 }
1386 0xC0 | 0xC4 | 0xCC => {
1388 self.do_compare(self.y, value);
1389 }
1390 0x24 | 0x2C => {
1392 self.status.set(StatusFlags::ZERO, (self.a & value) == 0);
1393 self.status.set(StatusFlags::OVERFLOW, (value & 0x40) != 0);
1394 self.status.set(StatusFlags::NEGATIVE, (value & 0x80) != 0);
1395 }
1396 0xA7 | 0xB7 | 0xAF | 0xBF | 0xA3 | 0xB3 => {
1398 self.a = value;
1399 self.x = value;
1400 self.set_zn(self.a);
1401 }
1402 0xBB => {
1404 let result = value & self.sp;
1405 self.a = result;
1406 self.x = result;
1407 self.sp = result;
1408 self.set_zn(result);
1409 }
1410 0x0B | 0x2B => {
1412 self.a &= value;
1413 self.set_zn(self.a);
1414 self.status.set(StatusFlags::CARRY, (self.a & 0x80) != 0);
1415 }
1416 0x4B => {
1418 self.a &= value;
1419 let carry = (self.a & 0x01) != 0;
1420 self.a >>= 1;
1421 self.status.set(StatusFlags::CARRY, carry);
1422 self.set_zn(self.a);
1423 }
1424 0x6B => {
1426 self.a &= value;
1427 let old_carry = self.status.contains(StatusFlags::CARRY);
1428 self.a = (self.a >> 1) | (u8::from(old_carry) << 7);
1429 self.set_zn(self.a);
1430 self.status.set(StatusFlags::CARRY, (self.a & 0x40) != 0);
1431 self.status.set(
1432 StatusFlags::OVERFLOW,
1433 ((self.a & 0x40) ^ ((self.a & 0x20) << 1)) != 0,
1434 );
1435 }
1436 0x8B => {
1438 self.a = (self.a | 0xEE) & self.x & value;
1439 self.set_zn(self.a);
1440 }
1441 0xAB => {
1443 self.a = (self.a | 0xEE) & value;
1444 self.x = self.a;
1445 self.set_zn(self.a);
1446 }
1447 0xCB => {
1449 let temp = (self.a & self.x).wrapping_sub(value);
1450 self.status
1451 .set(StatusFlags::CARRY, (self.a & self.x) >= value);
1452 self.x = temp;
1453 self.set_zn(self.x);
1454 }
1455 0x80 | 0x82 | 0x89 | 0xC2 | 0xE2 | 0x04 | 0x44 | 0x64 | 0x14 | 0x34 | 0x54 | 0x74
1457 | 0xD4 | 0xF4 | 0x0C | 0x1C | 0x3C | 0x5C | 0x7C | 0xDC | 0xFC => {
1458 }
1460 _ => {}
1461 }
1462 }
1463
1464 fn execute_write_instruction(&self) -> u8 {
1466 match self.current_opcode {
1467 0x85 | 0x95 | 0x8D | 0x9D | 0x99 | 0x81 | 0x91 => self.a,
1469 0x86 | 0x96 | 0x8E => self.x,
1471 0x84 | 0x94 | 0x8C => self.y,
1473 0x87 | 0x97 | 0x8F | 0x83 => self.a & self.x,
1475 0x93 | 0x9F => self.a & self.x & ((self.effective_addr >> 8) as u8).wrapping_add(1),
1477 0x9E => self.x & ((self.effective_addr >> 8) as u8).wrapping_add(1),
1479 0x9C => self.y & ((self.effective_addr >> 8) as u8).wrapping_add(1),
1481 0x9B => {
1483 self.a & self.x & ((self.effective_addr >> 8) as u8).wrapping_add(1)
1485 }
1486 _ => 0,
1487 }
1488 }
1489
1490 fn execute_rmw_instruction(&mut self) -> u8 {
1492 let value = self.temp_value;
1493 match self.current_opcode {
1494 0x06 | 0x16 | 0x0E | 0x1E => {
1496 let carry = (value & 0x80) != 0;
1497 let result = value << 1;
1498 self.status.set(StatusFlags::CARRY, carry);
1499 self.set_zn(result);
1500 result
1501 }
1502 0x46 | 0x56 | 0x4E | 0x5E => {
1504 let carry = (value & 0x01) != 0;
1505 let result = value >> 1;
1506 self.status.set(StatusFlags::CARRY, carry);
1507 self.set_zn(result);
1508 result
1509 }
1510 0x26 | 0x36 | 0x2E | 0x3E => {
1512 let old_carry = self.status.contains(StatusFlags::CARRY);
1513 let new_carry = (value & 0x80) != 0;
1514 let result = (value << 1) | u8::from(old_carry);
1515 self.status.set(StatusFlags::CARRY, new_carry);
1516 self.set_zn(result);
1517 result
1518 }
1519 0x66 | 0x76 | 0x6E | 0x7E => {
1521 let old_carry = self.status.contains(StatusFlags::CARRY);
1522 let new_carry = (value & 0x01) != 0;
1523 let result = (value >> 1) | (u8::from(old_carry) << 7);
1524 self.status.set(StatusFlags::CARRY, new_carry);
1525 self.set_zn(result);
1526 result
1527 }
1528 0xE6 | 0xF6 | 0xEE | 0xFE => {
1530 let result = value.wrapping_add(1);
1531 self.set_zn(result);
1532 result
1533 }
1534 0xC6 | 0xD6 | 0xCE | 0xDE => {
1536 let result = value.wrapping_sub(1);
1537 self.set_zn(result);
1538 result
1539 }
1540 0x07 | 0x17 | 0x0F | 0x1F | 0x1B | 0x03 | 0x13 => {
1542 let carry = (value & 0x80) != 0;
1543 let result = value << 1;
1544 self.status.set(StatusFlags::CARRY, carry);
1545 self.a |= result;
1546 self.set_zn(self.a);
1547 result
1548 }
1549 0x27 | 0x37 | 0x2F | 0x3F | 0x3B | 0x23 | 0x33 => {
1551 let old_carry = self.status.contains(StatusFlags::CARRY);
1552 let new_carry = (value & 0x80) != 0;
1553 let result = (value << 1) | u8::from(old_carry);
1554 self.status.set(StatusFlags::CARRY, new_carry);
1555 self.a &= result;
1556 self.set_zn(self.a);
1557 result
1558 }
1559 0x47 | 0x57 | 0x4F | 0x5F | 0x5B | 0x43 | 0x53 => {
1561 let carry = (value & 0x01) != 0;
1562 let result = value >> 1;
1563 self.status.set(StatusFlags::CARRY, carry);
1564 self.a ^= result;
1565 self.set_zn(self.a);
1566 result
1567 }
1568 0x67 | 0x77 | 0x6F | 0x7F | 0x7B | 0x63 | 0x73 => {
1570 let old_carry = self.status.contains(StatusFlags::CARRY);
1571 let new_carry = (value & 0x01) != 0;
1572 let result = (value >> 1) | (u8::from(old_carry) << 7);
1573 self.status.set(StatusFlags::CARRY, new_carry);
1574 self.do_adc(result);
1575 result
1576 }
1577 0xC7 | 0xD7 | 0xCF | 0xDF | 0xDB | 0xC3 | 0xD3 => {
1579 let result = value.wrapping_sub(1);
1580 self.do_compare(self.a, result);
1581 result
1582 }
1583 0xE7 | 0xF7 | 0xEF | 0xFF | 0xFB | 0xE3 | 0xF3 => {
1585 let result = value.wrapping_add(1);
1586 self.do_sbc(result);
1587 result
1588 }
1589 _ => value,
1590 }
1591 }
1592
1593 fn do_adc(&mut self, value: u8) {
1595 let carry = u16::from(self.status.contains(StatusFlags::CARRY));
1596 let sum = u16::from(self.a) + u16::from(value) + carry;
1597 let result = sum as u8;
1598
1599 self.status.set(StatusFlags::CARRY, sum > 0xFF);
1600 self.status.set(
1601 StatusFlags::OVERFLOW,
1602 (!(self.a ^ value) & (self.a ^ result) & 0x80) != 0,
1603 );
1604 self.a = result;
1605 self.set_zn(self.a);
1606 }
1607
1608 fn do_sbc(&mut self, value: u8) {
1610 self.do_adc(!value);
1612 }
1613
1614 fn do_compare(&mut self, register: u8, value: u8) {
1616 let result = register.wrapping_sub(value);
1617 self.status.set(StatusFlags::CARRY, register >= value);
1618 self.set_zn(result);
1619 }
1620
1621 #[inline]
1623 fn handle_nmi(&mut self, bus: &mut impl Bus) -> u8 {
1624 self.push_u16(bus, self.pc);
1625 self.push(bus, self.status.to_stack_byte(false)); self.status.insert(StatusFlags::INTERRUPT_DISABLE);
1627 self.pc = bus.read_u16(0xFFFA); 7
1629 }
1630
1631 #[inline]
1633 fn handle_irq(&mut self, bus: &mut impl Bus) -> u8 {
1634 self.push_u16(bus, self.pc);
1635 self.push(bus, self.status.to_stack_byte(false)); self.status.insert(StatusFlags::INTERRUPT_DISABLE);
1637 self.pc = bus.read_u16(0xFFFE); 7
1639 }
1640
1641 #[inline]
1645 fn execute_opcode(&mut self, opcode: u8, addr_mode: AddressingMode, bus: &mut impl Bus) -> u8 {
1646 match opcode {
1647 0xA9 => self.lda(bus, addr_mode),
1649 0xA5 | 0xB5 | 0xAD | 0xBD | 0xB9 | 0xA1 | 0xB1 => self.lda(bus, addr_mode),
1650 0xA2 => self.ldx(bus, addr_mode),
1651 0xA6 | 0xB6 | 0xAE | 0xBE => self.ldx(bus, addr_mode),
1652 0xA0 => self.ldy(bus, addr_mode),
1653 0xA4 | 0xB4 | 0xAC | 0xBC => self.ldy(bus, addr_mode),
1654 0x85 | 0x95 | 0x8D | 0x9D | 0x99 | 0x81 | 0x91 => self.sta(bus, addr_mode),
1655 0x86 | 0x96 | 0x8E => self.stx(bus, addr_mode),
1656 0x84 | 0x94 | 0x8C => self.sty(bus, addr_mode),
1657
1658 0xAA => self.tax(bus),
1660 0xA8 => self.tay(bus),
1661 0x8A => self.txa(bus),
1662 0x98 => self.tya(bus),
1663 0xBA => self.tsx(bus),
1664 0x9A => self.txs(bus),
1665
1666 0x48 => self.pha(bus),
1668 0x08 => self.php(bus),
1669 0x68 => self.pla(bus),
1670 0x28 => self.plp(bus),
1671
1672 0x69 | 0x65 | 0x75 | 0x6D | 0x7D | 0x79 | 0x61 | 0x71 => self.adc(bus, addr_mode),
1674 0xE9 | 0xE5 | 0xF5 | 0xED | 0xFD | 0xF9 | 0xE1 | 0xF1 | 0xEB => {
1675 self.sbc(bus, addr_mode)
1676 }
1677
1678 0xE6 | 0xF6 | 0xEE | 0xFE => self.inc(bus, addr_mode),
1680 0xC6 | 0xD6 | 0xCE | 0xDE => self.dec(bus, addr_mode),
1681 0xE8 => self.inx(bus),
1682 0xC8 => self.iny(bus),
1683 0xCA => self.dex(bus),
1684 0x88 => self.dey(bus),
1685
1686 0x29 | 0x25 | 0x35 | 0x2D | 0x3D | 0x39 | 0x21 | 0x31 => self.and(bus, addr_mode),
1688 0x09 | 0x05 | 0x15 | 0x0D | 0x1D | 0x19 | 0x01 | 0x11 => self.ora(bus, addr_mode),
1689 0x49 | 0x45 | 0x55 | 0x4D | 0x5D | 0x59 | 0x41 | 0x51 => self.eor(bus, addr_mode),
1690 0x24 | 0x2C => self.bit(bus, addr_mode),
1691
1692 0x0A => self.asl_acc(bus),
1694 0x06 | 0x16 | 0x0E | 0x1E => self.asl(bus, addr_mode),
1695 0x4A => self.lsr_acc(bus),
1696 0x46 | 0x56 | 0x4E | 0x5E => self.lsr(bus, addr_mode),
1697 0x2A => self.rol_acc(bus),
1698 0x26 | 0x36 | 0x2E | 0x3E => self.rol(bus, addr_mode),
1699 0x6A => self.ror_acc(bus),
1700 0x66 | 0x76 | 0x6E | 0x7E => self.ror(bus, addr_mode),
1701
1702 0xC9 | 0xC5 | 0xD5 | 0xCD | 0xDD | 0xD9 | 0xC1 | 0xD1 => self.cmp(bus, addr_mode),
1704 0xE0 | 0xE4 | 0xEC => self.cpx(bus, addr_mode),
1705 0xC0 | 0xC4 | 0xCC => self.cpy(bus, addr_mode),
1706
1707 0x10 => self.bpl(bus),
1709 0x30 => self.bmi(bus),
1710 0x50 => self.bvc(bus),
1711 0x70 => self.bvs(bus),
1712 0x90 => self.bcc(bus),
1713 0xB0 => self.bcs(bus),
1714 0xD0 => self.bne(bus),
1715 0xF0 => self.beq(bus),
1716
1717 0x4C => self.jmp_abs(bus),
1719 0x6C => self.jmp_ind(bus),
1720 0x20 => self.jsr(bus),
1721 0x60 => self.rts(bus),
1722 0x40 => self.rti(bus),
1723 0x00 => self.brk(bus),
1724
1725 0x18 => self.clc(bus),
1727 0x38 => self.sec(bus),
1728 0x58 => self.cli(bus),
1729 0x78 => self.sei(bus),
1730 0xB8 => self.clv(bus),
1731 0xD8 => self.cld(bus),
1732 0xF8 => self.sed(bus),
1733 0xEA => self.nop(bus),
1734
1735 0xA7 | 0xB7 | 0xAF | 0xBF | 0xA3 | 0xB3 => self.lax(bus, addr_mode),
1737 0x87 | 0x97 | 0x8F | 0x83 => self.sax(bus, addr_mode),
1738 0xC7 | 0xD7 | 0xCF | 0xDF | 0xDB | 0xC3 | 0xD3 => self.dcp(bus, addr_mode),
1739 0xE7 | 0xF7 | 0xEF | 0xFF | 0xFB | 0xE3 | 0xF3 => self.isc(bus, addr_mode),
1740 0x07 | 0x17 | 0x0F | 0x1F | 0x1B | 0x03 | 0x13 => self.slo(bus, addr_mode),
1741 0x27 | 0x37 | 0x2F | 0x3F | 0x3B | 0x23 | 0x33 => self.rla(bus, addr_mode),
1742 0x47 | 0x57 | 0x4F | 0x5F | 0x5B | 0x43 | 0x53 => self.sre(bus, addr_mode),
1743 0x67 | 0x77 | 0x6F | 0x7F | 0x7B | 0x63 | 0x73 => self.rra(bus, addr_mode),
1744 0x0B | 0x2B => self.anc(bus),
1745 0x4B => self.alr(bus),
1746 0x6B => self.arr(bus),
1747 0x8B => self.xaa(bus),
1748 0xAB => self.lxa(bus),
1749 0xCB => self.axs(bus),
1750 0x93 | 0x9F => self.sha(bus, addr_mode),
1751 0x9C => self.shy(bus),
1752 0x9E => self.shx(bus),
1753 0x9B => self.tas(bus),
1754 0xBB => self.las(bus, addr_mode),
1755
1756 0x1A | 0x3A | 0x5A | 0x7A | 0xDA | 0xFA => self.nop(bus),
1758 0x80 | 0x82 | 0x89 | 0xC2 | 0xE2 => self.nop_read(bus, addr_mode),
1759 0x04 | 0x44 | 0x64 | 0x14 | 0x34 | 0x54 | 0x74 | 0xD4 | 0xF4 => {
1760 self.nop_read(bus, addr_mode)
1761 }
1762 0x0C | 0x1C | 0x3C | 0x5C | 0x7C | 0xDC | 0xFC => self.nop_read(bus, addr_mode),
1763
1764 0x02 | 0x12 | 0x22 | 0x32 | 0x42 | 0x52 | 0x62 | 0x72 | 0x92 | 0xB2 | 0xD2 | 0xF2 => {
1766 self.jam()
1767 }
1768 }
1769 }
1770
1771 pub(crate) fn push(&mut self, bus: &mut impl Bus, value: u8) {
1773 bus.write(0x0100 | u16::from(self.sp), value);
1774 self.sp = self.sp.wrapping_sub(1);
1775 }
1776
1777 pub(crate) fn pop(&mut self, bus: &mut impl Bus) -> u8 {
1779 self.sp = self.sp.wrapping_add(1);
1780 bus.read(0x0100 | u16::from(self.sp))
1781 }
1782
1783 pub(crate) fn push_u16(&mut self, bus: &mut impl Bus, value: u16) {
1785 self.push(bus, (value >> 8) as u8);
1786 self.push(bus, (value & 0xFF) as u8);
1787 }
1788
1789 pub(crate) fn pop_u16(&mut self, bus: &mut impl Bus) -> u16 {
1791 let lo = self.pop(bus);
1792 let hi = self.pop(bus);
1793 u16::from_le_bytes([lo, hi])
1794 }
1795
1796 pub(crate) fn read_operand(&mut self, bus: &mut impl Bus, mode: AddressingMode) -> (u8, bool) {
1798 let result = mode.resolve(self.pc, self.x, self.y, bus);
1799 self.pc = self.pc.wrapping_add(u16::from(mode.operand_bytes()));
1800
1801 if result.page_crossed {
1805 match mode {
1806 AddressingMode::AbsoluteX
1807 | AddressingMode::AbsoluteY
1808 | AddressingMode::IndirectIndexedY => {
1809 let incorrect_addr = (result.base_addr & 0xFF00) | (result.addr & 0x00FF);
1812 let _ = bus.read(incorrect_addr);
1813 }
1814 _ => {}
1815 }
1816 }
1817
1818 let value = match mode {
1819 AddressingMode::Accumulator => self.a,
1820 _ => bus.read(result.addr),
1821 };
1822
1823 (value, result.page_crossed)
1824 }
1825
1826 pub(crate) fn write_operand(&mut self, bus: &mut impl Bus, mode: AddressingMode, value: u8) {
1828 let result = mode.resolve(self.pc, self.x, self.y, bus);
1829 self.pc = self.pc.wrapping_add(u16::from(mode.operand_bytes()));
1830
1831 match mode {
1834 AddressingMode::AbsoluteX
1835 | AddressingMode::AbsoluteY
1836 | AddressingMode::IndirectIndexedY => {
1837 let incorrect_addr = (result.base_addr & 0xFF00) | (result.addr & 0x00FF);
1839 bus.write(incorrect_addr, value);
1841 }
1842 _ => {}
1843 }
1844
1845 match mode {
1846 AddressingMode::Accumulator => self.a = value,
1847 _ => bus.write(result.addr, value),
1848 }
1849 }
1850
1851 #[inline]
1853 pub(crate) fn set_zn(&mut self, value: u8) {
1854 self.status.set_zn(value);
1855 }
1856}
1857
1858impl Default for Cpu {
1859 fn default() -> Self {
1860 Self::new()
1861 }
1862}
1863
1864#[cfg(test)]
1865mod tests {
1866 use super::*;
1867
1868 struct TestBus {
1869 memory: [u8; 0x10000],
1870 }
1871
1872 impl TestBus {
1873 fn new() -> Self {
1874 Self {
1875 memory: [0; 0x10000],
1876 }
1877 }
1878 }
1879
1880 impl Bus for TestBus {
1881 fn read(&mut self, addr: u16) -> u8 {
1882 self.memory[addr as usize]
1883 }
1884
1885 fn write(&mut self, addr: u16, value: u8) {
1886 self.memory[addr as usize] = value;
1887 }
1888 }
1889
1890 #[test]
1891 fn test_cpu_new() {
1892 let cpu = Cpu::new();
1893 assert_eq!(cpu.a, 0);
1894 assert_eq!(cpu.x, 0);
1895 assert_eq!(cpu.y, 0);
1896 assert_eq!(cpu.sp, 0xFD);
1897 assert!(cpu.status.contains(StatusFlags::INTERRUPT_DISABLE));
1898 }
1899
1900 #[test]
1901 fn test_cpu_reset() {
1902 let mut cpu = Cpu::new();
1903 let mut bus = TestBus::new();
1904
1905 bus.write(0xFFFC, 0x00);
1907 bus.write(0xFFFD, 0x80);
1908
1909 cpu.reset(&mut bus);
1910
1911 assert_eq!(cpu.pc, 0x8000);
1912 assert!(cpu.status.contains(StatusFlags::INTERRUPT_DISABLE));
1913 assert_eq!(cpu.cycles, 7);
1914 }
1915
1916 #[test]
1917 fn test_stack_operations() {
1918 let mut cpu = Cpu::new();
1919 let mut bus = TestBus::new();
1920
1921 cpu.sp = 0xFF;
1922
1923 cpu.push(&mut bus, 0x42);
1925 assert_eq!(cpu.sp, 0xFE);
1926 assert_eq!(bus.read(0x01FF), 0x42);
1927
1928 let value = cpu.pop(&mut bus);
1930 assert_eq!(value, 0x42);
1931 assert_eq!(cpu.sp, 0xFF);
1932
1933 cpu.push_u16(&mut bus, 0x1234);
1935 assert_eq!(cpu.sp, 0xFD);
1936 let value = cpu.pop_u16(&mut bus);
1937 assert_eq!(value, 0x1234);
1938 assert_eq!(cpu.sp, 0xFF);
1939 }
1940}