public void Executing_Instruction_Dxy0_DoesNotUseDisplay() { var cpu = new Cpu(); var decodedInstruction = new DecodedInstruction(0xD230); var instruction = new Instruction_Dxyn(decodedInstruction); instruction.Execute(cpu, MockedDisplay, MockedKeyboard); }
public void Executing_Instruction_Dxyn_WorksAsExpected() { const byte xCoordinate = 0x5, yCoordinate = 0x6; var cpu = new Cpu(); cpu.V[2] = xCoordinate; cpu.V[3] = yCoordinate; cpu.I = 0x300; cpu.Memory[cpu.I] = 0x1; var decodedInstruction = new DecodedInstruction(0xD231); // Expected execution result: // - decodedInstruction.n bytes (1) are read from memory, starting at location I (0x300) // - those bytes are written to screen, starting at location (V2, V3) = 5,6 // - since value at 0x300 is 0x1, and 1 is the least significant bit of that byte, then location where // pixel will be set is: xCoordinate + 7 (e.g. for value of 2, it would be xCoordinate + 6) // - re-executing the same command will reset the pixel and set VF register to 1 var mockSequence = new MockSequence(); var displayMock = new Mock<IDisplay>(MockBehavior.Strict); // First execution for(byte i = 0; i < 8; i++) { displayMock.InSequence(mockSequence).Setup(x => x.GetPixel( (byte)(xCoordinate + i), yCoordinate)).Returns(false); } displayMock.InSequence(mockSequence).Setup(x => x.SetPixel(xCoordinate + 7, yCoordinate)); // Second execution for (byte i = 0; i < 8; i++) { displayMock.InSequence(mockSequence).Setup(x => x.GetPixel( (byte)(xCoordinate + i), yCoordinate)).Returns(i == 7); } displayMock.InSequence(mockSequence).Setup(x => x.ClearPixel(xCoordinate + 7, yCoordinate)); var display = displayMock.Object; var instruction = new Instruction_Dxyn(decodedInstruction); instruction.Execute(cpu, display, MockedKeyboard); Assert.That(cpu.V[0xF], Is.EqualTo(0)); instruction.Execute(cpu, display, MockedKeyboard); Assert.That(cpu.V[0xF], Is.EqualTo(1)); displayMock.VerifyAll(); Assert.That(instruction.Mnemonic, Is.EqualTo($"DRW V{decodedInstruction.x:X}, V{decodedInstruction.y:X}, {decodedInstruction.n:X}")); }
/// <summary> /// Converts instance of <see cref="DecodedInstruction"/> into an instance of <see cref="CpuInstruction"/>. /// </summary> /// <param name="decodedInstruction">Decoded 2 bytes of memory.</param> /// <returns>Concrete Cpu instruction or <see cref="UndefinedInstruction"/> if instruction cannot be determined.</returns> public CpuInstruction GetCpuInstruction(DecodedInstruction decodedInstruction) { CpuInstruction cpuInstruction = null; switch (decodedInstruction.OpCode) { case 0x0: if (decodedInstruction.kk == 0xE0) { cpuInstruction = new Instruction_00E0(decodedInstruction); } else if (decodedInstruction.kk == 0xEE) { cpuInstruction = new Instruction_00EE(decodedInstruction); } break; case 0x1: cpuInstruction = new Instruction_1nnn(decodedInstruction); break; case 0x2: cpuInstruction = new Instruction_2nnn(decodedInstruction); break; case 0x3: cpuInstruction = new Instruction_3xkk(decodedInstruction); break; case 0x4: cpuInstruction = new Instruction_4xkk(decodedInstruction); break; case 0x5: if (decodedInstruction.n == 0x0) { cpuInstruction = new Instruction_5xy0(decodedInstruction); } break; case 0x6: cpuInstruction = new Instruction_6xkk(decodedInstruction); break; case 0x7: cpuInstruction = new Instruction_7xkk(decodedInstruction); break; case 0x8: { switch (decodedInstruction.n) { case 0x0: cpuInstruction = new Instruction_8xy0(decodedInstruction); break; case 0x1: cpuInstruction = new Instruction_8xy1(decodedInstruction); break; case 0x2: cpuInstruction = new Instruction_8xy2(decodedInstruction); break; case 0x3: cpuInstruction = new Instruction_8xy3(decodedInstruction); break; case 0x4: cpuInstruction = new Instruction_8xy4(decodedInstruction); break; case 0x5: cpuInstruction = new Instruction_8xy5(decodedInstruction); break; case 0x6: cpuInstruction = new Instruction_8xy6(decodedInstruction); break; case 0x7: cpuInstruction = new Instruction_8xy7(decodedInstruction); break; case 0xE: cpuInstruction = new Instruction_8xyE(decodedInstruction); break; default: cpuInstruction = new UndefinedInstruction(decodedInstruction); break; } } break; case 0x9: if (decodedInstruction.n == 0x0) { cpuInstruction = new Instruction_9xy0(decodedInstruction); } break; case 0xA: cpuInstruction = new Instruction_Annn(decodedInstruction); break; case 0xB: cpuInstruction = new Instruction_Bnnn(decodedInstruction); break; case 0xC: cpuInstruction = new Instruction_Cxkk(decodedInstruction); break; case 0xD: cpuInstruction = new Instruction_Dxyn(decodedInstruction); break; case 0xE: { switch (decodedInstruction.kk) { case 0x9E: cpuInstruction = new Instruction_Ex9E(decodedInstruction); break; case 0xA1: cpuInstruction = new Instruction_ExA1(decodedInstruction); break; default: cpuInstruction = new UndefinedInstruction(decodedInstruction); break; } } break; case 0xF: { switch (decodedInstruction.kk) { case 0x07: cpuInstruction = new Instruction_Fx07(decodedInstruction); break; case 0x0A: cpuInstruction = new Instruction_Fx0A(decodedInstruction); break; case 0x15: cpuInstruction = new Instruction_Fx15(decodedInstruction); break; case 0x18: cpuInstruction = new Instruction_Fx18(decodedInstruction); break; case 0x1E: cpuInstruction = new Instruction_Fx1E(decodedInstruction); break; case 0x29: cpuInstruction = new Instruction_Fx29(decodedInstruction); break; case 0x33: cpuInstruction = new Instruction_Fx33(decodedInstruction); break; case 0x55: cpuInstruction = new Instruction_Fx55(decodedInstruction); break; case 0x65: cpuInstruction = new Instruction_Fx65(decodedInstruction); break; default: cpuInstruction = new UndefinedInstruction(decodedInstruction); break; } break; } default: cpuInstruction = new UndefinedInstruction(decodedInstruction); break; } return(cpuInstruction ?? new UndefinedInstruction(decodedInstruction)); }