pub fn write_register_by_index(
        &mut self,
        index: u8,
        val: u8,
        cpu: &mut cpu::Cpu,
        bus: &mut dyn PpuAddressBus,
    ) {
        {
            match index {
                // ppuctrl
                0 => write_ppuctrl(self, val, cpu),
                // ppumask
                1 => write_ppumask(self, val, bus, cpu),
                // ppustatus, ignore attemps to write
                2 => return,
                // oamaddr
                3 => self.oamaddr = val,
                // oamdata
                4 => write_oamdata(self, val),
                // ppuscroll
                5 => write_ppuscroll(self, val),
                // ppuaddr
                6 => write_ppuaddr(self, val, bus, cpu),
                // ppudata
                7 => write_ppudata(self, val, bus, cpu),
                _ => (),
            }
        }

        fn write_ppuctrl(ppu: &mut Ppu, val: u8, cpu: &mut cpu::Cpu) {
            // set bits 10-11 of 'temp_vram_addr' equal to the low 2 bits of 'val'
            ppu.temp_vram_addr.set_nametable_select(val & 0b11);

            // true if nmi_enable bit went from 1 to 0 or 0 to 1
            let nmi_toggled = ((ppu.ppuctrl ^ val) >> 7) != 0;

            ppu.ppuctrl = val;
            ppu.set_ppustatus_low_bits(val);

            if nmi_toggled && ppu.is_vblank_nmi_enabled() && ppu.is_vblank() {
                cpu.bits.nmi.set(1);
                // HACK: delay nmi by one instruction
                cpu.bits.delay_nmi.set(1);
            }
        }

        fn write_ppumask(ppu: &mut Ppu, val: u8, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) {
            ppu.ppumask = val;

            if !ppu.is_currently_rendering() {
                bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
            }
        }

        fn write_oamdata(ppu: &mut Ppu, val: u8) {
            if ppu.is_currently_rendering() {
                // ignore attemps to write when rendering
                return;
            }

            ppu.write_to_oam_and_increment_addr(val);
            ppu.set_ppustatus_low_bits(val);
        }

        fn write_ppuscroll(ppu: &mut Ppu, val: u8) {
            // low bits toggle = 0 => x coordinate is being written
            if !ppu.bits.low_bits_toggle.is_true() {
                // write low 3 bits (fine x) to 'ppu.fine_x_scroll'
                ppu.bits.fine_x_scroll.set(val & 0b111);
                // write high 5 bits (coarse x) to low 5 bits
                // of temporary vram address register
                ppu.temp_vram_addr.set_coarse_x(val >> 3);
            }
            // low bits toggle = 1 => y coordinate is being written
            else {
                // write high 5 bits (coarse y) to
                // bits 5-10 of 'temp_vram_addr'
                ppu.temp_vram_addr.set_coarse_y(val >> 3);
                // write low 3 bits (fine y) to bits
                // 12-14 of 'temp_vram_addr'
                ppu.temp_vram_addr.set_fine_y(val & 0b111);
            }

            ppu.set_ppustatus_low_bits(val);
            ppu.toggle_low_bits_toggle();
        }

        fn write_ppuaddr(ppu: &mut Ppu, val: u8, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) {
            let mut temp_vram_addr_bytes = ppu.temp_vram_addr.inner.to_le_bytes();

            if !ppu.bits.low_bits_toggle.is_true() {
                // write low 6 bits into bits 8-13 of temporary
                // vram address register while clearing bit 14
                temp_vram_addr_bytes[1] = val & 0b0111111;
                // store back
                ppu.temp_vram_addr.inner = u16::from_le_bytes(temp_vram_addr_bytes);
            } else {
                // set all low bits of temporary vram register equal to 'val'
                temp_vram_addr_bytes[0] = val;
                ppu.temp_vram_addr.inner = u16::from_le_bytes(temp_vram_addr_bytes);

                // set 'current_vram_addr' equal to 'temp_vram_addr'
                ppu.current_vram_addr = ppu.temp_vram_addr;

                if !ppu.is_currently_rendering() {
                    // if not currently rendering, the address bus
                    // should be set to 'current_vram_addr'
                    bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
                }
            }

            ppu.set_ppustatus_low_bits(val);
            ppu.toggle_low_bits_toggle();
        }

        fn write_ppudata(ppu: &mut Ppu, val: u8, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) {
            bus.write(ppu.current_vram_addr.get_addr(), val, ppu.cycle_count, cpu);
            ppu.set_ppustatus_low_bits(val);

            // increment 'current_vram_addr' (same as when reading ppudata)
            if !ppu.is_currently_rendering() {
                ppu.increment_vram_addr();
                bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
            } else {
                ppu.increment_vram_addr_coarse_x();
                ppu.increment_vram_addr_y();
            }
        }
    }
