Skip to main content

Ppu

Struct Ppu 

Source
pub struct Ppu { /* private fields */ }
Expand description

PPU1 (5C77) + PPU2 (5C78) state.

Owns VRAM (32 K words), CGRAM (256 × 15-bit BGR), OAM (544 bytes), the full register file, the dot/scanline timeline, and a 256×239 15-bit framebuffer. Advanced one dot at a time by the master-clock scheduler via Ppu::tick_dot; the scheduler polls Ppu::nmi_pending, Ppu::irq_pending, and Ppu::frame_ready to drive interrupts and presentation.

Implementations§

Source§

impl Ppu

Source

pub fn write_reg(&mut self, addr: u16, val: u8)

Write one PPU register ($2100–$213F). Writes to read-only addresses are ignored.

Source

pub fn read_reg(&mut self, addr: u16) -> u8

Read one PPU register ($2100–$213F). Reads of write-only registers return the PPU MDR open-bus latch.

Source§

impl Ppu

Source

pub fn new() -> Self

Construct at power-on (NTSC). Storage starts zeroed; this is deterministic — the determinism contract forbids the OS RNG (docs/adr/0004). Phase alignment, if any, is driven by the scheduler’s seeded PRNG, not here.

Source

pub fn with_region(region: Region) -> Self

Construct at power-on for a specific Region.

Source

pub const fn set_region(&mut self, region: Region)

Set the video region (NTSC/PAL). Affects line count + the STAT78 region bit.

Source

pub const fn region(&self) -> Region

The active video region (NTSC/PAL).

Source

pub const fn visible_height(&self) -> u16

The total visible height for the current overscan setting (224 or 239).

Source

pub const fn is_hires(&self) -> bool

Whether the PPU is currently configured for hi-res output: BGMODE 5/6, or pseudo-hires (SETINI $2133 bit 3) in any mode — matching ares’ hires = pseudoHires || bgMode==5 || bgMode==6 (ref-proj/ares/ares/sfc/ppu/dac.cpp). This is the live per-scanline register state; Ppu::frame_hires is the value latched from this at the start of the frame that’s actually being composited into the framebuffer right now.

Source

pub const fn frame_hires(&self) -> bool

Whether the framebuffer currently being composited is hi-res (512-wide) — the value Ppu::framebuffer’s length/stride is based on for this frame. See the frame_hires field doc for why this is latched once per frame rather than read live per scanline.

Source

pub const fn visible_width(&self) -> usize

The output framebuffer’s width for the frame currently being composited: SCREEN_WIDTH normally, MAX_SCREEN_WIDTH when Ppu::frame_hires is set.

Source

pub fn tick_dot(&mut self, bus: &mut impl VideoBus)

Advance the PPU by exactly one dot, the scheduler’s video quantum. Composites a full visible scanline at RENDER_DOT (one dot before that line’s own per-line HDMA run can observe/mutate the registers the composite reads — see docs/ppu.md §Mid-scanline/ HDMA-driven register timing); raises NMI at VBlank start and the HV-IRQ when the programmed H/V is hit; calls VideoBus::notify_scanline at each line start and VideoBus::notify_vblank when VBlank begins. Hot path: allocation-free.

Source

pub const fn nmi_pending(&self) -> bool

Whether an NMI is pending (asserted at VBlank start). Poll; clear with Ppu::ack_nmi.

Source

pub const fn ack_nmi(&mut self)

Acknowledge / clear the pending NMI (the CPU does this when it takes the vector).

Source

pub const fn irq_pending(&self) -> bool

Whether an HV-timer IRQ is pending. Poll; clear with Ppu::ack_irq.

Source

pub const fn ack_irq(&mut self)

Acknowledge / clear the pending IRQ.

Source

pub const fn set_hv_irq( &mut self, enable_h: bool, enable_v: bool, h: u16, v: u16, )

Program the HV-IRQ comparator (the CPU writes $4200/$4207$420A; the scheduler forwards them here so the PPU owns the comparison against its own H/V phase).

Source

pub const fn in_vblank(&self) -> bool

Whether the PPU is currently in vertical blank.

Source

pub const fn in_hblank(&self) -> bool

