partial void Execute_LoadCommand() { var openFileDialog = new Microsoft.Win32.OpenFileDialog() { Filter = "HEX file (*.hex)|*.hex" }; var result = openFileDialog.ShowDialog(); if (result ?? false) { var fileName = openFileDialog.FileName; var(RAM, startAddr, endAddr) = HexFileLoader.Read(fileName, new byte[64 * 1024]); _basicBus = new BasicBus(RAM); RawMemory = _basicBus.RAM; _cpu.ConnectToBus(_basicBus); Memory = BuildMemoryMap(); _cpu.PC = startAddr; ProgramCounter = _cpu.PC.ToString("X4"); MemoryMapRow = GetMemoryMapRow(startAddr); var disassembly = _cpu.Disassemble(startAddr, endAddr); DisAsm = GetDisassembedProgram(disassembly); SelectedRow = startAddr.ToString("X4"); } }
public void LoadAwithValueWhenOperationIsLDAn() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x3E }, { 0x0081, 0x02 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); // Load 2 into register A, which starts out having a value of 3... var cpu = new Z80() { A = 0x03, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x02, cpu.A); // No affect on Condition Flags FlagsUnchanged(cpu); }
private void HandleStrayOpCodes2() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xDD }, { 0x0081, 0xDD }, { 0x0082, 0xDD }, { 0x0083, 0xFD }, { 0x0084, 0xDD }, // LD IX &1000 { 0x0085, 0x21 }, { 0x0086, 0x00 }, { 0x0087, 0x10 }, { 0x0088, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, IX = 0x00, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); while (cpu.PC < 0x0088) { cpu.Step(); } Assert.Equal(0x1000, cpu.IX); }
public void LoadRfromA() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xED }, { 0x0081, 0x4F }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x17, R = 0x00, IFF2 = true, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x17, cpu.A); Assert.Equal(0x17, cpu.R); // No affect on Condition Flags FlagsUnchanged(cpu); }
private void SwapRegistersWithEXX() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xD9 }, // EXX { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { B = 0x11, C = 0x22, D = 0x12, E = 0x23, H = 0x14, L = 0x24, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x0000, cpu.BC); Assert.Equal(0x1122, cpu.BC1); Assert.Equal(0x0000, cpu.DE); Assert.Equal(0x1223, cpu.DE1); Assert.Equal(0x0000, cpu.HL); Assert.Equal(0x1424, cpu.HL1); FlagsUnchanged(cpu); }
private void SwapAFandAFPrime() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x08 }, // EX AF,AF' { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x11, F = (Flags)0x22, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x0000, cpu.AF); Assert.Equal(0x1122, cpu.AF1); FlagsUnchanged(cpu); }
private void SwapDEandHL() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xEB }, // EX DE,HL { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { D = 0x11, E = 0x22, H = 0x33, L = 0x44, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x3344, cpu.DE); Assert.Equal(0x1122, cpu.HL); FlagsUnchanged(cpu); }
private void JumpToIY() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xFD }, // JR IY { 0x0081, 0xE9 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, { 0x0085, 0x00 }, { 0x0086, 0x00 }, // <- jump here { 0x0087, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, IY = 0x0086, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x086, cpu.PC); FlagsUnchanged(cpu); }
private void EnableInterruptBySettingIFF() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xFB }, // EI { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.True(cpu.IFF1); Assert.True(cpu.IFF2); }
private void JumpForwardFourForJRNZPositiveSix_NotZeroSet() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x20 }, // JR NZ $+6 { 0x0081, 0x04 }, // Assembler with compensate for PC incrementing twice { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, { 0x0085, 0x00 }, { 0x0086, 0x00 }, // <- jump here { 0x0087, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, PC = 0x0080 }; cpu.F = (Flags)0b00000000; // Reset Z flag cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x086, cpu.PC); }
private void DoNotJumpForwardFourForJRCPositiveSix_CarryNotSet() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x38 }, // JR C $+6 { 0x0081, 0x04 }, // Assembler with compensate for PC incrementing twice { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, { 0x0085, 0x00 }, { 0x0086, 0x00 }, { 0x0087, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x082, cpu.PC); FlagsUnchanged(cpu); }
private void NotJumpBackFourForDJNZ_WhenZero() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x007C, 0x00 }, // <- jump here { 0x007D, 0x00 }, { 0x007E, 0x00 }, { 0x007F, 0x00 }, { 0x0080, 0x10 }, // DJNZ $-4 { 0x0081, 0xFA }, // Assembler with compensate for PC incrementing twice { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, { 0x0085, 0x00 }, { 0x0086, 0x00 }, { 0x0087, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { B = 0x01, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x082, cpu.PC); }
private void DisassembleArithmetic1HexFileCorrectly() { var fakeBus = A.Fake <IBus>(); var expectedDisassembly = new Dictionary <ushort, string> { { 0x0080, "LD A,&05" }, { 0x0082, "LD B,&0A" }, { 0x0084, "ADD A,B" }, { 0x0085, "ADD A,A" }, { 0x0086, "LD C,&0F" }, { 0x0088, "SUB A,C" }, { 0x0089, "LD H,&08" }, { 0x008B, "LD L,&FF" }, { 0x008D, "LD (HL),A" }, { 0x008E, "NOP" }, }; var ram = HexFileReader.Read("../../../HexFiles/Arithmetic1.hex"); A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => ram[addr]); var cpu = new Z80() { A = 0x00, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); var disassembledCode = cpu.Disassemble(0x0080, 0x008E); Assert.Equal(expectedDisassembly, disassembledCode); }
private void LoadProgramCounterWithAddressForJPNN() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xC3 }, // JP 0191h { 0x0081, 0x91 }, { 0x0082, 0x01 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, { 0x0190, 0x00 }, { 0x0191, 0x00 }, // <- jump here { 0x0192, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x0191, cpu.PC); FlagsUnchanged(cpu); }
private void DisassembleMultiplicationHexFileCorrectly() { var fakeBus = A.Fake <IBus>(); var ram = HexFileReader.Read("../../../HexFiles/Multiplication.hex"); var expectedDisassembly = new Dictionary <ushort, string> { { 0x8000, "LD BC,&0015" }, { 0x8003, "LD B,&08" }, { 0x8005, "LD DE,&002A" }, { 0x8008, "LD D,&00" }, { 0x800A, "LD HL,&0000" }, { 0x800D, "SRL C" }, { 0x800F, "JR C,$+3" }, { 0x8011, "ADD HL,DE" }, { 0x8012, "SLA E" }, { 0x8014, "RL D" }, { 0x8016, "DEC B" }, { 0x8017, "JP NZ,&800D" }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => ram[addr]); var cpu = new Z80() { A = 0x00, PC = 0x8000 }; cpu.ConnectToBus(fakeBus); var disassembledCode = cpu.Disassemble(0x8000, 0x8017); Assert.Equal(expectedDisassembly, disassembledCode); }
private void SetInterruptMode2() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xED }, // IM 2 { 0x0081, 0x5E }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x00, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.True(cpu.InterruptMode == InterruptMode.Mode2); }
private void DisassembleDDCBandFDCBOpcodesCorrectly() { var fakeBus = A.Fake <IBus>(); var ram = HexFileReader.Read("../../../HexFiles/TestDDCBandFDCB.hex"); var expectedDisassembly = new Dictionary <ushort, string> { { 0x8000, "RL (IX+2)" }, { 0x8004, "RL (IY-3)" }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => ram[addr]); var cpu = new Z80() { A = 0x00, PC = 0x8000 }; cpu.ConnectToBus(fakeBus); var disassembledCode = cpu.Disassemble(0x8000, 0x8007); Assert.Equal(expectedDisassembly, disassembledCode); }
private void DecrementRegisterFlagsTest2() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x15 }, { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { D = 0x80, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x7F, cpu.D); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.True((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.True((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.True((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.True((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
static void Main(string[] args) { var ram = new byte[65536]; Array.Clear(ram, 0, ram.Length); var romData = File.ReadAllBytes(_rom); if (romData.Length != 16384) { throw new InvalidOperationException("Not a valid ROM file"); } Array.Copy(romData, ram, 16384); _cpu = new Z80(); IBus simpleBus = new SimpleBus(ram); _cpu.ConnectToBus(simpleBus); Console.Clear(); while (!(Console.KeyAvailable && (Console.ReadKey(true).Key == ConsoleKey.Escape))) { try { _cpu.Step(); Console.Write($"\rPC: {_cpu.PC.ToString("X4")}"); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); Console.ReadLine(); } } Console.WriteLine(); Console.WriteLine(); for (var i = 0x4000; i < 0x5800; i++) { if (i % 16 == 0) { Console.Write("{0:X4} | ", i); } { Console.Write("{0:x2} ", ram[i]); } if (i % 8 == 7) { Console.Write(" "); } if (i % 16 == 15) { Console.WriteLine(); } } }
public void LoadAWithNegative7WhenSubtracting6And12AndCarryFlagSetForOpcodeSBCAN() { // ====================================== // Testing a negative result: 6 - 12 - 1 = -6 // ====================================== var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xDE }, // SBC A, n { 0x0081, 0x0C }, // n = 12 { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x06, F = Z80.Flags.C, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0xF9, cpu.A); sbyte signedResult = (sbyte)cpu.A; Assert.Equal(-7, signedResult); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); // Set due to a subtraction Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.True((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.True((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.True((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.True((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.True((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
private void DecrementValueAtLocationPointedToByIYPlusDFlagsTest() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xFD }, { 0x0081, 0x35 }, { 0x0082, 0x03 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, // <- (IX) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x80 }, // <- (IX+3) { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); A.CallTo(() => fakeBus.Write(A <ushort> ._, A <byte> ._)) .Invokes((ushort addr, byte data) => UpdateMemory(addr, data)); var cpu = new Z80() { A = 0x00, IY = 0x08FF, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x7F, program[(ushort)(cpu.IY + 3)]); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.True((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.True((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.True((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.True((cpu.F & Z80.Flags.X) == Z80.Flags.X); void UpdateMemory(ushort addr, byte data) { program[addr] = data; } }
public Results RunTests() { ReadFuseTestsFile(); ReadFuseExpectedFile(); _cpu = new Z80(); foreach (var test in _tests) { var testName = test.Key; var opCode = testName.Split('_')[0]; _cpu.Reset(true); var isExtendedNopTest = opCode == "dd00" || opCode == "fddd00"; if (_cpu.IsOpCodeSupported(opCode) || isExtendedNopTest) { // Run test var testToRun = test.Value; var registers = testToRun.Registers; var memory = testToRun.Memory; var states = testToRun.States; InitialiseRegisters(registers); InitialiseMemory(memory); InitialiseStates(states); _cpu.ConnectToBus(_bus); var runToAddress = _expected[testName].Registers[11]; do { _cpu.Step(); } while (_cpu.PC < runToAddress); var(pass, details) = CompareActualWithExpected(_expected[testName]); if (pass) { _passing.Add(testName); } else { _failing.Add(testName, details); } } else { _notImplemented.Add(testName); } } return(new Results(_passing, _failing, _notImplemented)); }
public void LoadAWithThreeWhenSubtracting8And5ForOpcodeSUBAN() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xD6 }, // SUB A, n { 0x0081, 0x05 }, // n = 5 { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x08, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x03, cpu.A); sbyte signedResult = (sbyte)cpu.A; Assert.Equal(3, signedResult); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); // Set due to a subtraction Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.False((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.False((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.False((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
public void LoadMemoryLocationPointedToByHLwithValueInAccumulator() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x77 }, { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, // (HL) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); A.CallTo(() => fakeBus.Write(A <ushort> ._, A <byte> ._)) .Invokes((ushort addr, byte data) => UpdateMemory(addr, data)); // Load the value in register A (0x11), into the memory location pointed to by (HL)... var cpu = new Z80() { A = 0x11, H = 0x08, L = 0xFF, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x11, program[0x08FF]); // No affect on Condition Flags FlagsUnchanged(cpu); void UpdateMemory(ushort addr, byte data) { program[addr] = data; } }
public void LoadMemoryLocationPointedToByIYplusDwithValueN_GivenDisNegative() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xFD }, { 0x0081, 0x36 }, { 0x0082, 0xFE }, { 0x0083, 0xBB }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, // <- d = -2 { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, // (IY) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); A.CallTo(() => fakeBus.Write(A <ushort> ._, A <byte> ._)) .Invokes((ushort addr, byte data) => UpdateMemory(addr, data)); var cpu = new Z80() { A = 0x0F, IY = 0x08FF, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0xBB, program[0x08FF - 2]); // No affect on Condition Flags FlagsUnchanged(cpu); void UpdateMemory(ushort addr, byte data) { program[addr] = data; } }
public void LoadAWith7WhenSubtracting4FromBAndCarryFlagSetForOpcodeSBCAR() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0x98 }, //SBC A, B { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x0C, B = 0x04, F = Z80.Flags.C, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x07, cpu.A); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.False((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.False((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.False((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
public void LoadAWith6WhenSubtractingLocationPointedToByIXFrom10ForOpcodeSUBAIXD_GivenDisNegative() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xDD }, { 0x0081, 0x96 }, // SUB A, (IX+d) { 0x0082, 0xFE }, // d = -2 { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x04 }, // (IX-2) { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, // <- (IX) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x0A, IX = 0x08FF, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x06, cpu.A); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.False((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.False((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.False((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
public void LoadAWith9WhenSubtracting4FromLocationPointedToByIYForOpcodeSBCAHL_GivenDisPositive() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xFD }, { 0x0081, 0x9E }, // SBC A, (IY+d) { 0x0082, 0x03 }, // d = 3 { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, // <- (IY) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x04 }, // (IY+3) { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x0E, IY = 0x08FF, F = Z80.Flags.C, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x09, cpu.A); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.False((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.False((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.True((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
private void UnsetZeroFlagWhenFalseForCPIYD2() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xFD }, // CP (IY+3) { 0x0081, 0xBE }, { 0x0082, 0x03 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x00 }, // <- (IY) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x02 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x01, IY = 0x08FF, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x01, cpu.A); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.False((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.True((cpu.F & Z80.Flags.S) == Z80.Flags.S); // Negative comparison Assert.True((cpu.F & Z80.Flags.H) == Z80.Flags.H); // Borrow from bit 4 Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.True((cpu.F & Z80.Flags.C) == Z80.Flags.C); // Borrow from "bit 8" Assert.False((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.False((cpu.F & Z80.Flags.X) == Z80.Flags.X); }
private void SetZeroFlagWhenTrueForCPHL() { var fakeBus = A.Fake <IBus>(); var program = new Dictionary <ushort, byte> { // Program Code { 0x0080, 0xBE }, // CP (HL) { 0x0081, 0x00 }, { 0x0082, 0x00 }, { 0x0083, 0x00 }, { 0x0084, 0x00 }, // Data { 0x08FB, 0x00 }, { 0x08FC, 0x00 }, { 0x08FD, 0x00 }, { 0x08FE, 0x00 }, { 0x08FF, 0x01 }, // <- (HL) { 0x0900, 0x00 }, { 0x0901, 0x00 }, { 0x0902, 0x00 }, { 0x0903, 0x00 }, { 0x0904, 0x00 }, { 0x0905, 0x00 }, { 0x0906, 0x00 }, }; A.CallTo(() => fakeBus.Read(A <ushort> ._, A <bool> ._)) .ReturnsLazily((ushort addr, bool ro) => program[addr]); var cpu = new Z80() { A = 0x01, H = 0x08, L = 0xFF, PC = 0x0080 }; cpu.ConnectToBus(fakeBus); cpu.Step(); Assert.Equal(0x01, cpu.A); Assert.True((cpu.F & Z80.Flags.N) == Z80.Flags.N); Assert.True((cpu.F & Z80.Flags.Z) == Z80.Flags.Z); Assert.False((cpu.F & Z80.Flags.S) == Z80.Flags.S); Assert.False((cpu.F & Z80.Flags.H) == Z80.Flags.H); Assert.False((cpu.F & Z80.Flags.P) == Z80.Flags.P); Assert.False((cpu.F & Z80.Flags.C) == Z80.Flags.C); Assert.False((cpu.F & Z80.Flags.U) == Z80.Flags.U); Assert.False((cpu.F & Z80.Flags.X) == Z80.Flags.X); }