Cpu

Struct Cpu 

Source
pub struct Cpu {
    pub a: u8,
    pub x: u8,
    pub y: u8,
    pub pc: u16,
    pub sp: u8,
    pub status: StatusFlags,
    pub cycles: u64,
    pub stall: u8,
    pub jammed: bool,
    /* private fields */
}
Expand description

NES 6502 CPU

Cycle-accurate implementation of the MOS 6502 as used in the NES. All timing follows the NESdev Wiki specifications.

Fields§

§a: u8

Accumulator register

§x: u8

X index register

§y: u8

Y index register

§pc: u16

Program counter

§sp: u8

Stack pointer (points to $0100-$01FF)

§status: StatusFlags

Status flags

§cycles: u64

Total cycles executed

§stall: u8

Stall cycles (for DMA)

§jammed: bool

CPU jammed (halt opcodes)

Implementations§

Source§

impl Cpu

Source

pub fn new() -> Self

Create a new CPU in power-on state.

§Power-on State
  • A, X, Y: undefined (set to 0)
  • SP: $FD (after RESET pulls 3 bytes)
  • P: $34 (IRQ disabled)
  • PC: Read from RESET vector $FFFC-$FFFD
Source

pub fn reset(&mut self, bus: &mut impl Bus)

Reset the CPU.

Simulates the RESET interrupt sequence:

  • SP decremented by 3 (no writes)
  • I flag set
  • PC loaded from RESET vector ($FFFC-$FFFD)
  • Takes 7 cycles
Source

pub fn step(&mut self, bus: &mut impl Bus) -> u8

Execute one instruction and return cycles taken.

Handles interrupt polling and instruction execution. Returns the number of CPU cycles consumed.

Source

pub fn trigger_nmi(&mut self)

Trigger NMI (Non-Maskable Interrupt).

NMI is edge-triggered - call this when NMI line transitions from high to low.

Source

pub fn set_irq(&mut self, active: bool)

Set IRQ line state.

IRQ is level-triggered - will fire every instruction while line is low and I=0.

Source

pub fn irq_pending(&self) -> bool

Check if IRQ is pending.

Source

pub fn get_cycles(&self) -> u64

Get total cycles executed.

Source

pub fn is_jammed(&self) -> bool

Check if CPU is jammed (halted).

Source

pub fn get_state(&self) -> CpuState

Get current CPU state (for debugging/testing).

Source

pub fn tick(&mut self, bus: &mut impl CpuBus) -> bool

Execute exactly one CPU cycle with cycle-accurate bus synchronization.

This is the core of cycle-accurate emulation. Each call advances the CPU by exactly one cycle, calling on_cpu_cycle() before each memory access to keep PPU and APU perfectly synchronized.

Returns true when an instruction boundary is reached (ready for next instruction).

§Cycle-Accurate Timing

Each memory access calls on_cpu_cycle() BEFORE reading/writing, ensuring that PPU has advanced 3 dots and APU has advanced 1 cycle before the CPU observes the memory state. This is critical for accurate $2002 VBlank flag timing.

Source

pub fn read_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) -> u8

Read a byte from memory with cycle callback.

Calls on_cpu_cycle() BEFORE the read, then performs the actual read. This is the cycle-accurate version of memory read.

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • addr - 16-bit memory address to read from
§Returns

The 8-bit value at the specified address

§Timing
CPU Cycle:  |-------- read --------|
PPU Cycles: |--1--|--2--|--3--|
             ^ on_cpu_cycle() called here
Source

pub fn write_cycle(&mut self, bus: &mut impl CpuBus, addr: u16, value: u8)

Write a byte to memory with cycle callback.

Calls on_cpu_cycle() BEFORE the write, then performs the actual write. This is the cycle-accurate version of memory write.

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • addr - 16-bit memory address to write to
  • value - 8-bit value to write
§Timing
CPU Cycle:  |------- write --------|
PPU Cycles: |--1--|--2--|--3--|
             ^ on_cpu_cycle() called here
Source

pub fn dummy_cycle(&mut self, bus: &mut impl CpuBus, addr: u16)

Perform a dummy read cycle (for timing purposes).

Some instructions require timing cycles where a read is performed but the value is discarded. This method handles those cases while still calling on_cpu_cycle() for proper PPU/APU synchronization.

§Use Cases
  • Page boundary crossing in indexed addressing
  • Implied/Accumulator mode dummy reads
  • Branch taken cycles
  • RMW dummy write-back cycles
§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • addr - Address to read from (value is discarded)
Source

pub fn push_cycle(&mut self, bus: &mut impl CpuBus, value: u8)

Push a byte to the stack with cycle callback.

Calls on_cpu_cycle() BEFORE the write, then pushes to stack.

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • value - 8-bit value to push
Source

pub fn pop_cycle(&mut self, bus: &mut impl CpuBus) -> u8

Pop a byte from the stack with cycle callback.

Calls on_cpu_cycle() BEFORE the read, then pops from stack.

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
§Returns

The 8-bit value popped from the stack

Source

pub fn read_u16_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) -> u16

Read a 16-bit value from memory with cycle callbacks.

Performs two sequential reads with proper cycle callbacks. Each read triggers on_cpu_cycle().

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • addr - Address of the low byte
§Returns

16-bit value: (high << 8) | low

Source

pub fn read_u16_wrap_cycle(&mut self, bus: &mut impl CpuBus, addr: u16) -> u16

Read a 16-bit value with page wrap and cycle callbacks.

Implements the JMP indirect bug where the high byte wraps within the same page if the low byte is at $xxFF.

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • addr - Address of the low byte
§Returns

16-bit value with page-wrap bug behavior

Source

pub fn push_u16_cycle(&mut self, bus: &mut impl CpuBus, value: u16)

Push a 16-bit value to the stack with cycle callbacks.

Pushes high byte first, then low byte (6502 convention). Each push triggers on_cpu_cycle().

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
  • value - 16-bit value to push
Source

pub fn pop_u16_cycle(&mut self, bus: &mut impl CpuBus) -> u16

Pop a 16-bit value from the stack with cycle callbacks.

Pops low byte first, then high byte (6502 convention). Each pop triggers on_cpu_cycle().

§Arguments
  • bus - The cycle-aware bus implementing CpuBus
§Returns

16-bit value popped from the stack

Trait Implementations§

Source§

impl Debug for Cpu

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Cpu

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Cpu

§

impl RefUnwindSafe for Cpu

§

impl Send for Cpu

§

impl Sync for Cpu

§

impl Unpin for Cpu

§

impl UnwindSafe for Cpu

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.