Whether the PPU is currently in horizontal blank.

Source

pub const fn dot(&self) -> u16

The current horizontal dot counter (0..=340).

Source

pub const fn scanline(&self) -> u16

The current vertical scanline counter.

Source

pub const fn latch_hv_counters(&mut self)

Latch the current H/V dot counters into OPHCT/OPVCT ($213C/$213D) right now — the same effect a CPU read of SLHV ($2137) has (regs.rs’s 0x2137 arm calls this too, so there is one implementation of the latch itself). Real hardware also drives this from the WRIO ($4201) I/O port’s bit7 falling edge (the controller-port-2 IOBIT pin, wired straight to this latch — a Super Scope’s light sensor toggles it to record the CRT beam position when it “sees” it, rustysnes_core::controller); exposed as pub so the Bus (which owns WRIO, not the PPU) can trigger the identical latch from that path without duplicating it.

Source

pub const fn frame_ready(&self) -> bool

Whether a finished frame is available. Cleared by Ppu::take_frame.

Source

pub const fn bg_mode(&self) -> u8

The current BGMODE ($2105) value (0..=7) — which of the 8 tile/priority layouts is active. For the debugger overlay’s PPU panel (docs/frontend.md §Debugger overlay).

Source

pub const fn display_brightness(&self) -> u8

The current INIDISP ($2100) master brightness (0..=15). For the debugger overlay.

Source

pub const fn frame_count(&self) -> u64

Completed-frame count since power-on (monotonic, wrapping).

Source

pub fn framebuffer(&self) -> &[u16]

The composited framebuffer: visible_width() * SCREEN_HEIGHT 15-bit BGR pixels, row-major at the current frame’s stride (SCREEN_WIDTH normally, MAX_SCREEN_WIDTH for a hi-res frame — see Ppu::frame_hires). Only the first Ppu::visible_height rows are written each frame. A non-hires frame’s length here is exactly FRAMEBUFFER_LEN, unchanged from before hi-res output existed.

Source

pub fn take_frame(&mut self) -> &[u16]

Borrow the framebuffer and clear the frame_ready flag (one-shot presentation).

Source

pub fn vram_word(&self, addr: u16) -> u16

Read a VRAM word directly (test/diagnostic; not the register path).

Source

pub fn vram(&self) -> &[u16]

The full 64 KiB VRAM as a flat word slice (32Ki x u16, native word addressing) — for a host embedder that needs a raw memory-map pointer (e.g. a libretro core’s RETRO_MEMORY_VIDEO_RAM).

Source

pub fn vram_mut(&mut self) -> &mut [u16]

The mutable counterpart to Self::vram — same host-embedder use case.

Source

pub const fn cgram_word(&self, index: u8) -> u16

Read a CGRAM entry directly (test/diagnostic).

Source

pub const fn oam_byte(&self, index: u16) -> u8

Read an OAM byte directly (test/diagnostic).

Source

pub fn save_state(&self, w: &mut SaveWriter)

Write VRAM/CGRAM/OAM, the full register file, the write latches, the dot/scanline timeline, the interrupt/frame poll state, and the composited framebuffer into a "PPU0" section. There is no firmware/ROM byte here to exclude — the PPU carries no chip-ROM dump (docs/adr/0003); region is written too since it’s set by cart detection, not re-derivable from anything else stored here.

Source

pub fn load_state( &mut self, r: &mut SaveReader<'_>, ) -> Result<(), SaveStateError>

The inverse of Self::save_state.

§Errors

SaveStateError on truncated/corrupt input, a section with unconsumed trailing bytes, or SaveStateError::Invalid if the encoded region discriminant doesn’t match one of Region’s two variants (a semantic enum constraint, not a hardware register width).

Trait Implementations§

Source§

impl Clone for Ppu

Source§

fn clone(&self) -> Ppu

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Ppu

Source§

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

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

impl Default for Ppu

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl Freeze for Ppu

§

impl RefUnwindSafe for Ppu

§

impl Send for Ppu

§

impl Sync for Ppu

§

impl Unpin for Ppu

§

impl UnsafeUnpin for Ppu

§

impl UnwindSafe for Ppu

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.