// used for writing to the registers located in the cpu memory map at 0x2000-0x2007
used for writing to the registers located in the cpu memory map at 0x2000-0x2007
used for writing to the registers located in the cpu memory map at 0x2000 - 0x2007
pub fn write_register_by_index(
        &mut self,
        index: u8,
        val: u8,
        cpu: &mut cpu::Cpu,
        bus: &mut dyn PpuAddressBus,
    ) {
        {
            match index {
                // ppuctrl
                0 => write_ppuctrl(self, val, cpu),
                // ppumask
                1 => write_ppumask(self, val, bus, cpu),
                // ppustatus, ignore attemps to write
                2 => return,
                // oamaddr
                3 => self.oamaddr = val,
                // oamdata
                4 => write_oamdata(self, val),
                // ppuscroll
                5 => write_ppuscroll(self, val),
                // ppuaddr
                6 => write_ppuaddr(self, val, bus, cpu),
                // ppudata
                7 => write_ppudata(self, val, bus, cpu),
                _ => (),
            }
        }
        fn write_ppuctrl(ppu: &mut Ppu, val: u8, cpu: &mut cpu::Cpu) {
            // set bits 10-11 of 'temp_vram_addr' equal to the low 2 bits of 'val'
            ppu.temp_vram_addr.set_nametable_select(val & 0b11);
            // true if nmi_enable bit went from 1 to 0 or 0 to 1
            let nmi_toggled = ((ppu.ppuctrl ^ val) >> 7) != 0;
            ppu.ppuctrl = val;
            ppu.set_ppustatus_low_bits(val);
            if nmi_toggled && ppu.is_vblank_nmi_enabled() && ppu.is_vblank() {
                cpu.bits.nmi.set(1);
                // HACK: delay nmi by one instruction
                cpu.bits.delay_nmi.set(1);
            }
        }
        fn write_ppumask(ppu: &mut Ppu, val: u8, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) {
            ppu.ppumask = val;
            if !ppu.is_currently_rendering() {
                bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
            }
        }
        fn write_oamdata(ppu: &mut Ppu, val: u8) {
            if ppu.is_currently_rendering() {
                // ignore attemps to write when rendering
                return;
            }
            ppu.write_to_oam_and_increment_addr(val);
            ppu.set_ppustatus_low_bits(val);
        }
        fn write_ppuscroll(ppu: &mut Ppu, val: u8) {
            // low bits toggle = 0 => x coordinate is being written
            if !ppu.bits.low_bits_toggle.is_true() {
                // write low 3 bits (fine x) to 'ppu.fine_x_scroll'
                ppu.bits.fine_x_scroll.set(val & 0b111);
                // write high 5 bits (coarse x) to low 5 bits
                // of temporary vram address register
                ppu.temp_vram_addr.set_coarse_x(val >> 3);
            }
            // low bits toggle = 1 => y coordinate is being written
            else {
                // write high 5 bits (coarse y) to
                // bits 5-10 of 'temp_vram_addr'
                ppu.temp_vram_addr.set_coarse_y(val >> 3);
                // write low 3 bits (fine y) to bits
                // 12-14 of 'temp_vram_addr'
                ppu.temp_vram_addr.set_fine_y(val & 0b111);
            }
            ppu.set_ppustatus_low_bits(val);
            ppu.toggle_low_bits_toggle();
        }
        fn write_ppuaddr(ppu: &mut Ppu, val: u8, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) {
            let mut temp_vram_addr_bytes = ppu.temp_vram_addr.inner.to_le_bytes();
            if !ppu.bits.low_bits_toggle.is_true() {
                // write low 6 bits into bits 8-13 of temporary
                // vram address register while clearing bit 14
                temp_vram_addr_bytes[1] = val & 0b0111111;
                // store back
                ppu.temp_vram_addr.inner = u16::from_le_bytes(temp_vram_addr_bytes);
            } else {
                // set all low bits of temporary vram register equal to 'val'
                temp_vram_addr_bytes[0] = val;
                ppu.temp_vram_addr.inner = u16::from_le_bytes(temp_vram_addr_bytes);
                // set 'current_vram_addr' equal to 'temp_vram_addr'
                ppu.current_vram_addr = ppu.temp_vram_addr;
                if !ppu.is_currently_rendering() {
                    // if not currently rendering, the address bus
                    // should be set to 'current_vram_addr'
                    bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
                }
            }
            ppu.set_ppustatus_low_bits(val);
            ppu.toggle_low_bits_toggle();
        }
        fn write_ppudata(ppu: &mut Ppu, val: u8, bus: &mut dyn PpuAddressBus, cpu: &mut cpu::Cpu) {
            bus.write(ppu.current_vram_addr.get_addr(), val, ppu.cycle_count, cpu);
            ppu.set_ppustatus_low_bits(val);
            // increment 'current_vram_addr' (same as when reading ppudata)
            if !ppu.is_currently_rendering() {
                ppu.increment_vram_addr();
                bus.set_address(ppu.current_vram_addr.inner, ppu.cycle_count, cpu);
            } else {
                ppu.increment_vram_addr_coarse_x();
                ppu.increment_vram_addr_y();
            }
        }
    }
