public Renderer(PPU ppu, FrameSink destination, long offset) { fs = destination; PPU = ppu; ppu.Mode = Mode.OAMSearch; fetcher = new PixelFetcher(PPU); TimeUntilWhichToPause += offset; }
public PPU(Action enableVBlankInterrupt, Action enableLCDCStatusInterrupt, FrameSink frameSink) { OAM = new OAM(); VRAM = new VRAM(); EnableVBlankInterrupt = enableVBlankInterrupt; EnableLCDCStatusInterrupt = enableLCDCStatusInterrupt; Writer = frameSink; }
public Core(byte[] gameROM, byte[]?bootROM, Keypad Keypad, FrameSink frameSink) { if (gameROM.Length < 0x8000) { throw new Exception("Cartridge file has to be at least 8kb in size"); } PC = new(); InterruptRegisters = new InterruptRegisters(); Keypad.Input.KeyWentDown += InterruptRegisters.TriggerEvent; APU = new APU(32768); PPU = new PPU(InterruptRegisters.EnableVBlankInterrupt, InterruptRegisters.EnableLCDSTATInterrupt, frameSink); Timers = new Timers(InterruptRegisters.EnableTimerInterrupt); var ioRegisters = SetupControlRegisters(Keypad); CartHeader Header = new CartHeader(gameROM); MBC Card; if (Header.HasBattery()) { var mmf = Header.MakeMemoryMappedFile(); Card = Header.HasClock() ? Header.MakeMBC(gameROM, mmf, () => masterclock) : Header.MakeMBC(gameROM, mmf); } else { Card = Header.MakeMBC(gameROM); } //Writing out the RTC too often would be very heavy. This writes it out once per frame. // if (Header.Type == CartType.MBC3_TIMER_RAM_BATTERY) { var SaveRTC = ((MBC3)Card).SaveRTC(); void h(object?x, EventArgs y) => SaveRTC(); frameSink.FramePushed += h; } if (Card is MBC5WithRumble rumble) { rumble.RumbleStateChange += Keypad.ToggleRumble; } Memory = new MMU( bootROM, Card, PPU.VRAM, PPU.OAM, ioRegisters, (x => InterruptRegisters.InterruptControlRegister = x, () => InterruptRegisters.InterruptControlRegister), PC ); CPU = new CPU(Memory, InterruptRegisters, PC); ioRegisters[0x0f] = InterruptRegisters.HookUp(); ioRegisters[0x50] = Memory.HookUpMemory(); //We have to replicate the state of the system post boot without running the bootrom if (bootROM == null) { //registers CPU.SetStateWithoutBootrom(); //timers Timers.SetStateWithoutBootrom(); //sound APU.SetStateWithoutBootrom(); //graphics TODO: we can't really set up the graphics environment correctly //because we will have to also initialize the internal renderer state correctly PPU.SetStateWithoutBootrom(); InterruptRegisters.SetStateWithoutBootrom(); } }