Example #1
0
        private static byte Read(int address)
        {
            BUS_RW_P    = BUS_RW;
            BUS_ADDRESS = address;
            BUS_RW      = true;

            ClockComponents();

            if (address < 0x2000)// Internal 2K Work RAM (mirrored to 800h-1FFFh)
            {
                return(WRAM[address & 0x7FF]);
            }
            else if (address < 0x4000)
            {
                #region Internal PPU Registers (mirrored to 2008h-3FFFh)
                switch (address & 7)
                {
                case 2:    // $2002
                {
                    ppu_2002_temp = 0;

                    if (vbl_flag)
                    {
                        ppu_2002_temp |= 0x80;
                    }
                    if (spr_0Hit)
                    {
                        ppu_2002_temp |= 0x40;
                    }
                    if (spr_overflow)
                    {
                        ppu_2002_temp |= 0x20;
                    }

                    vbl_flag_temp = false;
                    vram_flipflop = false;

                    // NMI disable effect only at vbl set period (HClock between 1 and 3)
                    if ((VClock == vbl_vclock_Start) && (HClock <= 3))
                    {
                        NMI_Current = (vbl_flag_temp & nmi_enabled);
                    }

                    return(ppu_2002_temp);
                }

                case 4:    // $2004
                {
                    ppu_2004_temp = oam_ram[oam_address];
                    if (VClock < 240 && IsRenderingOn())
                    {
                        if (HClock < 64)
                        {
                            ppu_2004_temp = 0xFF;
                        }
                        else if (HClock < 192)
                        {
                            ppu_2004_temp = oam_ram[((HClock - 64) << 1) & 0xFC];
                        }
                        else if (HClock < 256)
                        {
                            ppu_2004_temp = ((HClock & 1) == 1) ? oam_ram[0xFC] : oam_ram[((HClock - 192) << 1) & 0xFC];
                        }
                        else if (HClock < 320)
                        {
                            ppu_2004_temp = 0xFF;
                        }
                        else
                        {
                            ppu_2004_temp = oam_ram[0];
                        }
                    }
                    return(ppu_2004_temp);
                }

                case 7:    // $2007
                {
                    ppu_2007_temp = 0;

                    if ((vram_address & 0x3F00) == 0x3F00)
                    {
                        // The return value should be from the palettes bank
                        ppu_2007_temp = (byte)(palettes_bank[vram_address & ((vram_address & 0x03) == 0 ? 0x0C : 0x1F)] & grayscale);
                        // fill buffer from chr or nametables
                        vram_address_temp_access1 = vram_address & 0x2FFF;
                        if (vram_address_temp_access1 < 0x2000)
                        {
                            reg2007buffer = board.ReadCHR(ref vram_address_temp_access1, false);
                        }
                        else
                        {
                            reg2007buffer = board.ReadNMT(ref vram_address_temp_access1);
                        }
                    }
                    else
                    {
                        ppu_2007_temp = reg2007buffer;
                        // fill buffer
                        vram_address_temp_access1 = vram_address & 0x3FFF;
                        if (vram_address_temp_access1 < 0x2000)
                        {
                            reg2007buffer = board.ReadCHR(ref vram_address_temp_access1, false);
                        }
                        else if (vram_address_temp_access1 < 0x3F00)
                        {
                            reg2007buffer = board.ReadNMT(ref vram_address_temp_access1);
                        }
                        else
                        {
                            reg2007buffer = palettes_bank[vram_address_temp_access1 & ((vram_address_temp_access1 & 0x03) == 0 ? 0x0C : 0x1F)];
                        }
                    }

                    vram_address = (vram_address + vram_increament) & 0x7FFF;
                    board.OnPPUAddressUpdate(ref vram_address);
                    return(ppu_2007_temp);
                }
                }
                #endregion
            }
            else if (address < 0x4020)
            {
                #region Internal APU Registers
                switch (address)
                {
                case 0x4015:
                {
                    temp_4015 = 0;
                    // Channels enable
                    if (sq1_duration_counter > 0)
                    {
                        temp_4015 |= 0x01;
                    }
                    if (sq2_duration_counter > 0)
                    {
                        temp_4015 |= 0x02;
                    }
                    if (trl_duration_counter > 0)
                    {
                        temp_4015 |= 0x04;
                    }
                    if (noz_duration_counter > 0)
                    {
                        temp_4015 |= 0x08;
                    }
                    if (dmc_dmaSize > 0)
                    {
                        temp_4015 |= 0x10;
                    }
                    // IRQ
                    if (FrameIrqFlag)
                    {
                        temp_4015 |= 0x40;
                    }
                    if (DeltaIrqOccur)
                    {
                        temp_4015 |= 0x80;
                    }

                    FrameIrqFlag = false;
                    IRQFlags    &= ~IRQ_APU;

                    return(temp_4015);
                }

                case 0x4016:
                {
                    temp_4016 = (byte)(PORT0 & 1);

                    PORT0 >>= 1;

                    if (IsZapperConnected)
                    {
                        temp_4016 |= zapper.GetData();
                    }

                    if (IsVSUnisystem)
                    {
                        temp_4016 |= VSUnisystemDIP.GetData4016();
                    }

                    return(temp_4016);
                }

                case 0x4017:
                {
                    temp_4017 = (byte)(PORT1 & 1);

                    PORT1 >>= 1;

                    if (IsZapperConnected)
                    {
                        temp_4017 |= zapper.GetData();
                    }
                    if (IsVSUnisystem)
                    {
                        temp_4017 |= VSUnisystemDIP.GetData4017();
                    }

                    return(temp_4017);
                }
                }
                #endregion
            }
            else if (address < 0x6000)// Cartridge Expansion Area almost 8K
            {
                return(board.ReadEXP(ref address));
            }
            else if (address < 0x8000)// Cartridge SRAM Area 8K
            {
                return(board.ReadSRM(ref address));
            }
            else if (address <= 0xFFFF)// Cartridge PRG-ROM Area 32K
            {
                return(board.ReadPRG(ref address));
            }
            // Should not reach here !
            return(0);
        }
