public void StepOverWorksWithRst() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0xF3, // DI 0x16, 0x06, // LD D,6 0xFF, // RST $38 0x7A, // LD A,D 0x76 // HALT }); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc1 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc2 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); // --- Assert regs.D.ShouldBe((byte)0x06); pc1.ShouldBe((ushort)0x8003); pc2.ShouldBe((ushort)0x8004); regs.PC.ShouldBe((ushort)0x8005); }
public void StopsAtTerminationPointWhenRequested() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A 0x76 // HALT }); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilExecutionPoint, terminationPoint: 0x8003)); // --- Assert regs.A.ShouldBe((byte)0x20); regs.B.ShouldBe((byte)0x00); regs.C.ShouldBe((byte)0x00); regs.PC.ShouldBe((ushort)0x8003); }
public void DisabledInterruptIsNotRaised() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0xED, 0x56, // IM 1 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x00, 0x0A, // LD BC,$0A00 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800F); spectrum.Cpu.Tacts.ShouldBeGreaterThanOrEqualTo(66599L); }
public void RegisterIxlWorksWithFalseCondition() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); spectrum.DebugExpressionContext = new SpectrumEvaluationContext(spectrum); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x06, 0x80, // LD B,$80 0xDD, 0x2E, 0x00, // LD XL,$00 0xDD, 0x2C, // INC XL 0x10, 0xFC, // DJNZ -4 0x76, // HALT }); var bp = CreateBreakpoint(null, "IXL == 0xFF"); debugProvider.Breakpoints.Add(0x8005, bp); debugProvider.Breakpoints.Add(0x8009, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.XL.ShouldBe((byte)0x80); regs.B.ShouldBe((byte)0x00); regs.PC.ShouldBe((ushort)0x8009); }
public void MachineWorksWithNoDebugCondition() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); spectrum.DebugExpressionContext = new SpectrumEvaluationContext(spectrum); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A }); var bp = CreateBreakpoint(null, null); debugProvider.Breakpoints.Add(0x8000, bp); debugProvider.Breakpoints.Add(0x8007, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.A.ShouldBe((byte)0x00); regs.B.ShouldBe((byte)0x00); regs.C.ShouldBe((byte)0x00); regs.PC.ShouldBe((ushort)0x8000); }
public void KempstonDeviceWithKeyPressWorks(bool left, bool right, bool up, bool down, bool fire, int expected) { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var provider = spectrum.KempstonProvider as KempstonTestProvider; // ReSharper disable once PossibleNullReferenceException provider.Reset(); provider.IsPresent = true; provider.LeftPressed = left; provider.RightPressed = right; provider.DownPressed = down; provider.UpPressed = up; provider.FirePressed = fire; // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x01, 0x1F, 0x00, // LD BC,001FH 0xED, 0x78, // IN A,(C) 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.A.ShouldBe((byte)expected); }
public void NoKempstonDeviceWorks() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var provider = spectrum.KempstonProvider as KempstonTestProvider; // ReSharper disable once PossibleNullReferenceException provider.Reset(); provider.IsPresent = false; // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x01, 0x1F, 0x00, // LD BC,001FH 0xED, 0x78, // IN A,(C) 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.A.ShouldBe((byte)0xFF); }
public void EnabledInterruptIsRaised() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); // --- We render the screen while the interrupt is enabled spectrum.InitCode(new byte[] { 0xED, 0x56, // IM 1 0xFB, // EI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x00, 0x0A, // LD BC,$0A00 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800F); // --- The instructions above take 66599 tacts while reaching the HALT operation // --- However, an interrupt is generated, and because of IM 1, the RST 38 is // --- invoked. It checks to keyboard status in 1034 tacts. // --- When HALT is reached, the CPU tact count is 67633. spectrum.Cpu.Tacts.ShouldBeGreaterThanOrEqualTo(67553L); }
public void ExecutionCyleWorksWithCancellation() { // --- Arrange var pixels = new TestPixelRenderer(SpectrumModels.ZxSpectrum48Pal.Screen); var spectrum = new SpectrumAdvancedTestMachine(pixels); // === The same as RenderingScreenWithPatternWorks1 test case, but waits // === while the full frame is rendered and a new frame is started. // --- We render the screen with pixels with color index // --- of 0x09 and 0x0A in a chequered pattern spectrum.InitCode(new byte[] { 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x75, 0x0A, // LD BC,$0A75 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0xFB, // EI 0x76 // HALT }); for (var addr = 0x4000; addr < 0x5800; addr++) { spectrum.WriteSpectrumMemory((ushort)addr, (byte)((addr & 0x0100) == 0 ? 0x55 : 0xAA)); } for (var addr = 0x5800; addr < 0x5B00; addr++) { spectrum.WriteSpectrumMemory((ushort)addr, 0x51); } var counter = spectrum.Clock.GetCounter(); var cancellationTime = counter + spectrum.Clock.GetFrequency() / 100000; // 0.01ms var startTime = spectrum.Clock.GetCounter(); var cancellationSource = new CancellationTokenSource(); // --- Act // === We wait up to two frames Task.WaitAll( Task.Run(() => spectrum.ExecuteCycle(cancellationSource.Token, new ExecuteCycleOptions(EmulationMode.UntilFrameEnds)), cancellationSource.Token), Task.Run(() => { spectrum.Clock.WaitUntil(cancellationTime, cancellationSource.Token); cancellationSource.Cancel(); }, cancellationSource.Token)); // === Display some extra information about the duration of the frame execution var duration = (spectrum.Clock.GetCounter() - startTime) / (double)spectrum.Clock.GetFrequency(); Console.WriteLine("Frame execution time: {0} second", duration); // --- Assert // === Only a part of the frame's tact time is used spectrum.Cpu.Tacts.ShouldBeLessThanOrEqualTo(spectrum.ScreenDevice.ScreenConfiguration.ScreenRenderingFrameTactCount + 1); }
public void MachineStopsAtMultipleBreakpoints() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A }); debugProvider.Breakpoints.Add(0x8003, MinimumBreakpointInfo.EmptyBreakpointInfo); debugProvider.Breakpoints.Add(0x8004, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); var pc1 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.A.ShouldBe((byte)0x20); regs.B.ShouldBe((byte)0x20); regs.C.ShouldBe((byte)0x00); pc1.ShouldBe((ushort)0x8003); regs.PC.ShouldBe((ushort)0x8004); }
public void StepIntoStopsAtNextInstruction() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A }); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepInto)); // --- Assert regs.A.ShouldBe((byte)0x10); regs.B.ShouldBe((byte)0x00); regs.C.ShouldBe((byte)0x00); regs.PC.ShouldBe((ushort)0x8002); }
public void MachineStopsAtFirstInstructionBreakpointAndStepsFurther() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A }); debugProvider.Breakpoints.Add(0x8000, MinimumBreakpointInfo.EmptyBreakpointInfo); debugProvider.Breakpoints.Add(0x8002, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.A.ShouldBe((byte)0x10); regs.B.ShouldBe((byte)0x00); regs.C.ShouldBe((byte)0x00); regs.PC.ShouldBe((ushort)0x8002); }
public void Flag5WorksWithFalseCondition() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); spectrum.DebugExpressionContext = new SpectrumEvaluationContext(spectrum); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x04, // LD A,$04 0xB7, // OR A 0x47, // LD B,A 0x76, // HALT }); var bp = CreateBreakpoint(null, "`5"); debugProvider.Breakpoints.Add(0x8003, bp); debugProvider.Breakpoints.Add(0x8004, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.PC.ShouldBe((ushort)0x8004); }
public void PortWithIssue3UlaAndHighTimingWorks() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); spectrum.InitCode(new byte[] { 0x3E, 0x18, // LD A,$18 0xF6, 0xF8, // OR A,$F8 0xD3, 0xFE, // OUT ($FE),A 0x3E, 0x08, // LD A,$08 0xF6, 0xE8, // OR A,$E8 0xD3, 0xFE, // OUT ($FE),A 0x06, 0x08, // LD B,8 0xDD, 0x21, 0x00, 0x00, // LD IX,0 0x10, 0xFA, // DJNZ $-4 0xDB, 0xFE, // IN A,($FE) 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert spectrum.Cpu.Registers.A.ShouldBe((byte)0xBF); }
public void CycleWorksWithMultiplyHitCondition1() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); spectrum.DebugExpressionContext = new SpectrumEvaluationContext(spectrum); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x06, 0x80, // LD B,$80 0x3E, 0x00, // LD A,$00 0x3C, // INC A 0x10, 0xFD, // DJNZ -3 0x76, // HALT }); var bp = CreateBreakpoint("*8", null); debugProvider.Breakpoints.Add(0x8004, bp); debugProvider.Breakpoints.Add(0x8007, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.A.ShouldBe((byte)0x07); regs.B.ShouldBe((byte)0x79); regs.PC.ShouldBe((ushort)0x8004); }
public void RegisterRWorksWithTrueCondition() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); spectrum.DebugExpressionContext = new SpectrumEvaluationContext(spectrum); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x06, 0x80, // LD B,$80 0x78, // LD A,B 0xED, 0x47, // LD I,A 0x10, 0xFB, // DJNZ -5 0x76, // HALT }); var bp = CreateBreakpoint(null, "R == 14"); debugProvider.Breakpoints.Add(0x8003, bp); debugProvider.Breakpoints.Add(0x8007, MinimumBreakpointInfo.EmptyBreakpointInfo); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger)); // --- Assert regs.R.ShouldBe((byte)0x0E); regs.I.ShouldBe((byte)0x7E); regs.B.ShouldBe((byte)0x7D); regs.PC.ShouldBe((ushort)0x8003); }
public void DoesNotStopAtTerminationPointInNormalExecutionMode() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A 0x76 // HALT }); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt, terminationPoint: 0x0002)); // --- Assert regs.A.ShouldBe((byte)0x20); regs.B.ShouldBe((byte)0x20); regs.C.ShouldBe((byte)0x20); regs.PC.ShouldBe((ushort)0x8005); }
public void SettingBorderValueChangesBorderArea1() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); // --- Because we execute 3675 CPU tacts, rendering reaches // --- the first 104 pixels of the first border row spectrum.InitCode(new byte[] { 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x8C, 0x00, // LD BC,$008C 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800D); spectrum.Cpu.Tacts.ShouldBe(3671L); pixels.IsFrameReady.ShouldBeFalse(); // --- The left 104 pixels of the first border row should be set to 0x05 pixels.SetPixelMemory(spectrum.ScreenDevice.GetPixelBuffer()); for (var column = 0; column < 96; column++) { pixels[0, column].ShouldBe((byte)0x05); } // --- The remaining pixels of the first border row should be intact (0xFF) for (var column = 96; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[0, column].ShouldBe((byte)0x00); } // --- All the other screen bytes should be intact (0xFF) for (var row = 1; row < spectrum.ScreenDevice.ScreenConfiguration.ScreenLines; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x00); } } }
private static void InitMachineOutCWithNops(int tactToReach, byte port, SpectrumAdvancedTestMachine spectrum) { var code = new List <byte> { 0xF3 // DI ; (4) }; var usedTacts = 4; var remainder = tactToReach % 4; switch (remainder) { case 0: code.Add(0x03); // INC BC (6) usedTacts += 6; break; case 1: code.Add(0x3E); // LD A,0 (7) code.Add(0x00); usedTacts += 7; break; case 2: break; case 3: code.Add(0xED); // LD A,I (9) code.Add(0x57); usedTacts += 9; break; } usedTacts += 26; var extraNops = (tactToReach - usedTacts) / 4; for (var i = 0; i < extraNops; i++) { code.Add(0x00); // NOP } // --- Now we add the instruction for contention code.Add(0x06); // LD B,port ; (7) code.Add(port); code.Add(0x0E); // LD C,port ; (7) code.Add(port); code.Add(0xED); // OUT (C),A ; (12) code.Add(0x79); code.Add(0x76); // HALT spectrum.InitCode(code); }
public void SettingBorderValueChangesBorderArea2() { // --- Arrange var pixels = new TestPixelRenderer(SpectrumModels.ZxSpectrum48Pal.Screen); var spectrum = new SpectrumAdvancedTestMachine(pixels); // --- Because we execute 14335 CPU tacts, rendering reaches // --- all top border rows, save the last invisible pixels of the last top border row spectrum.InitCode(new byte[] { 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x26, 0x02, // LD BC,$0226 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800D); spectrum.Cpu.Tacts.ShouldBe(14331L); pixels.IsFrameReady.ShouldBeFalse(); // --- The top 48 border rows should be set to 0x05 pixels.SetPixelMemory(spectrum.ScreenDevice.GetPixelBuffer()); for (var row = 0; row < 48; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } // --- All the other screen bytes should be intact (0xFF) for (var row = 48; row < spectrum.ScreenDevice.ScreenConfiguration.ScreenLines; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x00); } } }
private static void InitMachineReadWithNops(int tactToReach, SpectrumAdvancedTestMachine spectrum) { var code = new List <byte> { 0xF3 // DI ; (4) }; var usedTacts = 4; var remainder = tactToReach % 4; switch (remainder) { case 0: break; case 1: code.Add(0xED); // LD A,I (9) code.Add(0x57); usedTacts += 9; break; case 2: code.Add(0x03); // INC BC (6) usedTacts += 6; break; default: code.Add(0x3E); // LD A,0 (7) code.Add(0x00); usedTacts += 7; break; } usedTacts += 20; var extraNops = (tactToReach - usedTacts) / 4; for (var i = 0; i < extraNops; i++) { code.Add(0x00); // NOP } // --- Now we add the instruction for contention code.Add(0x3E); // LD A,#FF ; (7) code.Add(0xFF); code.Add(0x3A); // LD A,(#4100) ; (13) code.Add(0x00); code.Add(0x41); code.Add(0x76); // HALT spectrum.InitCode(code); }
public void StepOverWorksWithCallPFalse() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x90, // LD A,$90 0xB7, // OR A 0xF4, 0x09, 0x80, // CALL P,$8009 0x47, // LD B,A 0x4F, // LD C,A 0x76, // HALT 0x3E, 0x20, // LD a,$20 0x57, // LD D,A 0xC9 // RET }); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc1 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc2 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); // --- Assert regs.A.ShouldBe((byte)0x90); regs.B.ShouldBe((byte)0x90); regs.C.ShouldBe((byte)0x00); regs.D.ShouldBe((byte)0x00); pc1.ShouldBe((ushort)0x8003); pc2.ShouldBe((ushort)0x8006); regs.PC.ShouldBe((ushort)0x8007); }
public void EnabledInterruptIsRaised() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); // --- We render the screen while the interrupt is enabled spectrum.InitCode(new byte[] { 0xED, 0x56, // IM 1 0xFB, // EI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x00, 0x0A, // LD BC,$0A00 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); var startTime = spectrum.Clock.GetCounter(); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // === Display some extra information about the duration of the frame execution var duration = (spectrum.Clock.GetCounter() - startTime) / (double)spectrum.Clock.GetFrequency(); Console.WriteLine("Frame execution time: {0} second", duration); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800F); // --- The instructions above take 66599 tacts while reaching the HALT operation // --- However, an interrupt is generated, and because of IM 1, the RST 38 is // --- invoked. It checks to keyboard status in 1034 tacts. // --- When HALT is reached, the CPU tact count is 67633. spectrum.Cpu.Tacts.ShouldBeGreaterThanOrEqualTo(67553L); }
public void SettingBorderValueDoesNotChangeInvisibleScreenArea() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); // --- Because we execute only 451 CPU tacts, rendering does not // --- reach the visible border area spectrum.InitCode(new byte[] { 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x10, 0x00, // LD BC,$0010 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0xFB, // EI 0x76 // HALT }); ((IScreenDeviceTestSupport)spectrum.ScreenDevice).FillScreenBuffer(0xFF); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800E); spectrum.Cpu.Tacts.ShouldBe(451L); pixels.IsFrameReady.ShouldBeFalse(); pixels.SetPixelMemory(spectrum.ScreenDevice.GetPixelBuffer()); for (var row = 0; row < spectrum.ScreenDevice.ScreenConfiguration.ScreenLines; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0xFF); } } }
public void Bit6ValueIsHandledProperly(int portValue, string ulaIssue, int expectedValue) { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(ulaIssue: ulaIssue); spectrum.InitCode(new byte[] { 0x3E, (byte)portValue, // LD A,$18 0xD3, 0xFE, // OUT ($FE),A 0x06, 0x06, // LD B,8 0xDD, 0x21, 0x00, 0x00, // LD IX,0 0x10, 0xFA, // DJNZ $-4 0xDB, 0xFE, // IN A,($FE) 0x76 // HALT }); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert spectrum.Cpu.Registers.A.ShouldBe((byte)expectedValue); }
public void DisabledInterruptIsNotRaised() { // --- Arrange var pars = new ScreenConfiguration(); var pixels = new TestPixelRenderer(pars); var spectrum = new SpectrumAdvancedTestMachine(pars, pixels); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0xED, 0x56, // IM 1 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x00, 0x0A, // LD BC,$0A00 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); var startTime = spectrum.Clock.GetCounter(); // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // === Display some extra information about the duration of the frame execution var duration = (spectrum.Clock.GetCounter() - startTime) / (double)spectrum.Clock.GetFrequency(); Console.WriteLine("Frame execution time: {0} second", duration); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800F); spectrum.Cpu.Tacts.ShouldBeGreaterThanOrEqualTo(66599L); }
public void StepOverWorksWithMultipleSteps() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0x87, // ADD A,A 0x47, // LD B,A 0x4F, // LD C,A }); var regs = spectrum.Cpu.Registers; // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc1 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc2 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); var pc3 = regs.PC; spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.Debugger, DebugStepMode.StepOver)); // --- Assert regs.A.ShouldBe((byte)0x20); regs.B.ShouldBe((byte)0x20); regs.C.ShouldBe((byte)0x20); pc1.ShouldBe((ushort)0x8002); pc2.ShouldBe((ushort)0x8003); pc3.ShouldBe((ushort)0x8004); regs.PC.ShouldBe((ushort)0x8005); }
public void StopWhenTimeout() { // --- Arrange var spectrum = new SpectrumAdvancedTestMachine(); var debugProvider = new TestDebugInfoProvider(); spectrum.SetDebugInfoProvider(debugProvider); // --- We render the screen while the interrupt is disabled spectrum.InitCode(new byte[] { 0x3E, 0x10, // LD A,$10 0xC3, 0x00, 0x80 // JP #8000 }); var start = spectrum.Cpu.Tacts; // --- Act var result = spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt, timeoutTacts: 35000)); // --- Assert result.ShouldBeFalse(); (spectrum.Cpu.Tacts - start).ShouldBeGreaterThanOrEqualTo(35000); }
public void RenderingTenScreenFramesWorksAsExpected() { // --- Arrange var pixels = new TestPixelRenderer(SpectrumModels.ZxSpectrum48Pal.Screen); var spectrum = new SpectrumAdvancedTestMachine(pixels); // === The same as RenderingScreenWithPatternWorks1 test case, but waits // === while the full frame is rendered and a new frame is started. // --- We render the screen with pixels with color index // --- of 0x09 and 0x0A in a chequered pattern spectrum.InitCode(new byte[] { 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x75, 0x0A, // LD BC,$0A75 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); for (var addr = 0x4000; addr < 0x5800; addr++) { spectrum.WriteSpectrumMemory((ushort)addr, (byte)((addr & 0x0100) == 0 ? 0x55 : 0xAA)); } for (var addr = 0x5800; addr < 0x5B00; addr++) { spectrum.WriteSpectrumMemory((ushort)addr, 0x51); } var startTime = spectrum.Clock.GetCounter(); // --- Act // === Be aware of EmulationMode.UntilNextFrame for (var i = 0; i < 10; i++) { spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilFrameEnds)); } // === Display some extra information about the duration of the frame execution var duration = (spectrum.Clock.GetCounter() - startTime) / (double)spectrum.Clock.GetFrequency(); Console.WriteLine("Frame execution time: {0} second", duration); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800D); pixels.IsFrameReady.ShouldBeTrue(); // === The full frame's tact time is used spectrum.Cpu.Tacts.ShouldBeGreaterThanOrEqualTo(spectrum.ScreenDevice.ScreenConfiguration.ScreenRenderingFrameTactCount * 10); // === The full time should not exceed the 10*frame time + the longest Z80 instruction length, // === which is 23 spectrum.Cpu.Tacts.ShouldBeLessThanOrEqualTo(spectrum.ScreenDevice.ScreenConfiguration.ScreenRenderingFrameTactCount * 10 + 23); // --- The top 48 border rows should be set to 0x05 pixels.SetPixelMemory(spectrum.ScreenDevice.GetPixelBuffer()); for (var row = 0; row < 48; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } // --- Display rows should have a border value of 0x05 and a pixel value of 0x00 for (var row = 48; row < 48 + 192; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.BorderLeftPixels; column++) { pixels[row, column].ShouldBe((byte)0x05); } for (var column = spectrum.ScreenDevice.ScreenConfiguration.BorderLeftPixels; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth - spectrum.ScreenDevice.ScreenConfiguration.BorderRightPixels; column++) { var expectedColor = (row + column) % 2 == 1 ? 0x09 : 0x0A; pixels[row, column].ShouldBe((byte)expectedColor); } for (var column = spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth - spectrum.ScreenDevice.ScreenConfiguration.BorderRightPixels; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } // --- The bottom 48 border rows should be set to 0x05 for (var row = 48 + 192; row < spectrum.ScreenDevice.ScreenConfiguration.ScreenLines; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } }
public void RenderingScreenWithPatternWorks1() { // --- Arrange var pixels = new TestPixelRenderer(SpectrumModels.ZxSpectrum48Pal.Screen); var spectrum = new SpectrumAdvancedTestMachine(pixels); // --- We render the screen with pixels with color index // --- of 0x09 and 0x0A in a chequered pattern spectrum.InitCode(new byte[] { 0xF3, // DI 0x3E, 0x05, // LD A,$05 0xD3, 0xFE, // OUT ($FE),A 0x01, 0x75, 0x0A, // LD BC,$0A75 0x0B, // DECLB: DEC BC 0x78, // LD A,B 0xB1, // OR C 0x20, 0xFB, // JR NZ,DECLB 0x76 // HALT }); for (var addr = 0x4000; addr < 0x5800; addr++) { spectrum.WriteSpectrumMemory((ushort)addr, (byte)((addr & 0x0100) == 0 ? 0x55 : 0xAA)); } for (var addr = 0x5800; addr < 0x5B00; addr++) { spectrum.WriteSpectrumMemory((ushort)addr, 0x51); } // --- Act spectrum.ExecuteCycle(CancellationToken.None, new ExecuteCycleOptions(EmulationMode.UntilHalt)); // --- Assert var regs = spectrum.Cpu.Registers; regs.PC.ShouldBe((ushort)0x800D); spectrum.Cpu.Tacts.ShouldBe(69633L); pixels.IsFrameReady.ShouldBeFalse(); // --- The top 48 border rows should be set to 0x05 pixels.SetPixelMemory(spectrum.ScreenDevice.GetPixelBuffer()); for (var row = 0; row < 48; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } // --- Display rows should have a border value of 0x05 and a pixel value of 0x00 for (var row = 48; row < 48 + 192; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.BorderLeftPixels; column++) { pixels[row, column].ShouldBe((byte)0x05); } for (var column = spectrum.ScreenDevice.ScreenConfiguration.BorderLeftPixels; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth - spectrum.ScreenDevice.ScreenConfiguration.BorderRightPixels; column++) { var expectedColor = (row + column) % 2 == 1 ? 0x09 : 0x0A; pixels[row, column].ShouldBe((byte)expectedColor); } for (var column = spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth - spectrum.ScreenDevice.ScreenConfiguration.BorderRightPixels; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } // --- The bottom 48 border rows should be set to 0x05 for (var row = 48 + 192; row < spectrum.ScreenDevice.ScreenConfiguration.ScreenLines; row++) { for (var column = 0; column < spectrum.ScreenDevice.ScreenConfiguration.ScreenWidth; column++) { pixels[row, column].ShouldBe((byte)0x05); } } }