コード例 #1
0
ファイル: NesBus.cs プロジェクト: davignola/olcNESharp
        public byte CpuRead(ushort address, bool asReadOnly)
        {
            byte data = 0x00;

            // Cartridge Address Range
            if (Cartridge.CpuRead(address, ref data)) { return data; }


            if (address >= 0x0000 && address <= 0x1FFF)
            {
                // System RAM Address Range, mirrored every 2048
                data = Ram[address & 0x07FF];
            }
            else if (address >= 0x2000 && address <= 0x3FFF)
            {
                // PPU Address range, mirrored every 8
                data = Ppu2C02.CpuRead((ushort)(address & 0x0007), asReadOnly);
            }
            else if (address == 0x4015)
            {
                // APU Read Status
                data = Apu2A03.CpuRead(address, asReadOnly);
            }
            else if (address >= 0x4016 && address <= 0x4017)
            {
                // Read out the MSB of the controller status word
                data = (ControllerState[address & 0x0001] & 0x80) > 0 ? 1 : 0;
                ControllerState[address & 0x0001] <<= 1;
            }

            return data;
        }
コード例 #2
0
ファイル: NesBus.cs プロジェクト: davignola/olcNESharp
        public void CpuWrite(ushort address, byte data)
        {
            // The cartridge "sees all" and has the facility to veto
            // the propagation of the bus transaction if it requires.
            // This allows the cartridge to map any address to some
            // other data, including the facility to divert transactions
            // with other physical devices. The NES does not do this
            // but I figured it might be quite a flexible way of adding
            // "custom" hardware to the NES in the future!
            if (Cartridge.CpuWrite(address, data)) { return; }

            if (address >= 0x0000 && address <= 0x1FFF)
            {
                // System RAM Address Range. The range covers 8KB, though
                // there is only 2KB available. That 2KB is "mirrored"
                // through this address range. Using bitwise AND to mask
                // the bottom 11 bits is the same as addr % 2048.
                Ram[address & 0x07FF] = data;
            }
            else if (address >= 0x2000 && address <= 0x3FFF)
            {
                // PPU Address range. The PPU only has 8 primary registers
                // and these are repeated throughout this range. We can
                // use bitwise AND operation to mask the bottom 3 bits, 
                // which is the equivalent of addr % 8.
                Ppu2C02.CpuWrite((ushort)(address & 0x0007), data);
            }
            else if ((address >= 0x4000 && address <= 0x4013) || address == 0x4015 || address == 0x4017) //  NES APU
            {
                Apu2A03.CpuWrite(address, data);
            }
            else if (address == 0x4014)
            {
                // A write to this address initiates a DMA transfer
                dma_page = data;
                dma_addr = 0x00;
                dma_transfer = true;
            }
            else if (address >= 0x4016 && address <= 0x4017)
            {
                // "Lock In" controller state at this time
                ControllerState[address & 0x0001] = Controller[address & 0x0001];
            }
        }
コード例 #3
0
ファイル: NesBus.cs プロジェクト: davignola/olcNESharp
        public NesBus()
        {
            Devices = new List<IResetableDevice>();

            // Connect devices
            Cpu6502 = new Cpu6502();
            Cpu6502.ConnectBus(this);
            Devices.Add(Cpu6502);

            Ppu2C02 = new Ppu2C02();
            Ppu2C02.ConnectBus(this);
            Devices.Add(Ppu2C02);

            Apu2A03 = new Apu2A03();
            Apu2A03.ConnectBus(this);
            Devices.Add(Apu2A03);

            // init 2k RAM
            Ram = Enumerable.Repeat((byte)0, 2 * 1024).ToList();

            // Controlers
            Controller = new byte[] { 0x00, 0x00 };
            ControllerState = new byte[] { 0x00, 0x00 };
        }
コード例 #4
0
ファイル: NesBus.cs プロジェクト: davignola/olcNESharp
        public bool Clock()
        {
            // Clocking. The heart and soul of an emulator. The running
            // frequency is controlled by whatever calls this function.
            // So here we "divide" the clock as necessary and call
            // the peripheral devices clock() function at the correct
            // times.

            // The fastest clock frequency the digital system cares
            // about is equivalent to the PPU clock. So the PPU is clocked
            // each time this function is called...
            Ppu2C02.Clock();

            // ...also clock the APU
            Apu2A03.Clock();

            // The CPU runs 3 times slower than the PPU so we only call its
            // clock() function every 3 times this function is called. We
            // have a global counter to keep track of this.
            if (SystemClockCounter % 3 == 0)
            {
                // Is the system performing a DMA transfer form CPU memory to 
                // OAM memory on PPU?...
                if (dma_transfer)
                {
                    // ...Yes! We need to wait until the next even CPU clock cycle
                    // before it starts...
                    if (dma_dummy)
                    {
                        // ...So hang around in here each clock until 1 or 2 cycles
                        // have elapsed...
                        if (SystemClockCounter % 2 == 1)
                        {
                            // ...and finally allow DMA to start
                            dma_dummy = false;
                        }
                    }
                    else
                    {
                        // DMA can take place!
                        if (SystemClockCounter % 2 == 0)
                        {
                            // On even clock cycles, read from CPU bus
                            dma_data = CpuRead((ushort)(dma_page << 8 | dma_addr), false);
                        }
                        else
                        {
                            // On odd clock cycles, write to PPU OAM
                            Ppu2C02.OAM[dma_addr] = dma_data;
                            // Increment the lo byte of the address
                            dma_addr++;
                            // If this wraps around, we know that 256
                            // bytes have been written, so end the DMA
                            // transfer, and proceed as normal
                            if (dma_addr == 0x00)
                            {
                                dma_transfer = false;
                                dma_dummy = true;
                            }
                        }
                    }
                }
                else
                {
                    // No DMA happening, the CPU is in control of its
                    // own destiny. Go forth my friend and calculate
                    // awesomeness for many generations to come...
                    Cpu6502.Clock();
                }
            }

            // Synchronising with Audio
            bool bAudioSampleReady = false;
            dAudioTime += dAudioTimePerNESClock;
            if (dAudioTime >= dAudioTimePerSystemSample)
            {
                dAudioTime -= dAudioTimePerSystemSample;
                dAudioSample = Apu2A03.GetOutputSample();
                bAudioSampleReady = true;
            }


            // The PPU is capable of emitting an interrupt to indicate the
            // vertical blanking period has been entered. If it has, we need
            // to send that irq to the CPU.
            if (Ppu2C02.Nmi)
            {
                Ppu2C02.Nmi = false;
                Cpu6502.NMI();
            }

            // Check if cartridge is requesting IRQ
            if (Cartridge.GetMapper().IrqState)
            {
                Cartridge.GetMapper().IrqClear();
                Cpu6502.IRQ();
            }

            SystemClockCounter++;

            return bAudioSampleReady;
        }
コード例 #5
0
ファイル: NesBus.cs プロジェクト: davignola/olcNESharp
 public void InsertCartridge(Cartridge cartridge)
 {
     Cartridge = cartridge;
     Ppu2C02.ConnectCartridge(cartridge);
     Devices.Add(Cartridge);
 }