pub fn read_register_by_index(
        &mut self,
        index: u8,
        bus: &mut dyn PpuAddressBus,
        cpu: &mut cpu::Cpu,
    ) -> u8 {
        // NOTE: to help readability, this function and a few others on 'Ppu' are
        // split into smaller subfunctions. instead of factoring these subfunctions
        // out into the outer 'Ppu' impl block, i decided to keep them nested, so as
        // to not give the impression that they are needed anywhere else

        {
            return match index {
                // ppuctrl
                0 => 0,
                // ppumask
                1 => self.ppumask,
                // ppustatus
                2 => read_ppustatus(self),
                // oamaddr
                3 => 0,
                // oamdata
                4 => read_oamdata(self),
                // ppuscroll | ppuaddr
                5 | 6 => 0, // FIXME: should these reset the low bits toggle as well??
                // ppudata
                7 => read_ppudata(self, bus, cpu),
                _ => 0,
            };
        }

        fn read_ppustatus(ppu: &mut Ppu) -> u8 {
            // clear low bits toggle
            ppu.bits.low_bits_toggle.set(0);
            let status = ppu.ppustatus;
            // clear vblank flag
            ppu.set_vblank(false);

            if ppu.current_scanline == 241 && ppu.current_scanline_dot == 1 {
                // vblank flag should not have been set yet
                debug_assert!(status & 0b10000000 == 0);
                // if there is one cycle left before the vblank flag will be set
                // (when scanline = 241 and dot = 1, the flag will be set on the
                // next call to 'step()'), prevent the vblank flag from being set
                ppu.bits.suppress_vblank_flag.set(1);
            }

            status
        }

        fn read_oamdata(ppu: &mut Ppu) -> u8 {
            if let (0..=239, 1..=64) = (ppu.current_scanline, ppu.current_scanline_dot) {
                // if on dots/cycles 1-64 of a visible scanline, return 0xff
                return 0xff;
            }

            let mut byte = ppu.primary_oam.get_byte(ppu.oamaddr);
            if ppu.oamaddr % 4 == 2 {
                // if 'byte' is a sprite attribute byte, clear bits 2-4
                byte &= 0b11100011;
            }

            byte
        }

        fn read_ppudata(ppu: &mut Ppu, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) -> u8 {
            let val = if (ppu.current_vram_addr.inner >> 8) == 0b111111 {
                // read directly from vram if address is in range
                // 0x3f00-0x3fff (palette ram)
                let val = bus.read(ppu.current_vram_addr.get_addr(), ppu.cycle_count, cpu);
                // store value at mirrored address (down to 0x2f00-0x2fff)
                // in read buffer
                ppu.ppudata_read_buffer = bus.read(
                    ppu.current_vram_addr.get_addr() & !0x1000,
                    ppu.cycle_count,
                    cpu,
                );
                val
            } else {
                // read from read buffer if address is in range 0-0x3eff
                let val = ppu.ppudata_read_buffer;
                ppu.ppudata_read_buffer =
                    bus.read(ppu.current_vram_addr.get_addr(), ppu.cycle_count, cpu);
                val
            };

            if !ppu.is_currently_rendering() {
                // if not currently rendering, increment normally
                ppu.increment_vram_addr();
                // set address on address bus equal to 'current_vram_addr'
                bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
            } else {
                // if currently rendering, increment the bits of the address
                // corresponding to the y position and coarse x position (this
                // is afaik unintended behavior)
                ppu.increment_vram_addr_coarse_x();
                ppu.increment_vram_addr_y();
            }

            val
        }
    }
// used for reading the registers located in the cpu memory map at 0x2000-0x2007
used for reading the registers located in the cpu memory map at 0x2000-0x2007
used for reading the registers located in the cpu memory map at 0x2000 - 0x2007
pub fn read_register_by_index(
        &mut self,
        index: u8,
        bus: &mut dyn PpuAddressBus,
        cpu: &mut cpu::Cpu,
    ) -> u8 {
        // NOTE: to help readability, this function and a few others on 'Ppu' are
        // split into smaller subfunctions. instead of factoring these subfunctions
        // out into the outer 'Ppu' impl block, i decided to keep them nested, so as
        // to not give the impression that they are needed anywhere else
        {
            return match index {
                // ppuctrl
                0 => 0,
                // ppumask
                1 => self.ppumask,
                // ppustatus
                2 => read_ppustatus(self),
                // oamaddr
                3 => 0,
                // oamdata
                4 => read_oamdata(self),
                // ppuscroll | ppuaddr
                5 | 6 => 0, // FIXME: should these reset the low bits toggle as well??
                // ppudata
                7 => read_ppudata(self, bus, cpu),
                _ => 0,
            };
        }
        fn read_ppustatus(ppu: &mut Ppu) -> u8 {
            // clear low bits toggle
            ppu.bits.low_bits_toggle.set(0);
            let status = ppu.ppustatus;
            // clear vblank flag
            ppu.set_vblank(false);
            if ppu.current_scanline == 241 && ppu.current_scanline_dot == 1 {
                // vblank flag should not have been set yet
                debug_assert!(status & 0b10000000 == 0);
                // if there is one cycle left before the vblank flag will be set
                // (when scanline = 241 and dot = 1, the flag will be set on the
                // next call to 'step()'), prevent the vblank flag from being set
                ppu.bits.suppress_vblank_flag.set(1);
            }
            status
        }
        fn read_oamdata(ppu: &mut Ppu) -> u8 {
            if let (0..=239, 1..=64) = (ppu.current_scanline, ppu.current_scanline_dot) {
                // if on dots/cycles 1-64 of a visible scanline, return 0xff
                return 0xff;
            }
            let mut byte = ppu.primary_oam.get_byte(ppu.oamaddr);
            if ppu.oamaddr % 4 == 2 {
                // if 'byte' is a sprite attribute byte, clear bits 2-4
                byte &= 0b11100011;
            }
            byte
        }
        fn read_ppudata(ppu: &mut Ppu, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) -> u8 {
            let val = if (ppu.current_vram_addr.inner >> 8) == 0b111111 {
                // read directly from vram if address is in range
                // 0x3f00-0x3fff (palette ram)
                let val = bus.read(ppu.current_vram_addr.get_addr(), ppu.cycle_count, cpu);
                // store value at mirrored address (down to 0x2f00-0x2fff)
                // in read buffer
                ppu.ppudata_read_buffer = bus.read(
                    ppu.current_vram_addr.get_addr() & !0x1000,
                    ppu.cycle_count,
                    cpu,
                );
                val
            } else {
                // read from read buffer if address is in range 0-0x3eff
                let val = ppu.ppudata_read_buffer;
                ppu.ppudata_read_buffer =
                    bus.read(ppu.current_vram_addr.get_addr(), ppu.cycle_count, cpu);
                val
            };
            if !ppu.is_currently_rendering() {
                // if not currently rendering, increment normally
                ppu.increment_vram_addr();
                // set address on address bus equal to 'current_vram_addr'
                bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
            } else {
                // if currently rendering, increment the bits of the address
                // corresponding to the y position and coarse x position (this
                // is afaik unintended behavior)
                ppu.increment_vram_addr_coarse_x();
                ppu.increment_vram_addr_y();
            }
            val
        }
    }
