public MainViewModel() { //Console = Console.Default(); var mmu = new Mmu(); Console = new Console( new Cpu(mmu), mmu, new Gpu(mmu, // TODO make palettes configurable from UI //Colors.White, //Colors.LightGray, //Colors.DarkGray, //Colors.Black), //new Color { R = 0xB8, G = 0xC2, B = 0x66 }, //new Color { R = 0x7B, G = 0x8A, B = 0x32 }, //new Color { R = 0x43, G = 0x59, B = 0x1D }, //new Color { R = 0x13, G = 0x2C, B = 0x13 }), Colors.GhostWhite, Colors.LightSlateGray, Colors.DarkSlateBlue, Colors.Black), new Timer(mmu), new Controller(mmu)); Title = "GameboyEm"; OpenCommand = new ActionCommand(Open); LoadStateCommand = new ActionCommand(LoadState); SaveStateCommand = new ActionCommand(SaveState); CloseCommand = new ActionCommand(Application.Current.Shutdown); PowerOnCommand = new ActionCommand(PowerOn); PowerOffCommand = new ActionCommand(PowerOff); ResetCommand = new ActionCommand(Reset); DebuggerCommand = new ActionCommand(Debugger); }
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 Op0xCB99_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 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); }
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 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); }
public Benchmark() { const int memorySize = 32 * 1024 * 1024; var mmu = new Mmu(memorySize); var decoder = new InstructionDecoder(); cpu1 = new Cpu <PhysicalMemoryAccessor, NoTracing>(mmu, decoder); cpu2 = new Cpu <PhysicalMemoryAccessor, NoTracing>(mmu, decoder); mmu._pageDirectory = memorySize - 4; var elf = ELFReader.Load <uint>("D:\\fibo"); startAddress = elf.EntryPoint; var loadableSegments = elf.Segments.Where(s => s.Type == SegmentType.Load); foreach (var segment in loadableSegments) { var content = segment.GetMemoryContents(); var address = segment.PhysicalAddress; mmu.CopyToPhysical(address, content); } }
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); }
private void TestFile_(string fileName) { var lcd = new Lcd { Active = false }; var serialBus = new SerialBus(); var ioAddresses = new IoAddresses(serialBus); var memoryMap = new MemoryMap(ioAddresses); var registers = new Registers(); var memory = new Mmu(memoryMap, registers); var cpu = new Cpu(lcd, memory, new Opcodes(memory)); ushort initialPc = 0; ushort finalPc = 0; var maxCycleCount = 100000000; LinkedList <Expected?>?expecteds = null; if (BlarggTest.COMPARE_TO_BINJGB_) { var expectedTracePath = "R:/Documents/CSharpWorkspace/FinCSharp/FinCSharpTests/tst/emulation/gb/blargg/" + fileName + ".txt"; expecteds = new LinkedList <Expected?>(); try { using (var sr = new StreamReader(expectedTracePath)) { string line; while ((line = sr.ReadLine()) != null) { var words = line.Split(' '); var expectedAHex = words[0].Substring(2); var expectedA = byte.Parse(expectedAHex, NumberStyles.HexNumber); var expectedFText = words[1].Substring(2); var expectedF = 0; if (expectedFText[0] != '-') { expectedF |= 1 << 7; } if (expectedFText[1] != '-') { expectedF |= 1 << 6; } if (expectedFText[2] != '-') { expectedF |= 1 << 5; } if (expectedFText[3] != '-') { expectedF |= 1 << 4; } var expectedAf = ByteMath.MergeBytes(expectedA, (byte)expectedF); var expectedBcHex = words[2].Substring(3); var expectedBc = ushort.Parse(expectedBcHex, NumberStyles.HexNumber); var expectedDeHex = words[3].Substring(3); var expectedDe = ushort.Parse(expectedDeHex, NumberStyles.HexNumber); var expectedHlHex = words[4].Substring(3); var expectedHl = ushort.Parse(expectedHlHex, NumberStyles.HexNumber); var expectedPcHex = words[6].Substring(3); //var expectedPcHex = line.Substring(47, 4); var expectedPc = ushort.Parse(expectedPcHex, NumberStyles.HexNumber); var expectedCyclesText = line.Substring(57, line.IndexOf( ')', 57) - 57); var expectedCycles = int.Parse(expectedCyclesText); var expectedSclText = words[9].Substring(4); var expectedScl = int.Parse(expectedSclText); var expectedPpuModeText = words[12].Substring(5); var expectedPpuMode = int.Parse(expectedPpuModeText); expecteds.AddLast(new Expected(expectedAf, expectedBc, expectedDe, expectedHl, expectedPc, expectedCycles, expectedScl, expectedPpuMode)); } } } catch (Exception e) { expecteds.Clear(); expecteds = null; } } var romPath = "R:/Documents/CSharpWorkspace/FinCSharp/FinCSharpTests/tst/emulation/gb/blargg/" + fileName + ".gb"; var romFile = LocalFile.At(romPath); var romData = LocalFileUtil.ReadBytes(romFile); memoryMap.Rom = new Rom(romData); var output = ""; serialBus.Bytes.Subscribe(b => { output += Convert.ToChar(b); }); var outputPath = "R:/Documents/CSharpWorkspace/FinCSharp/FinCSharpTests/tst/emulation/gb/blargg/output_" + fileName + ".txt"; using var writer = (BlarggTest.LOG_TRACE_) ? new StreamWriter(outputPath) : null; var pc = registers.Pc; initialPc = 0; finalPc = 0; var shouldGetPpuMode = BlarggTest.LOG_TRACE_ || BlarggTest.COMPARE_TO_BINJGB_; var lcdc = ioAddresses.Lcdc; var ly = ioAddresses.Ly; var instruction = 0; var cycles = 0; //try { var enumerator = expecteds?.GetEnumerator(); for (var i = 0; i < maxCycleCount; ++i) { var expected = enumerator?.Current; enumerator?.MoveNext(); var ppuMode = shouldGetPpuMode ? cpu.PpuMode : 0; initialPc = pc.Value; if (BlarggTest.LOG_TRACE_) { StringBuilder line = new StringBuilder(); line.AppendFormat("0x{0:x4}: ", initialPc); line.AppendFormat("{0:x2} |", memoryMap[initialPc]); line.AppendFormat(" af={0:x4}", registers.Af.Value); line.AppendFormat(" bc={0:x4}", registers.Bc.Value); line.AppendFormat(" de={0:x4}", registers.De.Value); line.AppendFormat(" hl={0:x4}", registers.Hl.Value); line.AppendFormat(" sp={0:x4}", registers.Sp.Value); line.AppendFormat(" pc={0:x4} |", registers.Pc.Value); line.AppendFormat(" tot={0} |", cycles); line.AppendFormat(" scl={0}", cpu.UpwardScanlineCycleCounter); line.AppendFormat(" st={0}", cpu.PpuModeCycleCount); line.AppendFormat(" cnt={0} |", cpu.ScanlineCycleCounter / 2); line.AppendFormat(" lcdc={0:x2}", lcdc.Value); line.AppendFormat(" ly={0:x2}", ly.Value); line.AppendFormat(" ppu={0:x1} |", ppuMode); line.AppendFormat(" div={0:x2}", ioAddresses.Div); line.AppendFormat(" tima={0:x2}", ioAddresses.Tima); line.AppendFormat(" tma={0:x2}", ioAddresses.Tma); line.AppendFormat(" tac={0:x2}", ioAddresses.Tac); writer.WriteLine(line.ToString()); } if (expected != null && (expected.Pc != initialPc || expected.Cycles != cycles || expected.Af != registers.Af.Value || expected.Bc != registers.Bc.Value || expected.De != registers.De.Value || expected.Hl != registers.Hl.Value || expected.Scl != cpu.UpwardScanlineCycleCounter || expected.PpuMode != ppuMode)) { var errorBuilder = new StringBuilder(); errorBuilder.Append("Difference at instruction: " + instruction + "\n"); errorBuilder.AppendFormat("Af: {0:x4}/{1:x4}\n", expected.Af, registers.Af.Value); errorBuilder.AppendFormat("Bc: {0:x4}/{1:x4}\n", expected.Bc, registers.Bc.Value); errorBuilder.AppendFormat("De: {0:x4}/{1:x4}\n", expected.De, registers.De.Value); errorBuilder.AppendFormat("Hl: {0:x4}/{1:x4}\n", expected.Hl, registers.Hl.Value); errorBuilder.AppendFormat("Pc: {0:x4}/{1:x4}\n", expected.Pc, initialPc); errorBuilder.AppendFormat("Cycles: {0}/{1}\n", expected.Cycles, cycles); errorBuilder.AppendFormat("Scl: {0}/{1}\n", expected.Scl, cpu.UpwardScanlineCycleCounter); errorBuilder.AppendFormat("Ppu Mode: {0}/{1}\n", expected.PpuMode, ppuMode); Assert.Fail(errorBuilder.ToString()); } cycles += cpu.ExecuteCycles(1); instruction++; finalPc = pc.Value; if (initialPc == finalPc && memory.HaltState != HaltState.HALTED) { break; } } /*} catch (Exception e) { * output = cycles + ", " + registers.Pc.Value + ": " + output; * throw e; * }*/ output = cycles + ", " + registers.Pc.Value + ": " + output; if (!output.Contains("Passed")) { Asserts.Fail(output); } }
public ReplayOpcodes(Mmu memory) { this.memory_ = memory; this.impl_ = new Opcodes(memory); }
static void Main(string[] args) { const int memorySize = 32 * 1024 * 1024; var mmu = new Mmu(memorySize); var decoder = new InstructionDecoder(); var cpu = new Cpu <PhysicalMemoryAccessor, Tracing>(mmu, decoder); if (false /*cpu is Cpu<VirtualMemoryAccessor>*/) { var(location, data) = TlbHelper.PrepareIdentityMap(memorySize); mmu.CopyToPhysical(location, data); mmu._pageDirectory = location; } else { mmu._pageDirectory = memorySize - 4; } var elf = ELFReader.Load <uint>("D:\\fibo"); var startAddress = elf.EntryPoint; var loadableSegments = elf.Segments.Where(s => s.Type == SegmentType.Load); foreach (var segment in loadableSegments) { var content = segment.GetMemoryContents(); var address = segment.PhysicalAddress; mmu.CopyToPhysical(address, content); } cpu.Execute((int)startAddress); var stoper = Stopwatch.StartNew(); for (var i = 0; i < 10; ++i) { cpu.Execute((int)startAddress); } stoper.Stop(); Console.WriteLine(stoper.ElapsedMilliseconds); Console.WriteLine(cpu.InstructionsExecuted); Console.WriteLine($"{(double)cpu.InstructionsExecuted / stoper.ElapsedMilliseconds / 1000} MIPS"); cpu.Reset(); stoper = Stopwatch.StartNew(); for (var i = 0; i < 100; ++i) { cpu.Execute((int)startAddress); } stoper.Stop(); Console.WriteLine(stoper.ElapsedMilliseconds); Console.WriteLine(cpu.InstructionsExecuted); Console.WriteLine($"{(double)cpu.InstructionsExecuted / stoper.ElapsedMilliseconds / 1000} MIPS"); cpu.Reset(); stoper = Stopwatch.StartNew(); for (var i = 0; i < 100; ++i) { cpu.Execute((int)startAddress); } stoper.Stop(); Console.WriteLine(stoper.ElapsedMilliseconds); Console.WriteLine(cpu.InstructionsExecuted); Console.WriteLine($"{(double)cpu.InstructionsExecuted / stoper.ElapsedMilliseconds / 1000} MIPS"); }
public MmuTests() { _mmu = CreateMmu(); }
public void TestReadInvalid() { var mmu = new Mmu(_bios); mmu.ReadByte(0xFFFF); }
public void TestWriteInvalid() { var mmu = new Mmu(_bios); mmu.WriteByte(0xFFFF, (byte)0xFF); }
public void TestWriteBiosFailsDuringBoot() { var mmu = new Mmu(_bios); mmu.WriteByte(0x00, 42); }
public void TestInvlidBiosLength() { var badBios = new byte[] { 1, 2, 3 }; var mmu = new Mmu(badBios); }