pub fn write_register_by_index ( & mut self , index : u8 , val : u8 , cpu : & mut cpu :: Cpu , bus : & mut dyn PpuAddressBus , ) { { match index { // ppuctrl 0 => write_ppuctrl ( self , val , cpu ) , // ppumask 1 => write_ppumask ( self , val , bus , cpu ) , // ppustatus, ignore attemps to write 2 => return , // oamaddr 3 => self . oamaddr = val , // oamdata 4 => write_oamdata ( self , val ) , // ppuscroll 5 => write_ppuscroll ( self , val ) , // ppuaddr 6 => write_ppuaddr ( self , val , bus , cpu ) , // ppudata 7 => write_ppudata ( self , val , bus , cpu ) , _ => ( ) , } } fn write_ppuctrl ( ppu : & mut Ppu , val : u8 , cpu : & mut cpu :: Cpu ) { // set bits 10-11 of 'temp_vram_addr' equal to the low 2 bits of 'val' ppu . temp_vram_addr . set_nametable_select ( val & 0b11 ) ; // true if nmi_enable bit went from 1 to 0 or 0 to 1 let nmi_toggled = ( ( ppu . ppuctrl ^ val ) >> 7 ) != 0 ; ppu . ppuctrl = val ; ppu . set_ppustatus_low_bits ( val ) ; if nmi_toggled && ppu . is_vblank_nmi_enabled ( ) && ppu . is_vblank ( ) { cpu . bits . nmi . set ( 1 ) ; // HACK: delay nmi by one instruction cpu . bits . delay_nmi . set ( 1 ) ; } } fn write_ppumask ( ppu : & mut Ppu , val : u8 , bus : & mut dyn PpuAddressBus , cpu : & mut cpu :: Cpu ) { ppu . ppumask = val ; if ! ppu . is_currently_rendering ( ) { bus . set_address ( ppu . current_vram_addr . inner , ppu . cycle_count , cpu ) ; } } fn write_oamdata ( ppu : & mut Ppu , val : u8 ) { if ppu . is_currently_rendering ( ) { // ignore attemps to write when rendering return ; } ppu . write_to_oam_and_increment_addr ( val ) ; ppu . set_ppustatus_low_bits ( val ) ; } fn write_ppuscroll ( ppu : & mut Ppu , val : u8 ) { // low bits toggle = 0 => x coordinate is being written if ! ppu . bits . low_bits_toggle . is_true ( ) { // write low 3 bits (fine x) to 'ppu.fine_x_scroll' ppu . bits . fine_x_scroll . set ( val & 0b111 ) ; // write high 5 bits (coarse x) to low 5 bits // of temporary vram address register ppu . temp_vram_addr . set_coarse_x ( val >> 3 ) ; } // low bits toggle = 1 => y coordinate is being written else { // write high 5 bits (coarse y) to // bits 5-10 of 'temp_vram_addr' ppu . temp_vram_addr . set_coarse_y ( val >> 3 ) ; // write low 3 bits (fine y) to bits // 12-14 of 'temp_vram_addr' ppu . temp_vram_addr . set_fine_y ( val & 0b111 ) ; } ppu . set_ppustatus_low_bits ( val ) ; ppu . toggle_low_bits_toggle ( ) ; } fn write_ppuaddr ( ppu : & mut Ppu , val : u8 , bus : & mut dyn PpuAddressBus , cpu : & mut cpu :: Cpu ) { let mut temp_vram_addr_bytes = ppu . temp_vram_addr . inner . to_le_bytes ( ) ; if ! ppu . bits . low_bits_toggle . is_true ( ) { // write low 6 bits into bits 8-13 of temporary // vram address register while clearing bit 14 temp_vram_addr_bytes [ 1 ] = val & 0b0111111 ; // store back ppu . temp_vram_addr . inner = u16 :: from_le_bytes ( temp_vram_addr_bytes ) ; } else { // set all low bits of temporary vram register equal to 'val' temp_vram_addr_bytes [ 0 ] = val ; ppu . temp_vram_addr . inner = u16 :: from_le_bytes ( temp_vram_addr_bytes ) ; // set 'current_vram_addr' equal to 'temp_vram_addr' ppu . current_vram_addr = ppu . temp_vram_addr ; if ! ppu . is_currently_rendering ( ) { // if not currently rendering, the address bus // should be set to 'current_vram_addr' bus . set_address ( ppu . current_vram_addr . inner , ppu . cycle_count , cpu ) ; } } ppu . set_ppustatus_low_bits ( val ) ; ppu . toggle_low_bits_toggle ( ) ; } fn write_ppudata ( ppu : & mut Ppu , val : u8 , bus : & mut dyn PpuAddressBus , cpu : & mut cpu :: Cpu ) { bus . write ( ppu . current_vram_addr . get_addr ( ) , val , ppu . cycle_count , cpu ) ; ppu . set_ppustatus_low_bits ( val ) ; // increment 'current_vram_addr' (same as when reading ppudata) if ! ppu . is_currently_rendering ( ) { ppu . increment_vram_addr ( ) ; bus . set_address ( ppu . current_vram_addr . inner , ppu . cycle_count , cpu ) ; } else { ppu . increment_vram_addr_coarse_x ( ) ; ppu . increment_vram_addr_y ( ) ; } } }
used for writing to the registers located in the cpu memory map at 0x2000-0x2007
used for writing to the registers located in the cpu memory map at 0x2000 - 0x2007
&mut self
index
u8
val
u8
cpu
&mut cpu::Cpu
bus
&mut dyn PpuAddressBus
&mut self
index
u8
val
u8
cpu
&mut cpu::Cpu
bus
&mut dyn PpuAddressBus