public static InstructionFlowBehavior GenerateOutgoingCall(ProgramLine programLine, IDictionary<string, NumberExpression> programVariables)
        {
            if (programLine.Type == ProgramLineType.OpCodeInstruction)
            {
                // Analyse instruction effect on the program flow
                InstructionFlowBehavior instructionFlowBehavior = ProgramFlowAnalyzer.GetInstructionFlowBehavior(programLine.InstructionCode.InstructionType);

                // - check if the program flow continues to the next line
                programLine.ContinueToNextLine = (instructionFlowBehavior & InstructionFlowBehavior.ContinueToNextInstruction) > 0;

                // - check if the current program line can jump elswhere (either always or depending on a condition)
                if ((instructionFlowBehavior & InstructionFlowBehavior.JumpToKnownLocation) > 0)
                {
                    // Register the outgoing call address in the program line
                    CallSourceType callInstructionType;
                    InstructionLineParam targetAddressParameter;
                    AddressingMode targetAddressParameterType;

                    switch (programLine.InstructionType.Index)
                    {
                        // -- Call and jump instructions --
                        //  Instruction_18_CALL_Address                           PC => stack, PC = Param1 (ODh|ODl)
                        case 18:
                            callInstructionType = CallSourceType.CallInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[0];
                            targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                            break;
                        //  Instruction_19_CALL_FlagCondition_Address             (PC += instruction size) OR (PC => stack, PC = Param2 (ODh|ODl))
                        case 19:
                            callInstructionType = CallSourceType.CallInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[1];
                            targetAddressParameterType = programLine.InstructionType.Param2Type.Value;
                            break;
                        //  Instruction_36_DJNZ_RelativeDisplacement              (PC += instruction size) OR (PC += Param1 (OD))
                        case 36:
                            callInstructionType = CallSourceType.JumpInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[0];
                            targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                            break;
                        //  Instruction_54_JP_Address	                            PC = Param1 (ODh|ODl)
                        case 54:
                            callInstructionType = CallSourceType.JumpInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[0];
                            targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                            break;
                        //  Instruction_56_JP_FlagCondition_Address               (PC += instruction size) OR (PC = Param2 (ODh|ODl))
                        case 56:
                            callInstructionType = CallSourceType.JumpInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[1];
                            targetAddressParameterType = programLine.InstructionType.Param2Type.Value;
                            break;
                        //  Instruction_57_JR_RelativeDisplacement                PC += Param1 (OD)
                        case 57:
                            callInstructionType = CallSourceType.JumpInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[0];
                            targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                            break;
                        //  Instruction_58_JR_FlagCondition_RelativeDisplacement  (PC += instruction size) OR (PC += Param2 (OD))
                        case 58:
                            callInstructionType = CallSourceType.JumpInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[1];
                            targetAddressParameterType = programLine.InstructionType.Param2Type.Value;
                            break;
                        //  Instruction_122_RST_ResetAddress                      PC => stack, PC = (AddressModifiedPageZero)Param1
                        case 122:
                            callInstructionType = CallSourceType.CallInstruction;
                            targetAddressParameter = programLine.OpCodeParameters[0];
                            targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                            break;
                        default:
                            throw new NotImplementedException("Unexpected instruction type " + programLine.InstructionType.Index);
                    }

                    // Compute target address
                    int targetAddress;
                    if (targetAddressParameterType == AddressingMode.Relative && !(targetAddressParameter.NumberExpression is SymbolOperand))
                    {
                        targetAddress = programLine.LineAddress + targetAddressParameter.NumberExpression.GetValue(programVariables, programLine) /* + 2 not necessary because the assembler already adjusts when parsing the expression */;
                    }
                    else
                    {
                        targetAddress = targetAddressParameter.NumberExpression.GetValue(programVariables, programLine);
                    }

                    // Register call source and call target
                    CallSource callSource = new CallSource(callInstructionType, programLine.LineAddress, programLine);
                    CallTarget callTarget = new CallTarget(callSource, targetAddress);
                    programLine.OutgoingCall = callTarget;
                }

                return instructionFlowBehavior;
            }
            else
            {
                return 0;
            }
        }
        public static InstructionFlowBehavior GenerateOutgoingCall(ProgramLine programLine, IDictionary <string, NumberExpression> programVariables)
        {
            if (programLine.Type == ProgramLineType.OpCodeInstruction)
            {
                // Analyse instruction effect on the program flow
                InstructionFlowBehavior instructionFlowBehavior = ProgramFlowAnalyzer.GetInstructionFlowBehavior(programLine.InstructionCode.InstructionType);

                // - check if the program flow continues to the next line
                programLine.ContinueToNextLine = (instructionFlowBehavior & InstructionFlowBehavior.ContinueToNextInstruction) > 0;

                // - check if the current program line can jump elswhere (either always or depending on a condition)
                if ((instructionFlowBehavior & InstructionFlowBehavior.JumpToKnownLocation) > 0)
                {
                    // Register the outgoing call address in the program line
                    CallSourceType       callInstructionType;
                    InstructionLineParam targetAddressParameter;
                    AddressingMode       targetAddressParameterType;

                    switch (programLine.InstructionType.Index)
                    {
                    // -- Call and jump instructions --
                    //  Instruction_18_CALL_Address                           PC => stack, PC = Param1 (ODh|ODl)
                    case 18:
                        callInstructionType        = CallSourceType.CallInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[0];
                        targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                        break;

                    //  Instruction_19_CALL_FlagCondition_Address             (PC += instruction size) OR (PC => stack, PC = Param2 (ODh|ODl))
                    case 19:
                        callInstructionType        = CallSourceType.CallInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[1];
                        targetAddressParameterType = programLine.InstructionType.Param2Type.Value;
                        break;

                    //  Instruction_36_DJNZ_RelativeDisplacement              (PC += instruction size) OR (PC += Param1 (OD))
                    case 36:
                        callInstructionType        = CallSourceType.JumpInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[0];
                        targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                        break;

                    //  Instruction_54_JP_Address	                            PC = Param1 (ODh|ODl)
                    case 54:
                        callInstructionType        = CallSourceType.JumpInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[0];
                        targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                        break;

                    //  Instruction_56_JP_FlagCondition_Address               (PC += instruction size) OR (PC = Param2 (ODh|ODl))
                    case 56:
                        callInstructionType        = CallSourceType.JumpInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[1];
                        targetAddressParameterType = programLine.InstructionType.Param2Type.Value;
                        break;

                    //  Instruction_57_JR_RelativeDisplacement                PC += Param1 (OD)
                    case 57:
                        callInstructionType        = CallSourceType.JumpInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[0];
                        targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                        break;

                    //  Instruction_58_JR_FlagCondition_RelativeDisplacement  (PC += instruction size) OR (PC += Param2 (OD))
                    case 58:
                        callInstructionType        = CallSourceType.JumpInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[1];
                        targetAddressParameterType = programLine.InstructionType.Param2Type.Value;
                        break;

                    //  Instruction_122_RST_ResetAddress                      PC => stack, PC = (AddressModifiedPageZero)Param1
                    case 122:
                        callInstructionType        = CallSourceType.CallInstruction;
                        targetAddressParameter     = programLine.OpCodeParameters[0];
                        targetAddressParameterType = programLine.InstructionType.Param1Type.Value;
                        break;

                    default:
                        throw new NotImplementedException("Unexpected instruction type " + programLine.InstructionType.Index);
                    }

                    // Compute target address
                    int targetAddress;
                    if (targetAddressParameterType == AddressingMode.Relative && !(targetAddressParameter.NumberExpression is SymbolOperand))
                    {
                        targetAddress = programLine.LineAddress + targetAddressParameter.NumberExpression.GetValue(programVariables, programLine) /* + 2 not necessary because the assembler already adjusts when parsing the expression */;
                    }
                    else
                    {
                        targetAddress = targetAddressParameter.NumberExpression.GetValue(programVariables, programLine);
                    }

                    // Register call source and call target
                    CallSource callSource = new CallSource(callInstructionType, programLine.LineAddress, programLine);
                    CallTarget callTarget = new CallTarget(callSource, targetAddress);
                    programLine.OutgoingCall = callTarget;
                }

                return(instructionFlowBehavior);
            }
            else
            {
                return(0);
            }
        }
 public CallTarget(CallSource source, int targetAddress)
 {
     Source  = source;
     Address = targetAddress;
 }
 public CallTarget(CallSource source, int targetAddress)
 {
     Source = source;
     Address = targetAddress;
 }