Example #2
0
        public byte Read(int address)
        {
            BUS_RW_P    = BUS_RW;
            BUS_ADDRESS = address;
            BUS_RW      = true;

            #region Clock Components
            this.ppu.Clock();

            /*
             * NMI edge detector polls the status of the NMI line during φ2 of each CPU cycle
             * (i.e., during the second half of each cycle)
             */
            this.interrupts.PollInterruptStatus();
            this.ppu.Clock();
            this.ppu.Clock();
            if (this.emulator.DoPalAdditionalClock)            // In pal system ..
            {
                this.emulator.palCyc++;
                if (this.emulator.palCyc == 5)
                {
                    this.ppu.Clock();
                    this.emulator.palCyc = 0;
                }
            }
            this.apu.Clock();
            this.dma.Clock();

            board.OnCPUClock();
            #endregion

            if (address < 0x2000)            // Internal 2K Work RAM (mirrored to 800h-1FFFh)
            {
                return(WRAM[address & 0x7FF]);
            }
            else if (address < 0x4000)
            {
                #region Internal PPU Registers (mirrored to 2008h-3FFFh)
                switch (address & 7)
                {
                case 2:                        // $2002
                {
                    this.ppu.ppu_2002_temp = 0;

                    if (this.interrupts.vbl_flag)
                    {
                        this.ppu.ppu_2002_temp |= 0x80;
                    }
                    if (this.ppu.spr_0Hit)
                    {
                        this.ppu.ppu_2002_temp |= 0x40;
                    }
                    if (this.ppu.spr_overflow)
                    {
                        this.ppu.ppu_2002_temp |= 0x20;
                    }

                    this.interrupts.vbl_flag_temp = false;
                    this.ppu.vram_flipflop        = false;

                    this.interrupts.CheckNMI();                                    // NMI disable effect only at vbl set period (HClock between 1 and 3)

                    return(this.ppu.ppu_2002_temp);
                }

                case 4:                        // $2004
                {
                    this.ppu.ppu_2004_temp = oam_ram[this.ppu.oam_address];
                    if (this.ppu.VClock < 240 && this.ppu.IsRenderingOn())
                    {
                        if (this.ppu.HClock < 64)
                        {
                            this.ppu.ppu_2004_temp = 0xFF;
                        }
                        else if (this.ppu.HClock < 192)
                        {
                            this.ppu.ppu_2004_temp = oam_ram[((this.ppu.HClock - 64) << 1) & 0xFC];
                        }
                        else if (this.ppu.HClock < 256)
                        {
                            this.ppu.ppu_2004_temp = ((this.ppu.HClock & 1) == 1) ? oam_ram[0xFC] : oam_ram[((this.ppu.HClock - 192) << 1) & 0xFC];
                        }
                        else if (this.ppu.HClock < 320)
                        {
                            this.ppu.ppu_2004_temp = 0xFF;
                        }
                        else
                        {
                            this.ppu.ppu_2004_temp = oam_ram[0];
                        }
                    }
                    return(this.ppu.ppu_2004_temp);
                }

                case 7:                        // $2007
                {
                    this.ppu.ppu_2007_temp = 0;

                    if ((this.ppu.vram_address & 0x3F00) == 0x3F00)
                    {
                        // The return value should be from the palettes bank
                        this.ppu.ppu_2007_temp = (byte)(palettes_bank[this.ppu.vram_address & ((this.ppu.vram_address & 0x03) == 0 ? 0x0C : 0x1F)] & this.ppu.grayscale);
                        // fill buffer from chr or nametables
                        this.ppu.vram_address_temp_access1 = this.ppu.vram_address & 0x2FFF;
                        if (this.ppu.vram_address_temp_access1 < 0x2000)
                        {
                            this.ppu.reg2007buffer = board.ReadCHR(ref this.ppu.vram_address_temp_access1, false);
                        }
                        else
                        {
                            this.ppu.reg2007buffer = board.ReadNMT(ref this.ppu.vram_address_temp_access1);
                        }
                    }
                    else
                    {
                        this.ppu.ppu_2007_temp = this.ppu.reg2007buffer;
                        // fill buffer
                        this.ppu.vram_address_temp_access1 = this.ppu.vram_address & 0x3FFF;
                        if (this.ppu.vram_address_temp_access1 < 0x2000)
                        {
                            this.ppu.reg2007buffer = board.ReadCHR(ref this.ppu.vram_address_temp_access1, false);
                        }
                        else if (this.ppu.vram_address_temp_access1 < 0x3F00)
                        {
                            this.ppu.reg2007buffer = board.ReadNMT(ref this.ppu.vram_address_temp_access1);
                        }
                        else
                        {
                            this.ppu.reg2007buffer = palettes_bank[this.ppu.vram_address_temp_access1 & ((this.ppu.vram_address_temp_access1 & 0x03) == 0 ? 0x0C : 0x1F)];
                        }
                    }

                    this.ppu.vram_address = (this.ppu.vram_address + this.ppu.vram_increament) & 0x7FFF;
                    board.OnPPUAddressUpdate(ref this.ppu.vram_address);
                    return(this.ppu.ppu_2007_temp);
                }
                }
                #endregion
            }
            else if (address < 0x4020)
            {
                #region Internal APU Registers
                switch (address)
                {
                case 0x4015:
                {
                    temp_4015 = 0;
                    // Channels enable
                    if (this.apu.pulse1Channel.Duration_counter > 0)
                    {
                        temp_4015 |= 0x01;
                    }
                    if (this.apu.pulse2Channel.Duration_counter > 0)
                    {
                        temp_4015 |= 0x02;
                    }
                    if (this.apu.triangleChannel.Duration_counter > 0)
                    {
                        temp_4015 |= 0x04;
                    }
                    if (this.apu.noiseChannel.Duration_counter > 0)
                    {
                        temp_4015 |= 0x08;
                    }
                    if (this.apu.dmcChannel.dmc_dmaSize > 0)
                    {
                        temp_4015 |= 0x10;
                    }
                    // IRQ
                    if (this.apu.FrameIrqFlag)
                    {
                        temp_4015 |= 0x40;
                    }
                    if (this.apu.dmcChannel.DeltaIrqOccur)
                    {
                        temp_4015 |= 0x80;
                    }

                    this.apu.FrameIrqFlag = false;
                    Interrupts.IRQFlags  &= ~Interrupts.IRQ_APU;

                    return(temp_4015);
                }

                case 0x4016:
                {
                    temp_4016 = (byte)(this.input.PORT0 & 1);

                    this.input.PORT0 >>= 1;

                    if (this.input.IsZapperConnected)
                    {
                        temp_4016 |= this.input.zapper.GetData();
                    }

                    if (this.legacy.IsVSUnisystem)
                    {
                        temp_4016 |= this.input.VSUnisystemDIP.GetData4016();
                    }

                    return(temp_4016);
                }

                case 0x4017:
                {
                    temp_4017 = (byte)(this.input.PORT1 & 1);

                    this.input.PORT1 >>= 1;

                    if (this.input.IsZapperConnected)
                    {
                        temp_4017 |= this.input.zapper.GetData();
                    }
                    if (this.legacy.IsVSUnisystem)
                    {
                        temp_4017 |= this.input.VSUnisystemDIP.GetData4017();
                    }

                    return(temp_4017);
                }
                }
                #endregion
            }
            else if (address < 0x6000)            // Cartridge Expansion Area almost 8K
            {
                return(board.ReadEXP(ref address));
            }
            else if (address < 0x8000)            // Cartridge SRAM Area 8K
            {
                return(board.ReadSRM(ref address));
            }
            else if (address <= 0xFFFF)            // Cartridge PRG-ROM Area 32K
            {
                return(board.ReadPRG(ref address));
            }
            // Should not reach here !
            return(0);
        }