private static Emulator Boot() { var ppuRegs = new PPURegisters(); var memoryBus = new MemoryBus(ppuRegs) { IsBootRomMapped = useBootRom }; //memoryBus.Attach(new GameLinkConsole()); var ppu = new PPU(ppuRegs, memoryBus); ppu.Boot(); var cpu = new CPU(new Registers(), memoryBus); if (!useBootRom) { cpu.BootWithoutBootRom(); } var rom = Cartridge.LoadFrom(romPath); memoryBus.Load(rom); var joypad = new Joypad(memoryBus.JoypadRegister); return(new Emulator(cpu, ppu, joypad)); }
public NESRawMemoryMap(PPURegisters ppuRegisters, InputHandler inputHandler) : base() { this.ppuRegisters = ppuRegisters; this.inputHandler = inputHandler; this.ppuRegisterLookup = new Dictionary <int, Register8Bit>() { { PPURegisterAddresses.PPUCTRL, ppuRegisters.PPUCTRL }, { PPURegisterAddresses.PPUMASK, ppuRegisters.PPUMASK }, { PPURegisterAddresses.PPUSTATUS, ppuRegisters.PPUSTATUS }, { PPURegisterAddresses.OAMADDR, ppuRegisters.OAMADDR }, { PPURegisterAddresses.OAMDATA, ppuRegisters.OAMDATA }, { PPURegisterAddresses.PPUADDR, ppuRegisters.PPUADDR }, { PPURegisterAddresses.PPUDATA, ppuRegisters.PPUDATA }, { PPURegisterAddresses.OAMDMA, ppuRegisters.OAMDMA } }; this.apuRegisterLookup = new Dictionary <int, Register8Bit>() { { APURegisterAddresses.Pulse1TimerLow, null }, { APURegisterAddresses.Pulse1TimerHigh, null }, { APURegisterAddresses.Pulse2TimerLow, null }, { APURegisterAddresses.Pulse2TimerHigh, null }, { APURegisterAddresses.DirectLoad, null }, { APURegisterAddresses.ChannelStatus, null }, { APURegisterAddresses.TriangleTimerLow, null }, { APURegisterAddresses.TriangleTimerHigh, null }, }; this.inputHandler.ControllerChanged += this.OnControllerChanged; }
public SpriteHandler( IPPUMemoryMap ppuMemoryMap, PPURegisters registers, PaletteHandler paletteHandler) { this.registers = registers; this.ppuMemoryMap = ppuMemoryMap; this.paletteHandler = paletteHandler; }
private static void Start(string romPath) { var ppuRegs = new PPURegisters(); var memoryBus = new MemoryBus(ppuRegs); ppu = new PPU(ppuRegs, memoryBus); cpu = new CPU(new Registers(), memoryBus); cpu.BootWithoutBootRom(); var rom = Cartridge.LoadFrom(romPath); memoryBus.Load(rom); }
public void Generate_Expected_Background_Map_Pixels_From_Known_VRAM_Dump_Using_Unsigned_Tile_Numbers() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "tetris_title_screen.vram.dump")); var regs = new PPURegisters(lcdc: 0xD3, bgPalette: 0xE4); var memBus = new MemoryBus(regs) { VideoMemory = vram }; var ppu = new PPU(regs, memBus); ppu.TileSet.UpdateFrom(vram); var actualPixels = ppu.RenderBackgroundMap(); var expectedPixels = ImageHelper.LoadImageAsPaletteIndexedByteArray(Path.Combine("PPU", "Expected", "tetris_title_screen_expected_bgmap.png")); AssertPixelsMatch(expectedPixels, actualPixels, width: 256); }
public void Generate_Blank_Background_Map_Pixels_When_Background_Map_Drawing_Is_Disabled() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "pokemon_reds_room.vram.dump")); var regs = new PPURegisters(lcdc: 0xE0); //LCDC bit 0 = 0 => background is disabled var memBus = new MemoryBus(regs) { VideoMemory = vram }; var ppu = new PPU(regs, memBus); Assert.IsFalse(ppu.Registers.LCDControl.BackgroundDisplayEnabled); var actualPixels = ppu.RenderBackgroundMap(); var expectedPixels = new byte[TileMap.WidthInPixels * TileMap.HeightInPixels]; AssertPixelsMatch(expectedPixels, actualPixels, width: 256); }
public void Generate_Blank_Sprite_Pixels_When_Sprite_Drawing_Is_Disabled() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "pokemon_reds_room.vram.dump")); var oam = Memory.FromFile(Path.Combine("PPU", "Input", "pokemon_reds_room.oam.dump")); var regs = new PPURegisters(lcdc: 0xE3, spritePalette0: 0xE4, spritePalette1: 0xE4); var memBus = new MemoryBus(regs) { VideoMemory = vram, ObjectAttributeMemory = oam }; var ppu = new PPU(regs, memBus); ppu.Registers.LCDControl.SpriteDisplayEnabled = false; var actualPixels = ppu.RenderSprites(); var expectedPixels = new byte[PPU.ScreenWidthInPixels * PPU.ScreenHeightInPixels]; AssertPixelsMatch(expectedPixels, actualPixels, width: PPU.ScreenWidthInPixels); }
public void Generate_Blank_Window_Pixels_When_Window_Drawing_Is_Disabled() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "links_awakening_you_are_on_koholint_island.vram.dump")); var regs = new PPURegisters(lcdc: 0xD7); //LCDC bit 5 = 0 => window is disabled var memBus = new MemoryBus(regs) { VideoMemory = vram }; var ppu = new PPU(regs, memBus); Assert.IsFalse(ppu.Registers.LCDControl.WindowDisplayEnabled); var actualPixels = ppu.RenderWindow(); var expectedPixels = new byte[TileMap.WidthInPixels * TileMap.HeightInPixels]; AssertPixelsMatch(expectedPixels, actualPixels, width: 256); }
public void Generate_Expected_Window_Pixels_From_Known_VRAM_Dump_Using_Signed_Tile_Numbers() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "links_awakening_you_are_on_koholint_island.vram.dump")); var regs = new PPURegisters(lcdc: 0xE7, bgPalette: 0xE4); var memBus = new MemoryBus(regs) { VideoMemory = vram }; var ppu = new PPU(regs, memBus); ppu.TileSet.UpdateFrom(vram); var actualPixels = ppu.RenderWindow(); var expectedPixels = ImageHelper.LoadImageAsPaletteIndexedByteArray(Path.Combine("PPU", "Expected", "links_awakening_you_are_on_koholint_island_expected_window.png")); AssertPixelsMatch(expectedPixels, actualPixels, width: 256); }
public void Generate_Expected_Tileset_Pixels_From_Known_VRAM_Dump() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "tetris.tileset.dump")); var regs = new PPURegisters(); var memBus = new MemoryBus(regs) { VideoMemory = vram }; var ppu = new PPU(regs, memBus); ppu.TileSet.UpdateFrom(vram); var actualPixels = ppu.RenderTileSet(); var expectedPixels = ImageHelper.LoadImageAsPaletteIndexedByteArray(Path.Combine("PPU", "Expected", "tetris.tileset.png")); AssertPixelsMatch(expectedPixels, actualPixels, width: TileSet.WidthInPixels); }
public BackgroundHandler( IPPUMemoryMap ppuMemoryMap, PPURegisters registers, PPUInternalRegisters internalRegisters, ScrollHandler scrollHandler, PaletteHandler paletteHandler) { this.registers = registers; this.ppuMemoryMap = ppuMemoryMap; this.scrollHandler = scrollHandler; this.paletteHandler = paletteHandler; this.internalRegisters = internalRegisters; foreach (var patternTable in this.ppuMemoryMap.GetMemorySegments <PatternTable>()) { if (patternTable.Range.Min == 0x0000) { this.patternTable0 = patternTable; } else if (patternTable.Range.Min == 0x1000) { this.patternTable1 = patternTable; } } foreach (var nameTable in this.ppuMemoryMap.GetMemorySegments <Nametable>()) { if (nameTable.Range.Min == 0x2000) { this.nameTable0 = nameTable; } else if (nameTable.Range.Min == 0x2400) { this.nameTable1 = nameTable; } else if (nameTable.Range.Min == 0x2800) { this.nameTable2 = nameTable; } else if (nameTable.Range.Min == 0x2C00) { this.nameTable3 = nameTable; } } }
public void Generate_Expected_Sprite_Pixels_From_Known_VRAM_And_OAM_Dumps() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "tetris_title_screen.vram.dump")); var oam = Memory.FromFile(Path.Combine("PPU", "Input", "tetris_title_screen.oam.dump")); var regs = new PPURegisters(lcdc: 0xD3, spritePalette0: 0xFF, spritePalette1: 0xFF); var memBus = new MemoryBus(regs) { VideoMemory = vram, ObjectAttributeMemory = oam }; var ppu = new PPU(regs, memBus); ppu.TileSet.UpdateFrom(vram); ppu.Sprites.UpdateFrom(oam); var actualPixels = ppu.RenderSprites(); var expectedPixels = ImageHelper.LoadImageAsPaletteIndexedByteArray(Path.Combine("PPU", "Expected", "tetris_title_screen_expected_sprites.png")); AssertPixelsMatch(expectedPixels, actualPixels, width: PPU.ScreenWidthInPixels); }
public void Generate_Expected_Screen_Pixels_From_Known_Memory_Dump_When_Sprite_Drawing_Is_Disabled_But_Background_Drawing_Is_Enabled() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "pokemon_reds_room.vram.dump")); var oam = Memory.FromFile(Path.Combine("PPU", "Input", "pokemon_reds_room.oam.dump")); //magic numbers in PPU registers collected from bgb at the point the above memory dumps were captured var regs = new PPURegisters(lcdc: 0xE3, scrollY: 0xD0, windowX: 0x07, windowY: 0x90, bgPalette: 0xE4, spritePalette0: 0xD0, spritePalette1: 0xE0); var memBus = new MemoryBus(regs) { VideoMemory = vram, ObjectAttributeMemory = oam }; var ppu = new PPU(regs, memBus); ppu.TileSet.UpdateFrom(vram); ppu.Registers.LCDControl.SpriteDisplayEnabled = false; var actualPixels = ppu.ForceRenderScreen(); var expectedPixels = ImageHelper.LoadImageAsPaletteIndexedByteArray(Path.Combine("PPU", "Expected", "pokemon_reds_room_expected_screen_wo_sprites.png")); AssertPixelsMatch(expectedPixels, actualPixels, width: PPU.ScreenWidthInPixels); }
public void Generate_Expected_Screen_Pixels_From_Known_VRAM_And_OAM_Dumps_With_Background_And_8_x_16_Sprites_And_Window() { var vram = Memory.FromFile(Path.Combine("PPU", "Input", "links_awakening_you_are_on_koholint_island.vram.dump")); var oam = Memory.FromFile(Path.Combine("PPU", "Input", "links_awakening_you_are_on_koholint_island.oam.dump")); //magic numbers in PPU registers collected from bgb at the point the above memory dumps were captured var regs = new PPURegisters(lcdc: 0xE7, windowX: 0x06, windowY: 0x80, bgPalette: 0xE4, spritePalette0: 0x1C, spritePalette1: 0xE4); var memBus = new MemoryBus(regs) { VideoMemory = vram, ObjectAttributeMemory = oam }; var ppu = new PPU(regs, memBus); ppu.TileSet.UpdateFrom(vram); ppu.Sprites.UpdateFrom(oam); var actualPixels = ppu.ForceRenderScreen(); var expectedPixels = ImageHelper.LoadImageAsPaletteIndexedByteArray(Path.Combine("PPU", "Expected", "links_awakening_you_are_on_koholint_island_expected_screen.png")); AssertPixelsMatch(expectedPixels, actualPixels, width: PPU.ScreenWidthInPixels); }
public NESMemoryMapSlim(PPURegisters ppuRegisters, InputHandler inputHandler) : base() { this.ppuRegisters = ppuRegisters; this.inputHandler = inputHandler; this.sram = new SRAM(MemoryRanges.SRAM, "SRAM"); this.stack = new CPU.MOS6502.Stack(MemoryRanges.Stack, "Stack"); this.prgROMLowerBank = new ExternalFacade(this, MemoryRanges.ProgramRomLowerBank, Constants.ProgramRomLowerBank); this.prgROMUpperBank = new ExternalFacade(this, MemoryRanges.ProgramRomUpperBank, Constants.ProgramRomUpperBank); this.ppuRegisterLookup = new Dictionary <int, Register8Bit>() { { PPURegisterAddresses.PPUCTRL, ppuRegisters.PPUCTRL }, { PPURegisterAddresses.PPUMASK, ppuRegisters.PPUMASK }, { PPURegisterAddresses.PPUSTATUS, ppuRegisters.PPUSTATUS }, { PPURegisterAddresses.OAMADDR, ppuRegisters.OAMADDR }, { PPURegisterAddresses.OAMDATA, ppuRegisters.OAMDATA }, { PPURegisterAddresses.PPUADDR, ppuRegisters.PPUADDR }, { PPURegisterAddresses.PPUDATA, ppuRegisters.PPUDATA }, { PPURegisterAddresses.OAMDMA, ppuRegisters.OAMDMA } }; this.apuRegisterLookup = new Dictionary <int, Register8Bit>() { { APURegisterAddresses.Pulse1TimerLow, null }, { APURegisterAddresses.Pulse1TimerHigh, null }, { APURegisterAddresses.Pulse2TimerLow, null }, { APURegisterAddresses.Pulse2TimerHigh, null }, { APURegisterAddresses.DirectLoad, null }, { APURegisterAddresses.ChannelStatus, null }, { APURegisterAddresses.TriangleTimerLow, null }, { APURegisterAddresses.TriangleTimerHigh, null }, }; this.inputHandler.ControllerChanged += this.OnControllerChanged; this.ScopeMemoryRanges(); }
public ScrollHandler(PPURegisters registers, PPUInternalRegisters internalRegisters) { this.registers = registers; this.internalRegisters = internalRegisters; }