pub fn read_register_by_index ( & mut self , index : u8 , bus : & mut dyn PpuAddressBus , cpu : & mut cpu :: Cpu , ) -> u8 { // NOTE: to help readability, this function and a few others on 'Ppu' are // split into smaller subfunctions. instead of factoring these subfunctions // out into the outer 'Ppu' impl block, i decided to keep them nested, so as // to not give the impression that they are needed anywhere else { return match index { // ppuctrl 0 => 0 , // ppumask 1 => self . ppumask , // ppustatus 2 => read_ppustatus ( self ) , // oamaddr 3 => 0 , // oamdata 4 => read_oamdata ( self ) , // ppuscroll | ppuaddr 5 | 6 => 0 , // FIXME: should these reset the low bits toggle as well?? // ppudata 7 => read_ppudata ( self , bus , cpu ) , _ => 0 , } ; } fn read_ppustatus ( ppu : & mut Ppu ) -> u8 { // clear low bits toggle ppu . bits . low_bits_toggle . set ( 0 ) ; let status = ppu . ppustatus ; // clear vblank flag ppu . set_vblank ( false ) ; if ppu . current_scanline == 241 && ppu . current_scanline_dot == 1 { // vblank flag should not have been set yet debug_assert ! ( status 0b10000000 0 ) ; // if there is one cycle left before the vblank flag will be set // (when scanline = 241 and dot = 1, the flag will be set on the // next call to 'step()'), prevent the vblank flag from being set ppu . bits . suppress_vblank_flag . set ( 1 ) ; } status } fn read_oamdata ( ppu : & mut Ppu ) -> u8 { if let ( 0 ..= 239 , 1 ..= 64 ) = ( ppu . current_scanline , ppu . current_scanline_dot ) { // if on dots/cycles 1-64 of a visible scanline, return 0xff return 0xff ; } let mut byte = ppu . primary_oam . get_byte ( ppu . oamaddr ) ; if ppu . oamaddr % 4 == 2 { // if 'byte' is a sprite attribute byte, clear bits 2-4 byte &= 0b11100011 ; } byte } fn read_ppudata ( ppu : & mut Ppu , bus : & mut dyn PpuAddressBus , cpu : & mut cpu :: Cpu ) -> u8 { let val = if ( ppu . current_vram_addr . inner >> 8 ) == 0b111111 { // read directly from vram if address is in range // 0x3f00-0x3fff (palette ram) let val = bus . read ( ppu . current_vram_addr . get_addr ( ) , ppu . cycle_count , cpu ) ; // store value at mirrored address (down to 0x2f00-0x2fff) // in read buffer ppu . ppudata_read_buffer = bus . read ( ppu . current_vram_addr . get_addr ( ) & ! 0x1000 , ppu . cycle_count , cpu , ) ; val } else { // read from read buffer if address is in range 0-0x3eff let val = ppu . ppudata_read_buffer ; ppu . ppudata_read_buffer = bus . read ( ppu . current_vram_addr . get_addr ( ) , ppu . cycle_count , cpu ) ; val } ; if ! ppu . is_currently_rendering ( ) { // if not currently rendering, increment normally ppu . increment_vram_addr ( ) ; // set address on address bus equal to 'current_vram_addr' bus . set_address ( ppu . current_vram_addr . inner , ppu . cycle_count , cpu ) ; } else { // if currently rendering, increment the bits of the address // corresponding to the y position and coarse x position (this // is afaik unintended behavior) ppu . increment_vram_addr_coarse_x ( ) ; ppu . increment_vram_addr_y ( ) ; } val } }
used for reading the registers located in the cpu memory map at 0x2000-0x2007
used for reading the registers located in the cpu memory map at 0x2000 - 0x2007
&mut self
index
u8
bus
&mut dyn PpuAddressBus
cpu
&mut cpu::Cpu
&mut self
index
u8
bus
&mut dyn PpuAddressBus
cpu
&mut cpu::Cpu