Skip to main content

rustynes_ppu/
lib.rs

1//! Cycle-accurate Ricoh 2C02 PPU implementation.
2//!
3//! See `docs/ppu-2c02.md` for the implementation spec and
4//! `ref-docs/research-report.md` §PPU for the source material.
5//!
6//! Background rendering, sprite evaluation + rendering, sprite-zero hit,
7//! sprite overflow, and the open-bus latch are all implemented at PPU-dot
8//! resolution. PPUSTATUS / PPUDATA / PPUSCROLL / PPUADDR register quirks
9//! match the test-ROM corpus. The 2-PPU-clock PPUMASK pipeline delay
10//! between a mask write and the odd-frame dot-skip check is wired through.
11//!
12//! Region timing (NTSC vs PAL vs Dendy) is parameterized via
13//! [`PpuRegion`]; the structural difference between them is the post-
14//! render-to-pre-render scanline span (NTSC: 241..=260; PAL: 241..=310;
15//! Dendy: 241..=290).
16
17#![no_std]
18#![warn(missing_docs)]
19// Truncating casts are the canonical encoding for the PPU's 8/16-bit register
20// arithmetic; we annotate this once at module level rather than per-line.
21#![allow(
22    clippy::cast_possible_truncation,
23    clippy::cast_lossless,
24    clippy::cast_possible_wrap
25)]
26
27extern crate alloc;
28
29mod bus;
30#[cfg(feature = "ppu-fetch-trace")]
31pub mod fetch_trace;
32mod palette;
33mod palette_gen;
34mod ppu;
35#[cfg(feature = "debug-hooks")]
36pub mod provenance;
37mod raw_signal;
38mod registers;
39mod snapshot;
40#[cfg(feature = "ppu-state-trace")]
41pub mod state_trace;
42
43pub use bus::{BgSplitState, ExAttribute, PpuBus};
44pub use palette::{
45    NES_PALETTE, PpuPalette, build_rgba_lut, build_rgba_lut_from_base, nes_color_to_rgba,
46    palette_color_to_rgba,
47};
48pub use palette_gen::{NtscPaletteParams, generate_base_palette};
49pub use ppu::MASK_WRITE_DELAY;
50#[cfg(feature = "debug-hooks")]
51pub use ppu::ProvBgAddrs;
52pub use ppu::octal_trace;
53pub use ppu::read2007_diag;
54pub use ppu::{
55    FRAMEBUFFER_LEN, FRAMEBUFFER_PIXELS, PaletteInit, Ppu, PpuRegion, PpuRevision, SCREEN_HEIGHT,
56    SCREEN_WIDTH,
57};
58#[cfg(feature = "hd-pack")]
59pub use ppu::{HD_CHR_RAM, HD_TILE_NONE, HdSprite, HdTileSource};
60#[cfg(feature = "debug-hooks")]
61pub use provenance::{
62    CIRAM_LEN as ATTRIB_CIRAM_LEN, OAM_LEN as ATTRIB_OAM_LEN, PALETTE_LEN as ATTRIB_PALETTE_LEN,
63    PATTERN_ADDR_NONE, PixelLayer, PixelProvenance, PixelProvenanceFrame, ProvenanceStash,
64    SPRITE_SLOT_NONE, WriteAttrib, WriteAttribution,
65};
66pub use raw_signal::{
67    ATTENUATION, BLACK, LEVELS, PHASES, RAW_ENTRIES, WHITE, composite_voltage,
68    generate_raw_signal_lut, in_color_phase, normalize, signal_samples,
69};
70pub use snapshot::{PPU_SNAPSHOT_SLIM_FLAG, PPU_SNAPSHOT_VERSION, PpuSnapshotError};
71
72#[cfg(feature = "ppu-state-trace")]
73pub use state_trace::{
74    BINARY_MAGIC, HEADER_SIZE, PPU_TRACE_SCHEMA_VERSION, PpuStateRecord, PpuStateTrace,
75    PpuTraceConfig, RECORD_SIZE, fnv1a64,
76};
77
78/// Returns the crate version string.
79#[must_use]
80pub const fn version() -> &'static str {
81    env!("CARGO_PKG_VERSION")
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn version_is_non_empty() {
90        assert!(!version().is_empty());
91    }
92}