internal MemoryHandler(GameBoy gameboy) { this.gameboy = gameboy; this.memory = (Memory)gameboy.Memory; this.cartridge = (Cartridge.Cartridge)gameboy.Cartridge; this.cpu = (CPU)gameboy.CPU; this.display = (Display)gameboy.Display; this.apu = (APU)gameboy.APU; }
/// <summary> /// Class constructor. Performs the loading of the current cartridge into memory. /// </summary> /// <param name="gameboy"></param> internal RomOnlyMemoryHandler(GameBoy gameboy) : base(gameboy) { // We get the memory pointer byte[] memoryData = memory.MemoryData; Buffer.BlockCopy(this.cartridge.Data, romOnlyStart, memoryData, romOnlyStart, Math.Min(this.cartridge.Data.Length, romOnlyLength)); }
internal APU(GameBoy gameboy, Memory memory, int sampleRate, int numChannels, int sampleSize) { _gameboy = gameboy; _memory = memory; _sampleRate = sampleRate; _msSampleRate = _sampleRate / 1000; _numChannels = numChannels; _sampleSize = sampleSize; Reset(); }
public void ProgramCounterIncrementation() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.Cpu.Registers.PC.Value = 0x0000; // Act + assert gameboy.Cpu.Cycle(); Assert.That(gameboy.Cpu.Registers.PC.Value == 0x0001); gameboy.Cpu.Cycle(); Assert.That(gameboy.Cpu.Registers.PC.Value == 0x0002); gameboy.Cpu.Cycle(); Assert.That(gameboy.Cpu.Registers.PC.Value == 0x0003); }
public void CacheState(GameBoy gb, string name, System.Action fn) { string state = CachedStatesDirectory + "/" + name + ".gqs"; if (!CacheCleared && File.Exists(state)) { gb.LoadState(state); } else { fn(); gb.SaveState(state); } ulong cc = gb.EmulatedSamples; TimeSpan time = TimeSpan.FromSeconds((double)cc / 2097152.0); Console.WriteLine("{0}: {1} ({2:n0})", name, time.ToString(@"hh\:mm\:ss\.ff"), cc); }
public void Op0x21_NNIsLoadedIntoRegisterHL() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); gameboy.Mmu.WriteByte(gameboy.Cpu.Registers.PC.Value, 0x21); gameboy.Mmu.WriteByte((ushort)(gameboy.Cpu.Registers.PC.Value + 1), 0x34); gameboy.Mmu.WriteByte((ushort)(gameboy.Cpu.Registers.PC.Value + 2), 0x12); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Cpu.Registers.HL.Value == 0x1234); }
public void Op0x70_DoesSomethingUseful() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); gameboy.Cpu.Registers.PC.Value = 0; // gameboy.Mmu.WriteByte(0x00, 0x00; // gameboy.Mmu.WriteByte(0x01, 0x00; // Act gameboy.Cpu.Cycle(); // Assert // Assert.That(true); }
public void Op0x01_NNIsLoadedIntoRegisterBC() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); const byte nn = 12; gameboy.Mmu.WriteByte(gameboy.Cpu.Registers.PC.Value, 0x01); gameboy.Mmu.WriteByte((ushort)(gameboy.Cpu.Registers.PC.Value + 1), nn); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Cpu.Registers.BC.Value == nn); }
public void Emulation_in_release_mode_must_be_at_least_twice_as_fast_as_real_gameboy() { #if DEBUG var expectedPerformance = 100.0; #else var expectedPerformance = 50.0; #endif var gameBoy = new GameBoy("PerformanceTests/Roms/cpu_instrs_looped.gb"); Stopwatch stopWatch = new Stopwatch(); if (!Stopwatch.IsHighResolution) { Assert.Fail("No high res timer available in system!"); } stopWatch.Start(); var multiplier = 10000; var cycle = 0; var cycles = 17556 * multiplier; while (cycle++ < cycles) { gameBoy.AdvanceMachineCycle(JoypadState.None); } stopWatch.Stop(); var actualPerformance = 100 * stopWatch.ElapsedMilliseconds / (16.74 * multiplier); Console.WriteLine($"Performance: {actualPerformance}%"); if (actualPerformance < expectedPerformance) { Assert.Pass($"RunTime: {actualPerformance}%"); } else { Assert.Fail($"RunTime: {actualPerformance}% is worse than expected runtime: {expectedPerformance}%"); } }
private void loadRomToolStripMenuItem_Click(object sender, EventArgs e) { Thread thread_bug = new Thread(new ThreadStart( delegate { Control.CheckForIllegalCrossThreadCalls = false; //m_cartridge.Init("..//rom//ld.gb"); System.Windows.Forms.OpenFileDialog openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); openFileDialog1.InitialDirectory = "."; openFileDialog1.Filter = "GB files(*.gb,*.gbc)|*.gb;*.gbc|All files (*.*)|*.*"; openFileDialog1.FilterIndex = 0; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { GameBoy.LoadCartridge(openFileDialog1.FileName, openFileDialog1.SafeFileName, true); } })); thread_bug.SetApartmentState(ApartmentState.STA); /*<=*/ thread_bug.Start(); }
/// <summary> /// Class constructor. Performs the loading of the current cartridge into memory. /// </summary> /// <param name="gameboy"></param> internal MBC3MemoryHandler(GameBoy gameboy) : base(gameboy) { _state.CurrentRamBank = 0; _state.CurrentRomBank = 0; _state.RamBanksData = new byte[0x8000]; // 32768 bytes _romBanksData = new byte[0x200000]; // 2097152 bytes // We get the memory pointer byte[] memoryData = memory.MemoryData; // Copy ROM banks Buffer.BlockCopy(this.cartridge.Data, romBank0Start, _romBanksData, romBank0Start, Math.Min(this.cartridge.Data.Length, _romBanksData.Length)); // Copy first and second ROM banks Buffer.BlockCopy(this.cartridge.Data, romBank0Start, memoryData, romBank0Start, Math.Min(this.cartridge.Data.Length, romBankLength * 2)); }
public void Op0x5001_DisB() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); //gameboy.Memory.Init(0xFFFF); gameboy.Cpu.Registers.PC.Value = 0x00; gameboy.Cpu.Registers.B.Value = 0xAA; gameboy.Mmu.WriteByte(0x00, 0x50); gameboy.Mmu.WriteByte(0x01, 0x01); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Cpu.Registers.D.Value == 0xAA); Assert.That(gameboy.Cpu.Registers.D.Value == gameboy.Cpu.Registers.B.Value); }
public void Op0xAF_A0xFF_WipesA() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); gameboy.Cpu.Registers.A.Value = 0xFF; gameboy.Cpu.Registers.PC.Value = 0x00; gameboy.Mmu.WriteByte(0x00, 0xAF); gameboy.Mmu.WriteByte(0x01, 0x00); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Cpu.Registers.A.Value == 0x00); }
private void loadRomToolStripMenuItem_Click(object sender, EventArgs e) { Thread thread_bug = new Thread(new ThreadStart( delegate { Control.CheckForIllegalCrossThreadCalls = false; //m_cartridge.Init("..//rom//ld.gb"); OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.InitialDirectory = "."; openFileDialog1.Filter = "rom files(*.gb)|*.gb|All files (*.*)|*.*"; openFileDialog1.FilterIndex = 2; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { String s = openFileDialog1.FileName; GameBoy.LoadCartridge(s); } })); thread_bug.SetApartmentState(ApartmentState.STA); /*<=*/ thread_bug.Start(); }
public SDLThread(IntPtr Handle, IntPtr pgHandle, GameBoy owner) { this.owner = owner; int success = SDL_Init(SDL_INIT_VIDEO); if (success < 0) throw new SDLException(); Window = SDL_CreateWindow("LameBoy", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 720, SDL_WindowFlags.SDL_WINDOW_BORDERLESS); if (Window == null) throw new SDLException(); IntPtr rtHandle = this.Handle; Surface = SDL_GetWindowSurface(Window); Renderer = SDL_GetRenderer(Window); SetWindowPos(rtHandle, Handle, 0, 0, 0, 0, 0x0401); //0x400 = SHOWWINDOW SetParent(rtHandle, pgHandle); ShowWindow(rtHandle, 1); running = true; }
public void Op0x66_PointTo0xBBHIs0xBB() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); gameboy.Cpu.Registers.PC.Value = 0x00; gameboy.Cpu.Registers.HL.Value = 0xFF00; gameboy.Mmu.WriteByte(0x00, 0x66); gameboy.Mmu.WriteByte(0x01, 0x00); gameboy.Mmu.WriteByte(0xFF00, 0xBB); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Cpu.Registers.H.Value == 0xBB); }
static void Main(string[] args) { XmlSerializer xmls = new XmlSerializer(typeof(Opcode[][])); using (var ms = new MemoryStream(Encoding.ASCII.GetBytes(Properties.Resources.opcode_dict))) { var temp = ((Opcode[][])xmls.Deserialize(ms)); Opcodes = temp[0].Select(o => new RegexOpcode(o, null)).Concat(temp[1].Select(o => new RegexOpcode(o, 0xCB))).ToArray(); } if (Debugger.IsAttached) { args = new[] { "test_sections.asm", "test_sections.bin" } } ; //args = new[] { "-d", "test.bin", "test_d.asm" }; if (args[0] == "-d") { var data = File.ReadAllBytes(args[1]); var disassembled = Disassembler.Disassemble(data, true, false, true, true); File.WriteAllText(args[2], disassembled); } else { var code = File.ReadAllText(args[0]); var assembled = Assembler.Assemble(code); File.WriteAllBytes(args[1], assembled); if (Debugger.IsAttached) { var gb = new GameBoy(assembled); gb.Start(); } } } }
/// <summary> /// Creates a MemoryHandler the matches the CartridgeType. /// </summary> /// <param name="gameboy">A reference to a gameboy with a loaded catridge.</param> /// <returns>A MemoryHandler instance</returns> internal static MemoryHandler CreateMemoryHandler(GameBoy gameboy) { switch (gameboy.Cartridge.Type) { case CartridgeType.ROM_ONLY: case CartridgeType.ROM_RAM: return new RomOnlyMemoryHandler(gameboy); case CartridgeType.ROM_MBC1: case CartridgeType.ROM_MBC1_RAM: return new MBC1MemoryHandler(gameboy); case CartridgeType.ROM_MBC1_RAM_BATT: return new MBC1MemoryHandler(gameboy, true); case CartridgeType.ROM_MBC3: case CartridgeType.ROM_MBC3_RAM: case CartridgeType.ROM_MBC3_RAM_BATT: case CartridgeType.ROM_MBC3_TIMER_BATT: case CartridgeType.ROM_MBC3_TIMER_RAM_BATT: return new MBC3MemoryHandler(gameboy); } // TODO(Cristián): Implement logic for different CartridgeType return null; }
private static string ExecuteRom(string testRom, string expectedHash) { string hash = string.Empty; using (var framesink = new TestVideoFrameSink()) { var gameboy = new GameBoy(framesink, new NullInputSource()); gameboy.LoadRom(File.ReadAllBytes(testRom)); int framesRun = 0; do { gameboy.RunFrame(); hash = framesink.HashFrame(); } while (++framesRun < Config.FrameLimit && hash != expectedHash); framesink.SaveFrameAsPng(Path.ChangeExtension(testRom, "png")); } return(hash); }
/// <summary> /// Class constructor. Performs the loading of the current cartridge into memory. /// </summary> /// <param name="gameboy"></param> internal MBC1MemoryHandler(GameBoy gameboy, bool hasBattery = false) : base(gameboy) { _state.CurrentRamBank = 0; _state.CurrentRomBank = 1; _state.RamBanksData = new byte[0x8000]; // 32768 bytes _romBanksData = new byte[0x200000]; // 2097152 bytes // We obtain the memory pointer byte[] memoryData = memory.MemoryData; // Copy ROM banks Buffer.BlockCopy(this.cartridge.Data, romBank0Start, _romBanksData, romBank0Start, Math.Min(this.cartridge.Data.Length, _romBanksData.Length)); // Copy first and second ROM banks Buffer.BlockCopy(this.cartridge.Data, romBank0Start, memoryData, romBank0Start, Math.Min(this.cartridge.Data.Length, romBankLength * 2)); this.hasBattery = hasBattery; if (hasBattery) { string saveFile = String.Format("{0}.save", gameboy.CartridgeFilename); saveFilePath = Path.Combine(gameboy.CartridgeDirectory, saveFile); if (File.Exists(saveFilePath)) { byte[] savedRAM = File.ReadAllBytes(saveFilePath); Array.Copy(savedRAM, _state.RamBanksData, savedRAM.Length); // We send it to main memory Buffer.BlockCopy(_state.RamBanksData, _state.CurrentRamBank * ramBankLength, memoryData, ramBank0Start, ramBankLength); } } }
internal void LoadRow(DataRow row, CPU cpu, Memory memory, GameBoy gameboy) { // We load the Registers cpu.Registers.A = GetByte(row["Ai"]); cpu.Registers.F = GetByte(row["Fi"]); cpu.Registers.B = GetByte(row["Bi"]); cpu.Registers.C = GetByte(row["Ci"]); cpu.Registers.D = GetByte(row["Di"]); cpu.Registers.E = GetByte(row["Ei"]); cpu.Registers.H = GetByte(row["Hi"]); cpu.Registers.L = GetByte(row["Li"]); cpu.Registers.PC = GetUShort(row["PCi"]); cpu.Registers.SP = GetUShort(row["SPi"]); // We load the rom ushort memoryAddress = 0x0000; int columnCount = row.Table.Columns.Count; int romColumnIndex = row.Table.Columns["ROM"].Ordinal; // Create a dummy cartridge var cartridgeData = new byte[columnCount - romColumnIndex]; for (int columnIndex = romColumnIndex; columnIndex < columnCount; columnIndex++, memoryAddress++) { var element = row[columnIndex]; if (element is System.DBNull) { break; } var value = Convert.ToByte((String)element, 16); cartridgeData[memoryAddress] = value; } gameboy.LoadCartridge("test", cartridgeData); }
/// <summary> /// Class constructor. Performs the loading of the current cartridge into memory. /// </summary> /// <param name="gameboy"></param> internal MBC1MemoryHandler(GameBoy gameboy, bool hasBattery = false) : base(gameboy) { _state.CurrentRamBank = 0; _state.CurrentRomBank = 1; _state.RamBanksData = new byte[0x8000]; // 32768 bytes _romBanksData = new byte[0x200000]; // 2097152 bytes // We obtain the memory pointer byte[] memoryData = memory.MemoryData; // Copy ROM banks Buffer.BlockCopy(this.cartridge.Data, romBank0Start, _romBanksData, romBank0Start, Math.Min(this.cartridge.Data.Length, _romBanksData.Length)); // Copy first and second ROM banks Buffer.BlockCopy(this.cartridge.Data, romBank0Start, memoryData, romBank0Start, Math.Min(this.cartridge.Data.Length, romBankLength * 2)); this.hasBattery = hasBattery; if(hasBattery) { string saveFile = String.Format("{0}.save", gameboy.CartridgeFilename); saveFilePath = Path.Combine(gameboy.CartridgeDirectory, saveFile); if(File.Exists(saveFilePath)) { byte[] savedRAM = File.ReadAllBytes(saveFilePath); Array.Copy(savedRAM, _state.RamBanksData, savedRAM.Length); // We send it to main memory Buffer.BlockCopy(_state.RamBanksData, _state.CurrentRamBank * ramBankLength, memoryData, ramBank0Start, ramBankLength); } } }
public void Op0xCE_250Plus6CarryZero() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); gameboy.Cpu.Registers.A.Value = 0xFA; gameboy.Cpu.Registers.PC.Value = 0x00; gameboy.Mmu.WriteByte(0x00, 0xCE); gameboy.Mmu.WriteByte(0x01, 0x06); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Cpu.Registers.A.Value == 0x00); Assert.That(gameboy.Cpu.Registers.F.CarryFlag == true); Assert.That(gameboy.Cpu.Registers.F.SubtractFlag == false); Assert.That(gameboy.Cpu.Registers.F.ZeroFlag == true); }
public void Op0x32_ASavedHLDecremented() { // Arrange var mmu = new Mmu(); var cpu = new Cpu(mmu, new Registers()); var gameboy = new GameBoy(cpu, mmu, new MockCartridge()); gameboy.PowerUp(); var originalHl = gameboy.Cpu.Registers.HL.Value; gameboy.Cpu.Registers.A.Value = 0x25; gameboy.Cpu.Registers.PC.Value = 0x00; gameboy.Mmu.WriteByte(0x00, 0x32); gameboy.Mmu.WriteByte(0x01, 0x00); // Act gameboy.Cpu.Cycle(); // Assert Assert.That(gameboy.Mmu.ReadByte(originalHl) == gameboy.Cpu.Registers.A.Value); Assert.That(gameboy.Cpu.Registers.HL.Value == originalHl - 1); }
//[Timeout(1200)] public void OneSecondClockTest() { GameBoy gb = new GameBoy(); Cart cart = CartTests.LoadCart("cpu_instrs.gb"); gb.LoadCart(cart); gb.Start(); Stopwatch sw = Stopwatch.StartNew(); Thread.Sleep(1000); sw.Stop(); gb.Shutdown(); //crazy hacks needed to join thread ((Thread)(typeof(GameBoy).GetField("cpuThread", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(gb))).Join(); Console.WriteLine("Total cycles: {0}", gb.CPU.TotalCycles); double clock = gb.CPU.TotalCycles / (sw.ElapsedMilliseconds / 1000d); Assert.AreEqual(0x400000, clock, 250000); }
public void TestInstructionsViaExcel() { // Arrange var gameboy = new GameBoy(); var memory = (Memory)gameboy.Memory; var cpu = (CPU)gameboy.CPU; var row = TestContext.DataRow; LoadRow(row, cpu, memory, gameboy); // Act var steps = (int)row["Steps"]; for (int i = 0; i < steps; i++) { cpu.DetermineStep(true); } // Assert TestFlagsAndMemory(row, cpu); }
public override void Render(GameBoy gb) { Renderer.DrawString(Text, X, Y, RenderLayer, Scale, System.Numerics.Vector4.One); }
public GameBoyPad(GameBoy device) { _device = device; }
public override void Render(GameBoy gb) { Renderer.DrawQuad(X, Y, RenderLayer, Width, Height, Texture); }
public void Setup() { var gb = new GameBoy(new CartInterface(new byte[0])); _mmu = gb.Mmu; }
public void Setup() { _sut = new GameBoy(); _cancellationToken = new CancellationTokenSource(1000).Token; }
/// <summary> /// Executes the instruction on the given device. /// </summary> /// <param name="device">The device to execute the instruction on.</param> /// <returns>The clock cycles it took to evaluate the instruction.</returns> public int Execute(GameBoy device) { return(OpCode.Operation(device, this)); }
public override void OnInit(GameBoy gb) { RecordingNow = gb.EmulatedSamples; }
public bool IsDefeated(GameBoy gb) { return((gb.CpuRead(EventFlagAddress) & EventFlagBit) == 0); }
public override void OnAudioReady(GameBoy gb, int bufferOffset) { AudioStream.Stream.Write(gb.AudioBuffer, 0, bufferOffset * 4); }
public override void Dispose(GameBoy gb) { VideoStream.Close(); AudioStream.Close(); FFMPEG.RunFFMPEGCommand("-y -i movies/video.mp4 -i movies/audio.mp3 -c:v copy -c:a copy -shortest movies/" + Movie + ".mp4"); }