cge_nes 0.1.2

Cycle-accurate NES (Nintendo Entertainment System) emulator library: CPU, PPU, cartridge, input, and iNES ROM loading.
Documentation
//! PPU control register ($2000) implementation.
//!
//! This module handles the PPU control register which configures:
//! * Base nametable address selection
//! * VRAM address increment mode
//! * Sprite/background pattern table selection
//! * Sprite size
//! * Master/slave select
//! * NMI enable/disable

use crate::ppu::registers::Registers;
use bitflags::bitflags;

bitflags! {
    /// Control register flags for PPU configuration ($2000).
    ///
    /// Each bit controls a different aspect of PPU operation:
    /// * Bits 0-1: Base nametable address
    /// * Bit 2: VRAM address increment mode
    /// * Bit 3: Sprite pattern table address
    /// * Bit 4: Background pattern table address
    /// * Bit 5: Sprite size (8x8 or 8x16)
    /// * Bit 6: PPU master/slave select
    /// * Bit 7: Generate NMI at start of vblank
    #[derive(PartialEq, Eq, Copy, Clone, Debug)]
    pub struct PpuControlFlags: u8 {
        const NAME_TABLE_X =        0b00000001;
        const NAME_TABLE_Y =        0b00000010;
        const INC_MODE =            0b00000100;
        const SPRITE_TILE_SELECT =  0b00001000;
        const BG_TILE_SELECT =      0b00010000;
        const SPRITE_HEIGHT =       0b00100000;
        const PPU_MASTER_SLAVE =    0b01000000;
        const NMI_ENABLE =          0b10000000;
    }
}

/// Represents the currently selected nametable based on control register bits 0-1.
///
/// The PPU uses a 2x2 arrangement of nametables. This structure tracks which
/// nametable is currently selected as the base table for rendering.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct SelectedNameTable {
    flags: PpuControlFlags,
}

impl Default for PpuControlFlags {
    fn default() -> Self {
        Self::empty()
    }
}

impl SelectedNameTable {
    /// Creates a new SelectedNameTable with the specified position.
    ///
    /// # Parameters
    /// * `right_col` - If true, selects right column of nametables
    /// * `bottom_row` - If true, selects bottom row of nametables
    #[allow(dead_code)]
    pub fn new(right_col: bool, bottom_row: bool) -> Self {
        let mut flags = PpuControlFlags::default();

        if right_col {
            flags.insert(PpuControlFlags::NAME_TABLE_X);
        }

        if bottom_row {
            flags.insert(PpuControlFlags::NAME_TABLE_Y);
        }

        Self { flags }
    }
}

impl Registers {
    /// Returns true if sprites should be 8x16 pixels instead of 8x8.
    pub fn large_sprites_flag(&self) -> bool {
        self.ppu_ctrl.contains(PpuControlFlags::SPRITE_HEIGHT)
    }

    /// Returns true if sprite patterns should be fetched from the second pattern table.
    pub fn sprite_second_table_selected(&self) -> bool {
        self.ppu_ctrl.contains(PpuControlFlags::SPRITE_TILE_SELECT)
    }

    #[cfg(test)]
    pub fn set_sprite_second_table_selected(&mut self) {
        self.ppu_ctrl.insert(PpuControlFlags::SPRITE_TILE_SELECT);
    }

    /// Returns true if background patterns should be fetched from the second pattern table.
    pub fn bg_second_table_selected(&self) -> bool {
        self.ppu_ctrl.contains(PpuControlFlags::BG_TILE_SELECT)
    }

    /// Returns the currently selected base nametable.

    /// Returns true if NMI generation is enabled at start of vblank.
    pub fn nmi_enabled(&self) -> bool {
        self.ppu_ctrl.contains(PpuControlFlags::NMI_ENABLE)
    }
}