public static void Check_Instruction_18_CALL_Address()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,0");
            testProgram.AppendLine("CALL FUNC");
            testProgram.AppendLine("LD A,2");
            testProgram.AppendLine("ORG 100");
            testProgram.AppendLine("FUNC: LD A,1");
            testProgram.AppendLine("RET");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(5);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/CallAndReturn/Logs/Check_Instruction_18_CALL_Address"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_65_LD_Register16_Register16()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "10 (4, 3, 3)"
            testProgram.AppendLine("LD HL,1547");
            // TStatesByMachineCycle = "1 (6)"
            testProgram.AppendLine("LD SP,HL");
            // TStatesByMachineCycle = "14 (4, 4, 3, 3)"
            testProgram.AppendLine("LD IY,3225");
            // TStatesByMachineCycle = "10 (4, 6)"
            testProgram.AppendLine("LD SP,IY");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(4);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Load16Bit/Logs/Check_Instruction_65_LD_Register16_Register16"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_125_SBC_Register_Register16Address()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,10");
            // TStatesByMachineCycle = "10 (4, 3, 3)"
            testProgram.AppendLine("LD HL,100");
            // TStatesByMachineCycle = "10 (4, 3, 3)"
            testProgram.AppendLine("LD (HL),5");
            // TStatesByMachineCycle = 1 (4)
            testProgram.AppendLine("SCF");
            // TStatesByMachineCycle = 7 (4, 3)
            testProgram.AppendLine("SBC A,(HL)");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(5);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/Arithmetic_8bits/Logs/Check_Instruction_125_SBC_Register_Register16Address"))
            {
                throw new Exception("Log compare failed");
            }
        }
        /// <summary>
        /// Utility method used to compare execution log with arithmetic operations results (8 bits arithmetic)
        /// </summary>
        private static void CompareExecutionResultsWithSample(string sampleProgramFileName, string sampleResultFileName, int instructionsPerLine, int accColumn)
        {
            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(sampleProgramFileName, Encoding.UTF8, false);

            Stream stream = PlatformSpecific.GetStreamForProjectFile(sampleResultFileName);
            using (StreamReader reader = new StreamReader(stream))
            {
                string line = null;
                while ((line = reader.ReadLine()) != null)
                {
                    testSystem.ExecuteInstructionCount(instructionsPerLine);

                    string[] columns = line.Split(';');
                    string AHexValue = columns[accColumn];
                    byte AByteValue = Convert.ToByte(AHexValue, 16);
                    string FBinValue = columns[accColumn + 1];
                    byte FByteValue = Convert.ToByte(FBinValue, 2);

                    if (testSystem.CPU.A != AByteValue)
                    {
                        throw new Exception(String.Format("Error line {0}, A = {1}", line, String.Format("{0:X}", testSystem.CPU.A)));
                    }
                    else if ((testSystem.CPU.F) != FByteValue)
                    {
                        throw new Exception(String.Format("Error line {0}, F = {1}", line, Convert.ToString(testSystem.CPU.F, 2)));
                    }
                }
            }
        }
        public static void Check_FetchOpcode(bool simulateSlowMemoryAndDevices)
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,B");
            testProgram.AppendLine("LD R,A");

            TestSystem testSystem = new TestSystem(simulateSlowMemoryAndDevices);
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
               CPUStateLogger.CPUStateElements.InternalState |
               CPUStateLogger.CPUStateElements.Registers |
               CPUStateLogger.CPUStateElements.Buses |
               CPUStateLogger.CPUStateElements.ControlPins,
               new Z80CPU.LifecycleEventType[] {
                    Z80CPU.LifecycleEventType.HalfTState,
                    Z80CPU.LifecycleEventType.InstructionEnd,
                    Z80CPU.LifecycleEventType.InstructionStart,
                    Z80CPU.LifecycleEventType.MachineCycleEnd,
                    Z80CPU.LifecycleEventType.MachineCycleStart
                });
            testSystem.ExecuteInstructionCount(2);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("MachineCycles/Logs/Check_FetchOpcode" + GetSlowSuffix(simulateSlowMemoryAndDevices)))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_100_RL_Register()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD B,00000001B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");
            testProgram.AppendLine("RL B");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(10);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/RotateAndShift/Logs/Check_Instruction_100_RL_Register"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_26_CPDR()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD HL,100");
            testProgram.AppendLine("LD (HL),1");
            testProgram.AppendLine("LD HL,101");
            testProgram.AppendLine("LD (HL),2");
            testProgram.AppendLine("LD HL,102");
            testProgram.AppendLine("LD (HL),3");
            testProgram.AppendLine("LD BC,3");
            testProgram.AppendLine("LD A,5");
            testProgram.AppendLine("CPDR");
            testProgram.AppendLine("LD HL,102");
            testProgram.AppendLine("LD BC,3");
            testProgram.AppendLine("LD A,2");
            testProgram.AppendLine("CPDR");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(17);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/ExchangeBlockTransferAndSearch/Logs/Check_Instruction_26_CPDR"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_55_JP_Register16Address()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,0");
            testProgram.AppendLine("LD HL,100");
            testProgram.AppendLine("JP (HL)");
            testProgram.AppendLine("ORG 100");
            testProgram.AppendLine("LD IX,110");
            testProgram.AppendLine("JP (IX)");
            testProgram.AppendLine("ORG 110");
            testProgram.AppendLine("LD IY,120");
            testProgram.AppendLine("JP (IY)");
            testProgram.AppendLine("ORG 120");
            testProgram.AppendLine("LD A,1");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(8);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Jump/Logs/Check_Instruction_55_JP_Register16Address"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_20_CCF()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "1 (4)"
            testProgram.AppendLine("CCF");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,0");
            // TStatesByMachineCycle = "1 (4)"
            testProgram.AppendLine("CCF");
            // TStatesByMachineCycle = "1 (4)"
            testProgram.AppendLine("CCF");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(4);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/ArithmeticGeneralPurpose/Logs/Check_Instruction_20_CCF"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_60_LD_Register_Register()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD C,10");
            // TStatesByMachineCycle = "1 (4)"
            testProgram.AppendLine("LD D,C");
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("LD IXh,D");
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("LD E,IXh");
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("LD IXl,IXh");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("LD IYh,32");
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("LD IYl,IYh");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,55");
            // TStatesByMachineCycle = "9 (4, 5)"
            testProgram.AppendLine("LD R,A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,0");
            // TStatesByMachineCycle = "9 (4, 5)"
            testProgram.AppendLine("LD A,R");
            // TStatesByMachineCycle = "9 (4, 5)"
            testProgram.AppendLine("LD A,I");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(12);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Load_8Bit/Logs/Check_Instruction_60_LD_Register_Register"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_122_RST_ResetAddress()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,0");
            testProgram.AppendLine("RST 08H");
            testProgram.AppendLine("ORG 08H");
            testProgram.AppendLine("LD A,1");
            testProgram.AppendLine("RST 10H");
            testProgram.AppendLine("ORG 10H");
            testProgram.AppendLine("LD A,2");
            testProgram.AppendLine("RST 18H");
            testProgram.AppendLine("ORG 18H");
            testProgram.AppendLine("LD A,3");
            testProgram.AppendLine("RST 20H");
            testProgram.AppendLine("ORG 20H");
            testProgram.AppendLine("LD A,4");
            testProgram.AppendLine("RST 28H");
            testProgram.AppendLine("ORG 28H");
            testProgram.AppendLine("LD A,5");
            testProgram.AppendLine("RST 30H");
            testProgram.AppendLine("ORG 30H");
            testProgram.AppendLine("LD A,6");
            testProgram.AppendLine("RST 38H");
            testProgram.AppendLine("ORG 38H");
            testProgram.AppendLine("LD A,7");
            testProgram.AppendLine("RST 00H");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(17);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/CallAndReturn/Logs/Check_Instruction_122_RST_ResetAddress"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_59_LD_Register_Number8()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD H,30");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("LD IXl,55");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(2);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Load_8Bit/Logs/Check_Instruction_59_LD_Register_Number8"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_131_SET_Bit_IndexedAddress()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD IY,100");
            testProgram.AppendLine("LD (IY+1),0");
            testProgram.AppendLine("SET 7,(IY+1)");
            testProgram.AppendLine("LD A,(IY+1)");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(4);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/BitSetResetAndTest/Logs/Check_Instruction_131_SET_Bit_IndexedAddress"))
            {
                throw new Exception("Log compare failed");
            }
        }
        /// <summary>
        /// Utility method used to compare execution log with arithmetic operations results (16 bits arithmetic)
        /// </summary>
        private static void Compare16bitsExecutionResultsWithSample(string sampleProgramFileName, string sampleResultFileName, int instructionsPerLine)
        {
            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(sampleProgramFileName, Encoding.UTF8, false);

            Stream stream = PlatformSpecific.GetStreamForProjectFile(sampleResultFileName);
            using (StreamReader reader = new StreamReader(stream))
            {
                string line = null;
                while ((line = reader.ReadLine()) != null)
                {
                    testSystem.ExecuteInstructionCount(instructionsPerLine);

                    string[] columns = line.Split(';');
                    string HHexValue = columns[3];
                    byte HByteValue = Convert.ToByte(HHexValue, 16);
                    string LHexValue = columns[4];
                    byte LByteValue = Convert.ToByte(LHexValue, 16);
                    string FBinValue = columns[5];
                    byte FByteValue = Convert.ToByte(FBinValue, 2);

                    if (testSystem.CPU.L != LByteValue)
                    {
                        throw new Exception(String.Format("Error line {0}, L = {1}", line, String.Format("{0:X}", testSystem.CPU.L)));
                    }
                    else if (testSystem.CPU.H != HByteValue)
                    {
                        throw new Exception(String.Format("Error line {0}, H = {1}", line, String.Format("{0:X}", testSystem.CPU.H)));
                    }
                    // Ignore undocumented flags 3 and 5 : 11010111 = 215
                    else if ((testSystem.CPU.F & 215) != (FByteValue & 215))
                    {
                        throw new Exception(String.Format("Error line {0}, F = {1}", line, Convert.ToString(testSystem.CPU.F, 2)));
                    }
                }
            }
        }
        public static void Check_Instruction_36_DJNZ_RelativeDisplacement()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,0");
            testProgram.AppendLine("LD B,3");
            testProgram.AppendLine("INC A");
            testProgram.AppendLine("DJNZ -1");
            testProgram.AppendLine("LD A,0FFH");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(9);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Jump/Logs/Check_Instruction_36_DJNZ_RelativeDisplacement"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_39_EX_Register16Address_Register16()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD BC,1000");
            testProgram.AppendLine("LD HL,2000");
            testProgram.AppendLine("LD IX,3000");
            testProgram.AppendLine("LD IY,4000");
            testProgram.AppendLine("PUSH BC");
            testProgram.AppendLine("EX (SP),HL");
            testProgram.AppendLine("EX (SP),IX");
            testProgram.AppendLine("EX (SP),IY");
            testProgram.AppendLine("POP BC");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(9);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/ExchangeBlockTransferAndSearch/Logs/Check_Instruction_39_EX_Register16Address_Register16"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_StackMemoryReadAndWrite()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,10");
            testProgram.AppendLine("PUSH AF");
            testProgram.AppendLine("POP BC");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
               CPUStateLogger.CPUStateElements.InternalState |
               CPUStateLogger.CPUStateElements.Registers |
               CPUStateLogger.CPUStateElements.Buses |
               CPUStateLogger.CPUStateElements.ControlPins,
               new Z80CPU.LifecycleEventType[] {
                    Z80CPU.LifecycleEventType.HalfTState,
                    Z80CPU.LifecycleEventType.InstructionEnd,
                    Z80CPU.LifecycleEventType.InstructionStart,
                    Z80CPU.LifecycleEventType.MachineCycleEnd,
                    Z80CPU.LifecycleEventType.MachineCycleStart
                });
            testSystem.ExecuteInstructionCount(3);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("MachineCycles/Logs/Check_StackMemoryReadAndWrite"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_82_OR_IndexedAddress()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,10101010B");
            // TStatesByMachineCycle = "14 (4, 4, 3, 3)"
            testProgram.AppendLine("LD IX,97");
            // TStatesByMachineCycle = "19 (4, 4, 3,5,3)"
            testProgram.AppendLine("LD (IX+3),10001001B");
            // TStatesByMachineCycle = "19 (4, 4, 3, 5, 3)"
            testProgram.AppendLine("OR (IX+3)");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(4);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/Arithmetic_8bits/Logs/Check_Instruction_82_OR_IndexedAddress"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_7_ADD_Register_Register()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,5");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD B,252");
            // TStatesByMachineCycle = 1 (4)
            testProgram.AppendLine("ADD A,B");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("LD IXh,13");
            // TStatesByMachineCycle = "8 (4, 4)"
            testProgram.AppendLine("ADD A,IXh");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(5);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/Arithmetic_8bits/Logs/Check_Instruction_7_ADD_Register_Register"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_127_SBC_Register16_Register16()
        {
            string sampleProgramFileName = "ALU/Arithmetic16bits/Samples/testsbc16.asm";
            string sampleResultFileName = "ALU/Arithmetic16bits/Samples/resultsbc16.csv";
            Compare16bitsExecutionResultsWithSample(sampleProgramFileName, sampleResultFileName, 4);

            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "10 (4,3,3)"
            testProgram.AppendLine("LD BC,1");
            // TStatesByMachineCycle = "10 (4,3,3)"
            testProgram.AppendLine("LD DE,2");
            // TStatesByMachineCycle = "10 (4,3,3)"
            testProgram.AppendLine("LD HL,10");
            // TStatesByMachineCycle = "10 (4,3,3)"
            testProgram.AppendLine("LD SP,4");
            // TStatesByMachineCycle = "4"
            testProgram.AppendLine("SCF");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("SBC HL,BC");
            // TStatesByMachineCycle = "4"
            testProgram.AppendLine("SCF");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("SBC HL,DE");
            // TStatesByMachineCycle = "4"
            testProgram.AppendLine("SCF");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("SBC HL,HL");
            // TStatesByMachineCycle = "4"
            testProgram.AppendLine("SCF");
            // TStatesByMachineCycle = "11 (4,4,3)"
            testProgram.AppendLine("SBC HL,SP");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(12);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/Arithmetic16bits/Logs/Check_Instruction_127_SBC_Register16_Register16"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Flags(int launchAddress, string testDescription)
        {
            Console.Write(testDescription + "...");

            TestSystem testSystem = new TestSystem();

            string testSourcePath = "FlagsAndMemptr/z80tests-Flags.asm";
            using (Stream stream = PlatformSpecific.GetStreamForProjectFile(testSourcePath))
            {
                testSystem.LoadProgramInMemory(testSourcePath, stream, Encoding.UTF8, false);
                ((TestSystem._TestMemory)testSystem.Memory).SetReadOnlySection(0x500,0x5FF);
            }
            testSystem.CPU.InitProgramCounter((ushort)launchAddress);
            testSystem.CPU.InitRegister(Z80Simulator.Instructions.Register.I, 63);
            testSystem.AddBreakpointOnProgramLine(619);

            /*StringBuilder sb = new StringBuilder();
            int counter = 1;
            foreach (string variable in testSystem.ProgramInMemory.Variables.Keys)
            {
                if (variable.Contains("LAUNCH"))
                {
                    sb.AppendLine("public static int " + variable.Replace("LAUNCH", "ADDR") + " = 0x" + testSystem.ProgramInMemory.Variables[variable].GetValue(testSystem.ProgramInMemory.Variables, null).ToString("X4") +";");
                    sb.AppendLine("public static string " + variable.Replace("LAUNCH", "DESC") + " = \"" + testSystem.ProgramInMemory.Lines.First(line => (line.Comment !=null && line.Comment.Contains("test "+counter.ToString("D2")+" : "))).Comment.Split(':')[1].Trim() + "\";");
                    counter++;
                }
            }
            sb.Clear();
            for (counter = 1; counter <= 45; counter++)
            {
                sb.AppendLine("FlagsAndMemptrTests.Check_Flags(FlagsAndMemptrTests.FLAGS_TEST_" + counter.ToString("D2") + "_ADDR, FlagsAndMemptrTests.FLAGS_TEST_" + counter.ToString("D2") + "_DESC);");
            }*/

            /*CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
               CPUStateLogger.CPUStateElements.InternalState |
               CPUStateLogger.CPUStateElements.Registers,
               new Z80CPU.LifecycleEventType[] {
                    Z80CPU.LifecycleEventType.InstructionEnd
                });*/
            testSystem.ExecuteUntilNextBreakpoint();
            //logger.StopLogging();

            if (!(testSystem.CPU.A == 0 ||
                 (launchAddress == FLAGS_TEST_27_ADDR && testSystem.CPU.HL == 0x3063)))
            {
                throw new Exception("Flags test for " + testDescription + " failed : expected checksum " + testSystem.CPU.BC.ToString("X4") + " / computed checksum " + testSystem.CPU.HL.ToString("X4"));
            }

            Console.WriteLine("OK");
        }
        public static void Check_Instruction_66_LD_Register16_Address()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,12");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4253),A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,120");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4254),A");
            // TStatesByMachineCycle = "16 (4, 3, 3, 3, 3)"
            testProgram.AppendLine("LD HL,(4253)");
            // TStatesByMachineCycle = "20 (4, 4, 3, 3, 3, 3)"
            testProgram.AppendLine("LD DE,(4253)");
            // TStatesByMachineCycle = "20 (4, 4, 3, 3, 3, 3)"
            testProgram.AppendLine("LD IX,(4253)");
            // TStatesByMachineCycle = "20 (4, 4, 3, 3, 3, 3)"
            testProgram.AppendLine("LD SP,(4253)");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(8);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Load16Bit/Logs/Check_Instruction_66_LD_Register16_Address"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Memptr(int launchAddress, string testDescription)
        {
            TestSystem testSystem = new TestSystem();

            string testSourcePath = "FlagsAndMemptr/z80tests-Memptr.asm";
            using (Stream stream = PlatformSpecific.GetStreamForProjectFile(testSourcePath))
            {
                testSystem.LoadProgramInMemory(testSourcePath, stream, Encoding.UTF8, false);
            }
            testSystem.CPU.InitProgramCounter((ushort)launchAddress);
            testSystem.AddBreakpointOnProgramLine(1974);

            /*StringBuilder sb = new StringBuilder();
            int counter = 1;
            foreach (string variable in testSystem.ProgramInMemory.Variables.Keys)
            {
                if (variable.Contains("LAUNCH"))
                {
                    sb.AppendLine("public static int " + variable.Replace("LAUNCH", "ADDR") + " = 0x" + testSystem.ProgramInMemory.Variables[variable].GetValue(testSystem.ProgramInMemory.Variables, null).ToString("X4") +";");
                    sb.AppendLine("public static string " + variable.Replace("LAUNCH", "DESC") + " = \"" + testSystem.ProgramInMemory.Lines.First(line => (line.Comment !=null && line.Comment.Contains("test "+counter.ToString("D2")+" : "))).Comment.Split(':')[1].Trim() + "\";");
                    counter++;
                }
            }
            sb.Clear();
            for (counter = 1; counter <= 58; counter++)
            {
                sb.AppendLine("FlagsAndMemptrTests.Check_Memptr(FlagsAndMemptrTests.MEMPTR_TEST_" + counter.ToString("D2") + "_ADDR, FlagsAndMemptrTests.MEMPTR_TEST_" + counter.ToString("D2") + "_DESC);");
            }*/

            /*CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
               CPUStateLogger.CPUStateElements.InternalState |
               CPUStateLogger.CPUStateElements.Registers,
               new Z80CPU.LifecycleEventType[] {
                    Z80CPU.LifecycleEventType.InstructionEnd
                });*/
            testSystem.ExecuteUntilNextBreakpoint();
            //logger.StopLogging();

            if (testSystem.CPU.A != 0)
            {
                throw new Exception("Memptr test for " + testDescription + " failed");
            }
        }
        public static void Check_Instruction_91_PUSH_Register16()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,21");
            // TStatesByMachineCycle = "10 (4, 3, 3)"
            testProgram.AppendLine("LD BC,4370");
            // TStatesByMachineCycle = "14 (4, 4, 3, 3)"
            testProgram.AppendLine("LD IY,4884");
            // TStatesByMachineCycle = "11 (5, 3, 3)"
            testProgram.AppendLine("PUSH AF");
            // TStatesByMachineCycle = "11 (5, 3, 3)"
            testProgram.AppendLine("PUSH BC");
            // TStatesByMachineCycle = "15 (4, 5, 3, 3)"
            testProgram.AppendLine("PUSH IY");
            // TStatesByMachineCycle = "10 (4, 3, 3)",
            testProgram.AppendLine("POP DE");
            // TStatesByMachineCycle = "10 (4, 3, 3)",
            testProgram.AppendLine("POP DE");
            // TStatesByMachineCycle = "10 (4, 3, 3)",
            testProgram.AppendLine("POP DE");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(9);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Load16Bit/Logs/Check_Instruction_91_PUSH_Register16"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_90_POP_Register16()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,17");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4253),A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,18");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4252),A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,19");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4251),A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,20");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4250),A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,21");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4249),A");
            // TStatesByMachineCycle = "7 (4,3)"
            testProgram.AppendLine("LD A,22");
            // TStatesByMachineCycle = "13 (4, 3, 3, 3)"
            testProgram.AppendLine("LD (4248),A");
            // TStatesByMachineCycle = "10 (4, 3, 3)"
            testProgram.AppendLine("LD SP,4248");
            // TStatesByMachineCycle = "10 (4, 3, 3)",
            testProgram.AppendLine("POP AF");
            // TStatesByMachineCycle = "10 (4, 3, 3)",
            testProgram.AppendLine("POP HL");
            // TStatesByMachineCycle = "14 (4, 4, 3, 3)"
            testProgram.AppendLine("POP IX");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(16);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Load16Bit/Logs/Check_Instruction_90_POP_Register16"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_42_IM_InterruptMode()
        {
            StringBuilder testProgram = new StringBuilder();
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("IM 2");
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("IM 1");
            // TStatesByMachineCycle = "8 (4,4)"
            testProgram.AppendLine("IM 0");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(3);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/CPUControl/Logs/Check_Instruction_42_IM_InterruptMode"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_InstructionSet(int launchAddress, string testDescription)
        {
            TestSystem testSystem = new TestSystem();

            string testSourcePath = "Zexall/zexall2-Tests.asm";
            using (Stream stream = PlatformSpecific.GetStreamForProjectFile(testSourcePath))
            {
                testSystem.LoadProgramInMemory(testSourcePath, stream, Encoding.UTF8, false);
            }

            /*string[] testNames = new string[] { "SCFOP","CCFOP","SCFCCF","CCFSCF","BITA","BITHL","BITX","BITZ80","DAAOP","CPLOP","ADC16","ADD16","ADD16X",
            "ADD16Y","ALU8I","ALU8R","ALU8RX","ALU8X","CPD1","CPI1","INCA","INCB","INCBC","INCC","INCD","INCDE","INCE","INCH","INCHL","INCIX","INCIY",
            "INCL","INCM","INCSP","INCX","INCXH","INCXL","INCYH","INCYL","LD161","LD162","LD163","LD164","LD165","LD166","LD167","LD168","LD16IM","LD16IX",
            "LD8BD","LD8IM","LD8IMX","LD8IX1","LD8IX2","LD8IX3","LD8IXY","LD8RR","LD8RRX","LDA","LDD1","LDD2","LDI1","LDI2","NEGOP","RLDOP","ROT8080",
            "ROTXY","ROTZ80","SRZ80","SRZX","ST8IX1","ST8IX2","ST8IX3","STABD" };
            string[] testDescriptions = new string[] {"scf","ccf","scf+ccf","ccf+scf","bit n,a","bit n,(hl)","bit n,(<ix,iy>+1)","bit n,<b,c,d,e,h,l,(hl),a>",
            "daa","cpl","<adc,sbc> hl,<bc,de,hl,sp>","add hl,<bc,de,hl,sp>","add ix,<bc,de,ix,sp>","add iy,<bc,de,iy,sp>","aluop a,nn","aluop a,<b,c,d,e,h,l,(hl),a>",
            "aluop a,<ixh,ixl,iyh,iyl>","aluop a,(<ix,iy>+1)","cpd<r>","cpi<r>","<inc,dec> a","<inc,dec> b","<inc,dec> bc","<inc,dec> c","<inc,dec> d","<inc,dec> de",
            "<inc,dec> e","<inc,dec> h","<inc,dec> hl","<inc,dec> ix","<inc,dec> iy","<inc,dec> l","<inc,dec> (hl)","<inc,dec> sp","<inc,dec> (<ix,iy>+1)","<inc,dec> ixh",
            "<inc,dec> ixl","<inc,dec> iyh","<inc,dec> iyl","ld <bc,de>,(nnnn)","ld hl,(nnnn)","ld sp,(nnnn)","ld <ix,iy>,(nnnn)","ld (nnnn),<bc,de>","ld (nnnn),hl",
            "ld (nnnn),sp","ld (nnnn),<ix,iy>","ld <bc,de,hl,sp>,nnnn","ld <ix,iy>,nnnn","ld a,<(bc),(de)>","ld <b,c,d,e,h,l,(hl),a>,nn","ld (<ix,iy>+1),nn",
            "ld <b,c,d,e>,(<ix,iy>+1)","ld <h,l>,(<ix,iy>+1)","ld a,(<ix,iy>+1)","ld <ixh,ixl,iyh,iyl>,nn","ld <bcdehla>,<bcdehla>","ld <bcdexya>,<bcdexya>",
            "ld a,(nnnn) / ld (nnnn),a","ldd<r> (1)","ldd<r> (2)","ldi<r> (1)","ldi<r> (2)","neg","<rrd,rld>","<rlca,rrca,rla,rra>","shf/rot (<ix,iy>+1)",
            "shf/rot <b,c,d,e,h,l,(hl),a>","<set,res> n,<bcdehl(hl)a>","<set,res> n,(<ix,iy>+1)","ld (<ix,iy>+1),<b,c,d,e>","ld (<ix,iy>+1),<h,l>","ld (<ix,iy>+1),a",
            "ld (<bc,de>),a" };

            StringBuilder sb = new StringBuilder();
            int testIndex = 0;
            foreach (string testName in testNames)
            {
                sb.AppendLine("public static int ZEXALL2_TEST_"+testName+"_ADDR = 0x" + testSystem.ProgramInMemory.Variables[testName].GetValue(testSystem.ProgramInMemory.Variables, null).ToString("X4") +";");
                sb.AppendLine("public static string ZEXALL2_TEST_"+testName+"_DESC = \"" + testDescriptions[testIndex++] + "\";");
                //sb.AppendLine("ZexallTests.Check_InstructionSet(ZexallTests.ZEXALL2_TEST_" + testName + "_ADDR, ZexallTests.ZEXALL2_TEST_" + testName + "_DESC);");
            }*/

            // Sample results :
            // scf............................
            // CRC: 9e4dbc94 expected: ff4ceb48
            // ccf............................
            // CRC: 363b6874 expected: 573a3fa8
            // scf+ccf........................OK
            // ccf+scf........................OK

            // Input parameter :
            // HL = test address
            testSystem.CPU.InitRegister16(Register16.HL, (ushort)launchAddress);

            // Test execution routine : STT - address 1B86
            // Exit point : address 1BFB
            testSystem.CPU.InitProgramCounter(0x1B86);
            testSystem.AddBreakpointOnProgramLine(7190);

            /*CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
               CPUStateLogger.CPUStateElements.InternalState |
               CPUStateLogger.CPUStateElements.Registers,
               new Z80CPU.LifecycleEventType[] {
                    Z80CPU.LifecycleEventType.InstructionEnd
                });*/
            testSystem.ExecuteUntilNextBreakpoint();
            //logger.StopLogging();

            // Output parameters :
            // A = 0 success
            // A = 1 error
            // =>  HL points to expected CRC, CRCVAL is the address of observed CRC
            if (testSystem.CPU.A != 0)
            {
                int expCRCAddress = testSystem.CPU.HL; // Pointer in CRCTAB
                int obsCRCAddress = 0x1E5E; // CRCVAL

                int expCRC = 0x1000000 * testSystem.Memory.Cells[expCRCAddress] + 0x10000 * testSystem.Memory.Cells[expCRCAddress + 1] + 0x100 * testSystem.Memory.Cells[expCRCAddress + 2] + testSystem.Memory.Cells[expCRCAddress + 3];
                int obsCRC = 0x1000000 * testSystem.Memory.Cells[obsCRCAddress] + 0x10000 * testSystem.Memory.Cells[obsCRCAddress + 1] + 0x100 * testSystem.Memory.Cells[obsCRCAddress + 2] + testSystem.Memory.Cells[obsCRCAddress + 3];

                throw new Exception("Zexall instruction test for " + testDescription + " failed : observed CRC = " + obsCRC.ToString("X8") + ", expected CRC = " + expCRC.ToString("X8"));
            }
        }
        public static void Check_Speed()
        {
            #if (DEBUG)
            // Do not test speed when the code is not optimized
            #else
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("START: INC A");
            testProgram.AppendLine("JR START");

            TestSystem testSystem = new TestSystem(false);
            testSystem.LoadProgramInMemory(testProgram.ToString());

            // 14 millions TStates @ 3,5Mzh => 4 seconds in the real machine
            // The simulator should complete the loop faster
            long startTime = DateTime.Now.Ticks;
            for (int i = 0; i < 14000000; i++)
            {
                testSystem.Clock.Tick();
            }
            long endTime = DateTime.Now.Ticks;
            TimeSpan duration = new TimeSpan(endTime - startTime);
            double durationMs = duration.TotalMilliseconds;
            if (durationMs > 4000)
            {
                throw new Exception("Simlulation too slow : " + (int)durationMs + " ms");
            }
            else
            {
                // Console.WriteLine("Execution time < 4s : " + (int)durationMs + " ms");
            }
            #endif
        }
        public static void Check_Instruction_16_BIT_Bit_Register16Address()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD HL,10100000000000B");
            testProgram.AppendLine("LD BC,1");
            testProgram.AppendLine("ADD HL,BC");
            testProgram.AppendLine("LD (HL),00000001B");
            testProgram.AppendLine("BIT 0,(HL)");
            testProgram.AppendLine("LD (HL),10000000B");
            testProgram.AppendLine("BIT 7,(HL)");
            testProgram.AppendLine("BIT 4,(HL)");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(8);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("ALU/BitSetResetAndTest/Logs/Check_Instruction_16_BIT_Bit_Register16Address"))
            {
                throw new Exception("Log compare failed");
            }
        }
        public static void Check_Instruction_58_JR_FlagCondition_RelativeDisplacement()
        {
            StringBuilder testProgram = new StringBuilder();
            testProgram.AppendLine("LD A,0");
            testProgram.AppendLine("JR Z,NEAR");
            testProgram.AppendLine("ORG 10");
            testProgram.AppendLine("NEAR: JR NZ,FAR");
            testProgram.AppendLine("LD A,1");
            testProgram.AppendLine("ORG 100");
            testProgram.AppendLine("FAR: LD A,2");

            TestSystem testSystem = new TestSystem();
            testSystem.LoadProgramInMemory(testProgram.ToString());

            CPUStateLogger logger = new CPUStateLogger(testSystem.CPU);
            logger.StartLogging(
                CPUStateLogger.CPUStateElements.InternalState | CPUStateLogger.CPUStateElements.Registers,
                new Z80CPU.LifecycleEventType[] { Z80CPU.LifecycleEventType.MachineCycleEnd });
            testSystem.ExecuteInstructionCount(4);
            logger.StopLogging();

            if (!logger.CompareWithSavedLog("CPU/Jump/Logs/Check_Instruction_58_JR_FlagCondition_RelativeDisplacement"))
            {
                throw new Exception("Log compare failed");
            }
        }