nes_core/cpu/
mod.rs

1//! A 6502 Central Processing Unit
2//!
3//! <http://wiki.nesdev.com/w/index.php/CPU>
4
5use alloc::format;
6use alloc::string::{String, ToString};
7use alloc::vec::Vec;
8use crate::{
9    apu::{Apu, Channel},
10    bus::CpuBus,
11    cart::Cart,
12    common::{Clock, ResetKind, NesRegion, Regional, Reset},
13    input::{FourPlayer, Joypad, Player, Zapper},
14    mapper::Mapper,
15    mem::{Access, Mem},
16    ppu::Ppu,
17};
18use bitflags::{bitflags, Flags};
19use instr::{
20    AddrMode::{ABS, ABX, ABY, ACC, IDX, IDY, IMM, IMP, IND, REL, ZP0, ZPX, ZPY},
21    Instr,
22    Operation::{
23        ADC, AHX, ALR, ANC, AND, ARR, ASL, AXS, BCC, BCS, BEQ, BIT, BMI, BNE, BPL, BRK, BVC, BVS,
24        CLC, CLD, CLI, CLV, CMP, CPX, CPY, DCP, DEC, DEX, DEY, EOR, IGN, INC, INX, INY, ISB, JMP,
25        JSR, LAS, LAX, LDA, LDX, LDY, LSR, NOP, ORA, PHA, PHP, PLA, PLP, RLA, ROL, ROR, RRA, RTI,
26        RTS, SAX, SBC, SEC, SED, SEI, SKB, SLO, SRE, STA, STX, STY, SXA, SYA, TAS, TAX, TAY, TSX,
27        TXA, TXS, TYA, XAA, XXX,
28    },
29};
30use serde::{Deserialize, Serialize};
31use core::fmt::{self, Write};
32use anyhow::Result;
33
34pub mod instr;
35
36bitflags! {
37    #[derive(Default, Serialize, Deserialize, Debug, Copy, Clone)]
38    #[must_use]
39    pub struct Irq: u8 {
40        const MAPPER = 1 << 1;
41        const FRAME_COUNTER = 1 << 2;
42        const DMC = 1 << 3;
43    }
44}
45
46// Status Registers
47// http://wiki.nesdev.com/w/index.php/Status_flags
48// 7654 3210
49// NVUB DIZC
50// |||| ||||
51// |||| |||+- Carry
52// |||| ||+-- Zero
53// |||| |+--- Interrupt Disable
54// |||| +---- Decimal Mode - Not used in the NES but still has to function
55// |||+------ Break - 1 when pushed to stack from PHP/BRK, 0 from IRQ/NMI
56// ||+------- Unused - always set to 1 when pushed to stack
57// |+-------- Overflow
58// +--------- Negative
59bitflags! {
60    #[derive(Default, Serialize, Deserialize, Debug, Copy, Clone)]
61    #[must_use]
62    pub struct Status: u8 {
63        const C = 1;      // Carry
64        const Z = 1 << 1; // Zero
65        const I = 1 << 2; // Disable Interrupt
66        const D = 1 << 3; // Decimal Mode
67        const B = 1 << 4; // Break
68        const U = 1 << 5; // Unused
69        const V = 1 << 6; // Overflow
70        const N = 1 << 7; // Negative
71    }
72}
73
74/// Every cycle is either a read or a write.
75#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
76enum Cycle {
77    Read,
78    Write,
79}
80
81/// The Central Processing Unit status and registers
82#[derive(Clone, Serialize, Deserialize)]
83#[must_use]
84pub struct Cpu {
85    cycle: usize,
86    // total number of cycles ran
87    region: NesRegion,
88    master_clock: u64,
89    clock_divider: u64,
90    start_clocks: u64,
91    end_clocks: u64,
92    pc: u16,
93    // program counter
94    sp: u8,
95    // stack pointer - stack is at $0100-$01FF
96    acc: u8,
97    // accumulator
98    x: u8,
99    // x register
100    y: u8,
101    // y register
102    status: Status,
103    // Status Registers
104    bus: CpuBus,
105    instr: Instr,
106    // The currently executing instruction
107    abs_addr: u16,
108    // Used memory addresses get set here
109    rel_addr: u16,
110    // Relative address for branch instructions
111    fetched_data: u8,
112    // Represents data fetched for the ALU
113    irq: Irq,
114    // Pending interrupts
115    run_irq: bool,
116    prev_run_irq: bool,
117    nmi: bool,
118    prev_nmi: bool,
119    prev_nmi_pending: bool,
120    #[serde(skip)]
121    corrupted: bool,
122    // Encountering an invalid opcode corrupts CPU processing
123    dmc_dma: bool,
124    halt: bool,
125    dummy_read: bool,
126    cycle_accurate: bool,
127    disasm: String,
128}
129
130impl Cpu {
131    // TODO 1789772.667 MHz (~559 ns/cycle) - May want to use 1786830 for a stable 60 FPS
132    // Add Emulator setting like Mesen??
133    // http://forums.nesdev.com/viewtopic.php?p=223679#p223679
134    const NTSC_MASTER_CLOCK_RATE: f32 = 21_477_272.0;
135    const NTSC_CPU_CLOCK_RATE: f32 = Self::NTSC_MASTER_CLOCK_RATE / 12.0;
136    const PAL_MASTER_CLOCK_RATE: f32 = 26_601_712.0;
137    const PAL_CPU_CLOCK_RATE: f32 = Self::PAL_MASTER_CLOCK_RATE / 16.0;
138    const DENDY_CPU_CLOCK_RATE: f32 = Self::PAL_MASTER_CLOCK_RATE / 15.0;
139
140    // Represents CPU/PPU alignment and would range from 0..=ppu_divider-1, if random alignment was emulated
141    const PPU_OFFSET: u64 = 1;
142
143    const NMI_VECTOR: u16 = 0xFFFA;
144    // NMI Vector address
145    const IRQ_VECTOR: u16 = 0xFFFE;
146    // IRQ Vector address
147    const RESET_VECTOR: u16 = 0xFFFC;
148    // Vector address at reset
149    const POWER_ON_STATUS: Status = Status::U.union(Status::I);
150    const POWER_ON_SP: u8 = 0xFD;
151    const SP_BASE: u16 = 0x0100; // Stack-pointer starting address
152
153    pub fn new(bus: CpuBus) -> Self {
154        let mut cpu = Self {
155            cycle: 0,
156            region: NesRegion::default(),
157            master_clock: 0,
158            clock_divider: 0,
159            start_clocks: 0,
160            end_clocks: 0,
161            pc: 0x0000,
162            sp: 0x00,
163            acc: 0x00,
164            x: 0x00,
165            y: 0x00,
166            status: Self::POWER_ON_STATUS,
167            bus,
168            instr: Cpu::INSTRUCTIONS[0x00],
169            abs_addr: 0x0000,
170            rel_addr: 0x0000,
171            fetched_data: 0x00,
172            irq: Irq::empty(),
173            run_irq: false,
174            prev_run_irq: false,
175            nmi: false,
176            prev_nmi: false,
177            prev_nmi_pending: false,
178            corrupted: false,
179            dmc_dma: false,
180            halt: false,
181            dummy_read: false,
182            cycle_accurate: true,
183            disasm: String::with_capacity(100),
184        };
185        cpu.set_region(cpu.region);
186        cpu
187    }
188
189    #[inline]
190    #[must_use]
191    pub const fn region_clock_rate(region: NesRegion) -> f32 {
192        match region {
193            NesRegion::Ntsc => Self::NTSC_CPU_CLOCK_RATE,
194            NesRegion::Pal => Self::PAL_CPU_CLOCK_RATE,
195            NesRegion::Dendy => Self::DENDY_CPU_CLOCK_RATE,
196        }
197    }
198
199    #[inline]
200    #[must_use]
201    pub const fn clock_rate(&self) -> f32 {
202        Self::region_clock_rate(self.region)
203    }
204
205    #[inline]
206    #[must_use]
207    pub const fn cycle(&self) -> usize {
208        self.cycle
209    }
210
211    #[inline]
212    #[must_use]
213    pub const fn pc(&self) -> u16 {
214        self.pc
215    }
216
217    #[inline]
218    #[must_use]
219    pub const fn sp(&self) -> u8 {
220        self.sp
221    }
222
223    #[inline]
224    #[must_use]
225    pub const fn a(&self) -> u8 {
226        self.acc
227    }
228
229    #[inline]
230    #[must_use]
231    pub const fn x(&self) -> u8 {
232        self.x
233    }
234
235    #[inline]
236    #[must_use]
237    pub const fn y(&self) -> u8 {
238        self.y
239    }
240
241    #[inline]
242    pub const fn status(&self) -> Status {
243        self.status
244    }
245
246    #[inline]
247    #[must_use]
248    pub const fn corrupted(&self) -> bool {
249        self.corrupted
250    }
251
252    #[inline]
253    #[must_use]
254    pub fn disasm(&self) -> &str {
255        &self.disasm
256    }
257
258    #[inline]
259    pub const fn ppu(&self) -> &Ppu {
260        self.bus.ppu()
261    }
262
263    #[inline]
264    pub fn ppu_mut(&mut self) -> &mut Ppu {
265        self.bus.ppu_mut()
266    }
267
268    #[inline]
269    pub const fn apu(&self) -> &Apu {
270        self.bus.apu()
271    }
272
273    #[inline]
274    pub fn apu_mut(&mut self) -> &mut Apu {
275        self.bus.apu_mut()
276    }
277
278    #[inline]
279    pub const fn mapper(&self) -> &Mapper {
280        self.bus.mapper()
281    }
282
283    #[inline]
284    pub fn mapper_mut(&mut self) -> &mut Mapper {
285        self.bus.mapper_mut()
286    }
287
288    #[inline]
289    pub const fn joypad(&self, slot: Player) -> &Joypad {
290        self.bus.joypad(slot)
291    }
292
293    #[inline]
294    pub fn joypad_mut(&mut self, slot: Player) -> &mut Joypad {
295        self.bus.joypad_mut(slot)
296    }
297
298    #[inline]
299    pub fn connect_zapper(&mut self, enabled: bool) {
300        self.bus.connect_zapper(enabled);
301    }
302
303    #[inline]
304    pub const fn zapper(&self) -> &Zapper {
305        self.bus.zapper()
306    }
307
308    #[inline]
309    pub fn zapper_mut(&mut self) -> &mut Zapper {
310        self.bus.zapper_mut()
311    }
312
313    #[inline]
314    pub fn load_cart(&mut self, cart: Cart) {
315        self.bus.load_cart(cart);
316    }
317
318    #[inline]
319    #[must_use]
320    pub const fn cart_battery_backed(&self) -> bool {
321        self.bus.cart_battery_backed()
322    }
323
324    #[inline]
325    #[must_use]
326    pub fn sram(&self) -> &[u8] {
327        self.bus.sram()
328    }
329
330    #[inline]
331    pub fn load_sram(&mut self, sram: Vec<u8>) {
332        self.bus.load_sram(sram);
333    }
334
335    #[inline]
336    #[must_use]
337    pub fn wram(&self) -> &[u8] {
338        self.bus.wram()
339    }
340
341    /// Add a Game Genie code to override memory reads/writes.
342    ///
343    /// # Errors
344    ///
345    /// Errors if genie code is invalid.
346    #[inline]
347    pub fn add_genie_code(&mut self, genie_code: String) -> Result<()> {
348        self.bus.add_genie_code(genie_code)
349    }
350
351    #[inline]
352    pub fn remove_genie_code(&mut self, genie_code: &str) {
353        self.bus.remove_genie_code(genie_code);
354    }
355
356    #[inline]
357    #[must_use]
358    pub const fn ppu_cycle(&self) -> u32 {
359        self.bus.ppu_cycle()
360    }
361
362    #[inline]
363    #[must_use]
364    pub const fn ppu_scanline(&self) -> u32 {
365        self.bus.ppu_scanline()
366    }
367
368    #[inline]
369    #[must_use]
370    pub fn frame_buffer(&self) -> &[u16] {
371        self.bus.frame_buffer()
372    }
373
374    #[inline]
375    #[must_use]
376    pub const fn frame_number(&self) -> u32 {
377        self.bus.frame_number()
378    }
379
380    #[inline]
381    #[must_use]
382    pub const fn audio_channel_enabled(&self, channel: Channel) -> bool {
383        self.bus.audio_channel_enabled(channel)
384    }
385
386    #[inline]
387    pub fn toggle_audio_channel(&mut self, channel: Channel) {
388        self.bus.toggle_audio_channel(channel);
389    }
390
391    #[inline]
392    #[must_use]
393    pub fn audio_samples(&self) -> &[f32] {
394        self.bus.audio_samples()
395    }
396
397    #[inline]
398    pub fn clear_audio_samples(&mut self) {
399        self.bus.clear_audio_samples();
400    }
401
402    #[inline]
403    pub const fn four_player(&self) -> FourPlayer {
404        self.bus.four_player()
405    }
406
407    #[inline]
408    pub fn set_four_player(&mut self, four_player: FourPlayer) {
409        self.bus.set_four_player(four_player);
410    }
411
412    #[inline]
413    pub fn set_cycle_accurate(&mut self, enabled: bool) {
414        self.cycle_accurate = enabled;
415    }
416
417    // <http://wiki.nesdev.com/w/index.php/IRQ>
418    //  #  address R/W description
419    // --- ------- --- -----------------------------------------------
420    //  1    PC     R  fetch PCH
421    //  2    PC     R  fetch PCL
422    //  3  $0100,S  W  push PCH to stack, decrement S
423    //  4  $0100,S  W  push PCL to stack, decrement S
424    //  5  $0100,S  W  push P to stack, decrement S
425    //  6    PC     R  fetch low byte of interrupt vector
426    //  7    PC     R  fetch high byte of interrupt vector
427    pub fn irq(&mut self) {
428        self.read(self.pc, Access::Dummy);
429        self.read(self.pc, Access::Dummy);
430        self.push_u16(self.pc);
431
432        // Pushing status to the stack has to happen after checking NMI since it can hijack the BRK
433        // IRQ when it occurs between cycles 4 and 5.
434        // https://www.nesdev.org/wiki/CPU_interrupts#Interrupt_hijacking
435        //
436        // Set U and !B during push
437        let status = ((self.status | Status::U) & !Status::B).bits();
438
439        if self.nmi {
440            self.nmi = false;
441            self.push(status);
442            self.status.set(Status::I, true);
443
444            self.pc = self.read_u16(Self::NMI_VECTOR);
445            log::trace!("NMI: {}", self.cycle);
446        } else {
447            self.push(status);
448            self.status.set(Status::I, true);
449
450            self.pc = self.read_u16(Self::IRQ_VECTOR);
451            log::trace!("IRQ: {}", self.cycle);
452        }
453    }
454
455    fn handle_interrupts(&mut self) {
456        // https://www.nesdev.org/wiki/CPU_interrupts
457        //
458        // The internal signal goes high during φ1 of the cycle that follows the one where
459        // the edge is detected, and stays high until the NMI has been handled. NMI is handled only
460        // when `prev_nmi` is true.
461        self.prev_nmi = self.nmi;
462
463        // This edge detector polls the status of the NMI line during φ2 of each CPU cycle (i.e.,
464        // during the second half of each cycle, hence here in `end_cycle`) and raises an internal
465        // signal if the input goes from being high during one cycle to being low during the
466        // next.
467        let nmi_pending = self.bus.nmi_pending();
468        if !self.prev_nmi_pending && nmi_pending {
469            self.nmi = true;
470            log::trace!("NMI Edge Detected: {}", self.cycle);
471        }
472        self.prev_nmi_pending = nmi_pending;
473
474        self.irq = self.bus.irqs_pending();
475
476        // The IRQ status at the end of the second-to-last cycle is what matters,
477        // so keep the second-to-last status.
478        self.prev_run_irq = self.run_irq;
479        self.run_irq = !self.irq.is_empty() && !self.status.intersects(Status::I);
480        if self.run_irq {
481            log::trace!("IRQ Level Detected: {}: {:?}", self.cycle, self.irq);
482        }
483
484        if self.bus.dmc_dma() {
485            self.dmc_dma = true;
486            self.halt = true;
487            self.dummy_read = true;
488        }
489    }
490
491    fn start_cycle(&mut self, cycle: Cycle) {
492        self.master_clock += if cycle == Cycle::Read {
493            self.start_clocks - 1
494        } else {
495            self.start_clocks + 1
496        };
497        self.cycle = self.cycle.wrapping_add(1);
498
499        if self.cycle_accurate {
500            self.bus.clock_to(self.master_clock - Self::PPU_OFFSET);
501            self.bus.clock();
502        }
503    }
504
505    fn end_cycle(&mut self, cycle: Cycle) {
506        self.master_clock += if cycle == Cycle::Read {
507            self.end_clocks + 1
508        } else {
509            self.end_clocks - 1
510        };
511
512        if self.cycle_accurate {
513            self.bus.clock_to(self.master_clock - Self::PPU_OFFSET);
514        }
515
516        self.handle_interrupts();
517    }
518
519    fn process_dma_cycle(&mut self) {
520        // OAM DMA cycles count as halt/dummy reads for DMC DMA when both run at the same time
521        if self.halt {
522            self.halt = false;
523        } else if self.dummy_read {
524            self.dummy_read = false;
525        }
526        self.start_cycle(Cycle::Read);
527    }
528
529    fn handle_dma(&mut self, addr: u16) {
530        self.start_cycle(Cycle::Read);
531        self.bus.read(addr, Access::Dummy);
532        self.end_cycle(Cycle::Read);
533        self.halt = false;
534
535        let skip_dummy_reads = addr == 0x4016 || addr == 0x4017;
536
537        let oam_base_addr = self.bus.oam_dma_addr();
538        let mut oam_offset = 0;
539        let mut oam_dma_count = 0;
540        let mut read_val = 0;
541
542        while self.bus.oam_dma() || self.dmc_dma {
543            if self.cycle & 0x01 == 0x00 {
544                if self.dmc_dma && !self.halt && !self.dummy_read {
545                    // DMC DMA ready to read a byte (halt and dummy read done before)
546                    self.process_dma_cycle();
547                    read_val = self.bus.read(self.bus.dmc_dma_addr(), Access::Dummy);
548                    self.end_cycle(Cycle::Read);
549                    self.bus.load_dmc_buffer(read_val);
550                    self.dmc_dma = false;
551                } else if self.bus.oam_dma() {
552                    // DMC DMA not running or ready, run OAM DMA
553                    self.process_dma_cycle();
554                    read_val = self.bus.read(oam_base_addr + oam_offset, Access::Dummy);
555                    self.end_cycle(Cycle::Read);
556                    oam_offset += 1;
557                    oam_dma_count += 1;
558                } else {
559                    // DMC DMA running, but not ready yet (needs to halt, or dummy read) and OAM
560                    // DMA isn't running
561                    debug_assert!(self.halt || self.dummy_read);
562                    self.process_dma_cycle();
563                    if !skip_dummy_reads {
564                        self.bus.read(addr, Access::Dummy); // throw away
565                    }
566                    self.end_cycle(Cycle::Read);
567                }
568            } else if self.bus.oam_dma() && oam_dma_count & 0x01 == 0x01 {
569                // OAM DMA write cycle, done on odd cycles after a read on even cycles
570                self.process_dma_cycle();
571                self.bus.write(0x2004, read_val, Access::Dummy);
572                self.end_cycle(Cycle::Read);
573                oam_dma_count += 1;
574                if oam_dma_count == 0x200 {
575                    self.bus.oam_dma_finish();
576                }
577            } else {
578                // Align to read cycle before starting OAM DMA (or align to perform DMC read)
579                self.process_dma_cycle();
580                if !skip_dummy_reads {
581                    self.bus.read(addr, Access::Dummy); // throw away
582                }
583                self.end_cycle(Cycle::Read);
584            }
585        }
586    }
587
588    // Status Register functions
589
590    // Convenience method to set both Z and N
591    #[inline]
592    fn set_zn_status(&mut self, val: u8) {
593        self.status.set(Status::Z, val == 0x00);
594        self.status.set(Status::N, val & 0x80 == 0x80);
595    }
596
597    #[inline]
598    const fn status_bit(&self, reg: Status) -> u8 {
599        self.status.intersection(reg).bits()
600    }
601
602    // Stack Functions
603
604    // Push a byte to the stack
605    #[inline]
606    fn push(&mut self, val: u8) {
607        self.write(Self::SP_BASE | u16::from(self.sp), val, Access::Write);
608        self.sp = self.sp.wrapping_sub(1);
609    }
610
611    // Pull a byte from the stack
612    #[must_use]
613    #[inline]
614    fn pop(&mut self) -> u8 {
615        self.sp = self.sp.wrapping_add(1);
616        self.read(Self::SP_BASE | u16::from(self.sp), Access::Read)
617    }
618
619    // Peek byte at the top of the stack
620    #[must_use]
621    #[inline]
622    pub fn peek_stack(&self) -> u8 {
623        self.peek(
624            Self::SP_BASE | u16::from(self.sp.wrapping_add(1)),
625            Access::Dummy,
626        )
627    }
628
629    // Peek at the top of the stack
630    #[must_use]
631    #[inline]
632    pub fn peek_stack_u16(&self) -> u16 {
633        let lo = self.peek(Self::SP_BASE | u16::from(self.sp), Access::Dummy);
634        let hi = self.peek(
635            Self::SP_BASE | u16::from(self.sp.wrapping_add(1)),
636            Access::Dummy,
637        );
638        u16::from_le_bytes([lo, hi])
639    }
640
641    // Push a word (two bytes) to the stack
642    #[inline]
643    fn push_u16(&mut self, val: u16) {
644        let [lo, hi] = val.to_le_bytes();
645        self.push(hi);
646        self.push(lo);
647    }
648
649    // Pull a word (two bytes) from the stack
650    #[inline]
651    fn pop_u16(&mut self) -> u16 {
652        let lo = self.pop();
653        let hi = self.pop();
654        u16::from_le_bytes([lo, hi])
655    }
656
657    // Memory accesses
658
659    // Source the data used by an instruction. Some instructions don't fetch data as the source
660    // is implied by the instruction such as INX which increments the X register.
661    fn fetch_data(&mut self) {
662        let mode = self.instr.addr_mode();
663        self.fetched_data = match mode {
664            IMP | ACC => self.acc,
665            ABX | ABY | IDY => {
666                // Read instructions may have crossed a page boundary and need to be re-read
667                match self.instr.op() {
668                    LDA | LDX | LDY | EOR | AND | ORA | ADC | SBC | CMP | BIT | LAX | NOP | IGN
669                    | LAS => {
670                        let reg = match mode {
671                            ABX => self.x,
672                            ABY | IDY => self.y,
673                            _ => unreachable!("not possible"),
674                        };
675                        // Read if we crossed, otherwise use what was already set in cycle 4 from
676                        // addressing mode
677                        //
678                        // ABX/ABY/IDY all add `reg` to `abs_addr`, so this checks if it wrapped
679                        // around to 0.
680                        if (self.abs_addr & 0x00FF) < u16::from(reg) {
681                            self.read(self.abs_addr, Access::Read)
682                        } else {
683                            self.fetched_data
684                        }
685                    }
686                    _ => self.read(self.abs_addr, Access::Read), // Cycle 2/4/5 read
687                }
688            }
689            _ => self.read(self.abs_addr, Access::Read), // Cycle 2/4/5 read
690        };
691    }
692
693    // Writes data back to where fetched_data was sourced from. Either accumulator or memory
694    // specified in abs_addr.
695    #[inline]
696    fn write_fetched(&mut self, val: u8) {
697        match self.instr.addr_mode() {
698            IMP | ACC => self.acc = val,
699            IMM => (), // noop
700            _ => self.write(self.abs_addr, val, Access::Write),
701        }
702    }
703
704    // Reads an instruction byte and increments PC by 1.
705    #[must_use]
706    #[inline]
707    fn read_instr(&mut self) -> u8 {
708        let val = self.read(self.pc, Access::Read);
709        self.pc = self.pc.wrapping_add(1);
710        val
711    }
712
713    // Reads an instruction 16-bit word and increments PC by 2.
714    #[must_use]
715    #[inline]
716    fn read_instr_u16(&mut self) -> u16 {
717        let lo = self.read_instr();
718        let hi = self.read_instr();
719        u16::from_le_bytes([lo, hi])
720    }
721
722    // Read a 16-bit word.
723    #[must_use]
724    #[inline]
725    pub fn read_u16(&mut self, addr: u16) -> u16 {
726        let lo = self.read(addr, Access::Read);
727        let hi = self.read(addr.wrapping_add(1), Access::Read);
728        u16::from_le_bytes([lo, hi])
729    }
730
731    // Peek a 16-bit word without side effects.
732    #[must_use]
733    #[inline]
734    pub fn peek_u16(&self, addr: u16) -> u16 {
735        let lo = self.peek(addr, Access::Dummy);
736        let hi = self.peek(addr.wrapping_add(1), Access::Dummy);
737        u16::from_le_bytes([lo, hi])
738    }
739
740    // Like read_word, but for Zero Page which means it'll wrap around at 0xFF
741    #[must_use]
742    #[inline]
743    fn read_zp_u16(&mut self, addr: u8) -> u16 {
744        let lo = self.read(addr.into(), Access::Read);
745        let hi = self.read(addr.wrapping_add(1).into(), Access::Read);
746        u16::from_le_bytes([lo, hi])
747    }
748
749    // Like peek_word, but for Zero Page which means it'll wrap around at 0xFF
750    #[must_use]
751    #[inline]
752    fn peek_zp_u16(&self, addr: u8) -> u16 {
753        let lo = self.peek(addr.into(), Access::Dummy);
754        let hi = self.peek(addr.wrapping_add(1).into(), Access::Dummy);
755        u16::from_le_bytes([lo, hi])
756    }
757
758    pub fn disassemble(&mut self, pc: &mut u16) {
759        let opcode = self.peek(*pc, Access::Dummy);
760        let instr = Cpu::INSTRUCTIONS[opcode as usize];
761        let mut bytes = Vec::with_capacity(3);
762        self.disasm.clear();
763        let _ = write!(self.disasm, "{pc:04X} ");
764        bytes.push(opcode);
765        let mut addr = pc.wrapping_add(1);
766        let mode = match instr.addr_mode() {
767            IMM => {
768                bytes.push(self.peek(addr, Access::Dummy));
769                addr = addr.wrapping_add(1);
770                format!(" #${:02X}", bytes[1])
771            }
772            ZP0 => {
773                bytes.push(self.peek(addr, Access::Dummy));
774                addr = addr.wrapping_add(1);
775                let val = self.peek(bytes[1].into(), Access::Dummy);
776                format!(" ${:02X} = #${val:02X}", bytes[1])
777            }
778            ZPX => {
779                bytes.push(self.peek(addr, Access::Dummy));
780                addr = addr.wrapping_add(1);
781                let x_offset = bytes[1].wrapping_add(self.x);
782                let val = self.peek(x_offset.into(), Access::Dummy);
783                format!(" ${:02X},X @ ${x_offset:02X} = #${val:02X}", bytes[1])
784            }
785            ZPY => {
786                bytes.push(self.peek(addr, Access::Dummy));
787                addr = addr.wrapping_add(1);
788                let y_offset = bytes[1].wrapping_add(self.y);
789                let val = self.peek(y_offset.into(), Access::Dummy);
790                format!(" ${:02X},Y @ ${y_offset:02X} = #${val:02X}", bytes[1])
791            }
792            ABS => {
793                bytes.push(self.peek(addr, Access::Dummy));
794                bytes.push(self.peek(addr.wrapping_add(1), Access::Dummy));
795                let abs_addr = self.peek_u16(addr);
796                addr = addr.wrapping_add(2);
797                if instr.op() == JMP || instr.op() == JSR {
798                    format!(" ${abs_addr:04X}")
799                } else {
800                    let val = self.peek(abs_addr, Access::Dummy);
801                    format!(" ${abs_addr:04X} = #${val:02X}")
802                }
803            }
804            ABX => {
805                bytes.push(self.peek(addr, Access::Dummy));
806                bytes.push(self.peek(addr.wrapping_add(1), Access::Dummy));
807                let abs_addr = self.peek_u16(addr);
808                addr = addr.wrapping_add(2);
809                let x_offset = abs_addr.wrapping_add(self.x.into());
810                let val = self.peek(x_offset, Access::Dummy);
811                format!(" ${abs_addr:04X},X @ ${x_offset:04X} = #${val:02X}")
812            }
813            ABY => {
814                bytes.push(self.peek(addr, Access::Dummy));
815                bytes.push(self.peek(addr.wrapping_add(1), Access::Dummy));
816                let abs_addr = self.peek_u16(addr);
817                addr = addr.wrapping_add(2);
818                let y_offset = abs_addr.wrapping_add(self.y.into());
819                let val = self.peek(y_offset, Access::Dummy);
820                format!(" ${abs_addr:04X},Y @ ${y_offset:04X} = #${val:02X}")
821            }
822            IND => {
823                bytes.push(self.peek(addr, Access::Dummy));
824                bytes.push(self.peek(addr.wrapping_add(1), Access::Dummy));
825                let abs_addr = self.peek_u16(addr);
826                addr = addr.wrapping_add(2);
827                let lo = self.peek(abs_addr, Access::Dummy);
828                let hi = if abs_addr & 0x00FF == 0x00FF {
829                    self.peek(abs_addr & 0xFF00, Access::Dummy)
830                } else {
831                    self.peek(abs_addr + 1, Access::Dummy)
832                };
833                let val = u16::from_le_bytes([lo, hi]);
834                format!(" (${abs_addr:04X}) = ${val:04X}")
835            }
836            IDX => {
837                bytes.push(self.peek(addr, Access::Dummy));
838                addr = addr.wrapping_add(1);
839                let x_offset = bytes[1].wrapping_add(self.x);
840                let abs_addr = self.peek_zp_u16(x_offset);
841                let val = self.peek(abs_addr, Access::Dummy);
842                format!(" (${:02X},X) @ ${abs_addr:04X} = #${val:02X}", bytes[1])
843            }
844            IDY => {
845                bytes.push(self.peek(addr, Access::Dummy));
846                addr = addr.wrapping_add(1);
847                let abs_addr = self.peek_zp_u16(bytes[1]);
848                let y_offset = abs_addr.wrapping_add(self.y.into());
849                let val = self.peek(y_offset, Access::Dummy);
850                format!(" (${:02X}),Y @ ${y_offset:04X} = #${val:02X}", bytes[1])
851            }
852            REL => {
853                bytes.push(self.peek(addr, Access::Dummy));
854                let mut rel_addr: u16 = self.peek(addr, Access::Dummy).into();
855                addr = addr.wrapping_add(1);
856                if rel_addr & 0x80 == 0x80 {
857                    // If address is negative, extend sign to 16-bits
858                    rel_addr |= 0xFF00;
859                }
860                format!(" ${:04X}", addr.wrapping_add(rel_addr))
861            }
862            ACC | IMP => "".to_string(),
863        };
864        *pc = addr;
865        for byte in &bytes {
866            let _ = write!(self.disasm, "{byte:02X} ");
867        }
868        for _ in 0..(3 - bytes.len()) {
869            self.disasm.push_str("   ");
870        }
871        let _ = write!(self.disasm, "{instr:?}{mode}");
872    }
873
874    // Print the current instruction and status
875    pub fn trace_instr(&mut self) {
876        let mut pc = self.pc;
877        self.disassemble(&mut pc);
878
879        let status_str = |status: Status, set: char, clear: char| {
880            if self.status.contains(status) {
881                set
882            } else {
883                clear
884            }
885        };
886
887        log::trace!(
888            "{:<50} A:{:02X} X:{:02X} Y:{:02X} P:{}{}--{}{}{}{} SP:{:02X} PPU:{:3},{:3} CYC:{}",
889            self.disasm,
890            self.acc,
891            self.x,
892            self.y,
893            status_str(Status::N, 'N', 'n'),
894            status_str(Status::V, 'V', 'v'),
895            status_str(Status::D, 'd', 'd'),
896            status_str(Status::I, 'I', 'i'),
897            status_str(Status::Z, 'Z', 'z'),
898            status_str(Status::C, 'C', 'c'),
899            self.sp,
900            self.bus.ppu_cycle(),
901            self.bus.ppu_scanline(),
902            self.cycle,
903        );
904    }
905
906    /// Utilities
907    #[must_use]
908    #[inline]
909    const fn pages_differ(addr1: u16, addr2: u16) -> bool {
910        (addr1 & 0xFF00) != (addr2 & 0xFF00)
911    }
912}
913
914impl Cpu {
915    pub fn clock_inspect<F>(&mut self, mut inspect: F) -> usize
916        where
917            F: FnMut(&mut Cpu),
918    {
919        let start_cycle = self.cycle;
920
921        if log::log_enabled!(log::Level::Trace) {
922            self.trace_instr();
923        }
924        inspect(self);
925
926        let opcode = self.read_instr(); // Cycle 1 of instruction
927        self.instr = Cpu::INSTRUCTIONS[opcode as usize];
928
929        match self.instr.addr_mode() {
930            IMM => self.imm(),
931            ZP0 => self.zp0(),
932            ZPX => self.zpx(),
933            ZPY => self.zpy(),
934            ABS => self.abs(),
935            ABX => self.abx(),
936            ABY => self.aby(),
937            IND => self.ind(),
938            IDX => self.idx(),
939            IDY => self.idy(),
940            REL => self.rel(),
941            ACC => self.acc(),
942            IMP => self.imp(),
943        };
944
945        match self.instr.op() {
946            ADC => self.adc(), // ADd with Carry M with A
947            AND => self.and(), // AND M with A
948            ASL => self.asl(), // Arithmatic Shift Left M or A
949            BCC => self.bcc(), // Branch on Carry Clear
950            BCS => self.bcs(), // Branch if Carry Set
951            BEQ => self.beq(), // Branch if EQual to zero
952            BIT => self.bit(), // Test BITs of M with A (Affects N, V and Z)
953            BMI => self.bmi(), // Branch on MInus (negative)
954            BNE => self.bne(), // Branch if Not Equal to zero
955            BPL => self.bpl(), // Branch on PLus (positive)
956            BRK => self.brk(), // BReaK (forced interrupt)
957            BVC => self.bvc(), // Branch if no oVerflow Set
958            BVS => self.bvs(), // Branch on oVerflow Set
959            CLC => self.clc(), // CLear Carry flag
960            CLD => self.cld(), // CLear Decimal mode
961            CLI => self.cli(), // CLear Interrupt disable
962            CLV => self.clv(), // CLear oVerflow flag
963            CMP => self.cmp(), // CoMPare
964            CPX => self.cpx(), // ComPare with X
965            CPY => self.cpy(), // ComPare with Y
966            DEC => self.dec(), // DECrement M or A
967            DEX => self.dex(), // DEcrement X
968            DEY => self.dey(), // DEcrement Y
969            EOR => self.eor(), // Exclusive-OR M with A
970            INC => self.inc(), // INCrement M or A
971            INX => self.inx(), // INcrement X
972            INY => self.iny(), // INcrement Y
973            JMP => self.jmp(), // JuMP - safe to unwrap because JMP is Absolute
974            JSR => self.jsr(), // Jump and Save Return addr - safe to unwrap because JSR is Absolute
975            LDA => self.lda(), // LoaD A with M
976            LDX => self.ldx(), // LoaD X with M
977            LDY => self.ldy(), // LoaD Y with M
978            LSR => self.lsr(), // Logical Shift Right M or A
979            NOP => self.nop(), // NO oPeration
980            SKB => self.skb(), // Like NOP, but issues a dummy read
981            IGN => self.ign(), // Like NOP, but issues a dummy read
982            ORA => self.ora(), // OR with A
983            PHA => self.pha(), // PusH A to the stack
984            PHP => self.php(), // PusH Processor status to the stack
985            PLA => self.pla(), // PulL A from the stack
986            PLP => self.plp(), // PulL Processor status from the stack
987            ROL => self.rol(), // ROtate Left M or A
988            ROR => self.ror(), // ROtate Right M or A
989            RTI => self.rti(), // ReTurn from Interrupt
990            RTS => self.rts(), // ReTurn from Subroutine
991            SBC => self.sbc(), // Subtract M from A with carry
992            SEC => self.sec(), // SEt Carry flag
993            SED => self.sed(), // SEt Decimal mode
994            SEI => self.sei(), // SEt Interrupt disable
995            STA => self.sta(), // STore A into M
996            STX => self.stx(), // STore X into M
997            STY => self.sty(), // STore Y into M
998            TAX => self.tax(), // Transfer A to X
999            TAY => self.tay(), // Transfer A to Y
1000            TSX => self.tsx(), // Transfer SP to X
1001            TXA => self.txa(), // TRansfer X to A
1002            TXS => self.txs(), // Transfer X to SP
1003            TYA => self.tya(), // Transfer Y to A
1004            ISB => self.isb(), // INC & SBC
1005            DCP => self.dcp(), // DEC & CMP
1006            AXS => self.axs(), // (A & X) - val into X
1007            LAS => self.las(), // LDA & TSX
1008            LAX => self.lax(), // LDA & TAX
1009            AHX => self.ahx(), // Store A & X & H in M
1010            SAX => self.sax(), // Sotre A & X in M
1011            XAA => self.xaa(), // TXA & AND
1012            SXA => self.sxa(), // Store X & H in M
1013            RRA => self.rra(), // ROR & ADC
1014            TAS => self.tas(), // STA & TXS
1015            SYA => self.sya(), // Store Y & H in M
1016            ARR => self.arr(), // AND #imm & ROR
1017            SRE => self.sre(), // LSR & EOR
1018            ALR => self.alr(), // AND #imm & LSR
1019            RLA => self.rla(), // ROL & AND
1020            ANC => self.anc(), // AND #imm
1021            SLO => self.slo(), // ASL & ORA
1022            XXX => self.xxx(), // Unimplemented opcode
1023        }
1024
1025        if self.prev_run_irq || self.prev_nmi {
1026            self.irq();
1027        }
1028
1029        if !self.cycle_accurate {
1030            self.bus.clock_to(self.master_clock - Self::PPU_OFFSET);
1031            let cycles = self.cycle - start_cycle;
1032            for _ in 0..cycles {
1033                self.bus.clock();
1034            }
1035            self.handle_interrupts();
1036        }
1037
1038        self.cycle - start_cycle
1039    }
1040}
1041
1042impl Clock for Cpu {
1043    /// Runs the CPU one instruction
1044    fn clock(&mut self) -> usize {
1045        self.clock_inspect(|_| {})
1046    }
1047}
1048
1049impl Mem for Cpu {
1050    fn read(&mut self, addr: u16, access: Access) -> u8 {
1051        if self.halt || self.bus.oam_dma() {
1052            self.handle_dma(addr);
1053        }
1054
1055        self.start_cycle(Cycle::Read);
1056        let val = self.bus.read(addr, access);
1057        self.end_cycle(Cycle::Read);
1058        val
1059    }
1060
1061    fn peek(&self, addr: u16, access: Access) -> u8 {
1062        self.bus.peek(addr, access)
1063    }
1064
1065    fn write(&mut self, addr: u16, val: u8, access: Access) {
1066        self.start_cycle(Cycle::Write);
1067        self.bus.write(addr, val, access);
1068        self.end_cycle(Cycle::Write);
1069    }
1070}
1071
1072impl Regional for Cpu {
1073    #[inline]
1074    fn region(&self) -> NesRegion {
1075        self.region
1076    }
1077
1078    fn set_region(&mut self, region: NesRegion) {
1079        let (clock_divider, start_clocks, end_clocks) = match region {
1080            NesRegion::Ntsc => (12, 6, 6),
1081            NesRegion::Pal => (16, 8, 8),
1082            NesRegion::Dendy => (15, 7, 8),
1083        };
1084        self.region = region;
1085        self.clock_divider = clock_divider;
1086        self.start_clocks = start_clocks;
1087        self.end_clocks = end_clocks;
1088        self.bus.set_region(region);
1089    }
1090}
1091
1092impl Reset for Cpu {
1093    /// Resets the CPU
1094    ///
1095    /// Updates the PC, SP, and Status values to defined constants.
1096    ///
1097    /// These operations take the CPU 7 cycles.
1098    fn reset(&mut self, kind: ResetKind) {
1099        log::trace!("{:?} RESET", kind);
1100
1101        match kind {
1102            ResetKind::Soft => {
1103                self.status.set(Status::I, true);
1104                // Reset pushes to the stack similar to IRQ, but since the read bit is set, nothing is
1105                // written except the SP being decremented
1106                self.sp = self.sp.wrapping_sub(0x03);
1107            }
1108            ResetKind::Hard => {
1109                self.acc = 0x00;
1110                self.x = 0x00;
1111                self.y = 0x00;
1112                self.status = Self::POWER_ON_STATUS;
1113                self.sp = Self::POWER_ON_SP;
1114            }
1115        }
1116
1117        self.bus.reset(kind);
1118        self.cycle = 0;
1119        self.master_clock = 0;
1120        self.irq = Irq::empty();
1121        self.run_irq = false;
1122        self.prev_run_irq = false;
1123        self.nmi = false;
1124        self.prev_nmi = false;
1125        self.prev_nmi_pending = false;
1126        self.corrupted = false;
1127        self.halt = false;
1128        self.dummy_read = false;
1129
1130        // Read directly from bus so as to not clock other components during reset
1131        let lo = self.bus.read(Self::RESET_VECTOR, Access::Read);
1132        let hi = self.bus.read(Self::RESET_VECTOR + 1, Access::Read);
1133        self.pc = u16::from_le_bytes([lo, hi]);
1134
1135        for _ in 0..7 {
1136            self.start_cycle(Cycle::Read);
1137            self.end_cycle(Cycle::Read);
1138        }
1139    }
1140}
1141
1142impl fmt::Debug for Cpu {
1143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> {
1144        f.debug_struct("Cpu")
1145            .field("cycle", &self.cycle)
1146            .field("pc", &format_args!("${:04X}", self.pc))
1147            .field("sp", &format_args!("${:02X}", self.sp))
1148            .field("acc", &format_args!("${:02X}", self.acc))
1149            .field("x", &format_args!("${:02X}", self.x))
1150            .field("y", &format_args!("${:02X}", self.y))
1151            .field("status", &self.status)
1152            .field("bus", &self.bus)
1153            .field("instr", &self.instr)
1154            .field("abs_addr", &format_args!("${:04X}", self.abs_addr))
1155            .field("rel_addr", &format_args!("${:04X}", self.rel_addr))
1156            .field("fetched_data", &format_args!("${:02X}", self.fetched_data))
1157            .field("irq", &self.irq)
1158            .field("nmi", &self.nmi)
1159            .field("prev_nmi", &self.prev_nmi)
1160            .field("prev_nmi_pending", &self.prev_nmi_pending)
1161            .field("corrupted", &self.corrupted)
1162            .field("run_irq", &self.run_irq)
1163            .field("last_run_irq", &self.prev_run_irq)
1164            .field("halt", &self.halt)
1165            .field("dummy_read", &self.dummy_read)
1166            .finish()
1167    }
1168}
1169
1170#[cfg(test)]
1171mod tests {
1172    use crate::common::ResetKind;
1173
1174    #[test]
1175    fn cycle_timing() {
1176        use super::*;
1177        let mut cpu = Cpu::new(CpuBus::default());
1178        let cart = Cart::empty();
1179        cpu.load_cart(cart);
1180        cpu.reset(ResetKind::Hard);
1181        cpu.clock();
1182
1183        assert_eq!(cpu.cycle, 14, "cpu after power + one clock");
1184
1185        for instr in Cpu::INSTRUCTIONS.iter() {
1186            let extra_cycle = match instr.op() {
1187                BCC | BNE | BPL | BVC => 1,
1188                _ => 0,
1189            };
1190            // Ignore invalid opcodes
1191            if instr.op() == XXX {
1192                continue;
1193            }
1194            cpu.reset(ResetKind::Hard);
1195            cpu.bus.write(0x0000, instr.opcode(), Access::Write);
1196            cpu.clock();
1197            let cpu_cyc = 7 + instr.cycles() + extra_cycle;
1198            assert_eq!(
1199                cpu.cycle,
1200                cpu_cyc,
1201                "cpu ${:02X} {:?} #{:?}",
1202                instr.opcode(),
1203                instr.op(),
1204                instr.addr_mode()
1205            );
1206        }
1207    }
1208}