Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        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);
        }
Пример #11
0
        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);
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
        }
Пример #14
0
        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);
        }
Пример #17
0
        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);
        }
Пример #18
0
        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);
                }
            }
        }
Пример #19
0
        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);
        }
Пример #20
0
        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);
                }
            }
        }
Пример #21
0
        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);
        }
Пример #22
0
        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);
        }
Пример #24
0
        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);
                }
            }
        }
Пример #25
0
        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);
        }
Пример #27
0
        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);
        }
Пример #28
0
        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);
        }
Пример #29
0
        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);
                }
            }
        }
Пример #30
0
        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);
                }
            }
        }