public AGSBinaryInstruction(AGSOpcodes opcode, string mnemonic, params AGSBinaryArgumentType[] arguments)
 {
     Opcode    = opcode;
     Mnemonic  = mnemonic;
     Arguments = arguments;
 }
        //TODO(adm244): parse fixups in AGSScript and convert them, so that we only pass here AGSScript and ip
        public static AGSInstruction DisassembleInstruction(AGSScript script, AGSFixupType[] fixups, int[] code, int ip)
        {
            AGSInstruction instruction = new AGSInstruction();

            byte  instanceId = (byte)((code[ip] >> 24) & 0xFF);
            Int32 opcodeRaw  = (Int32)(code[ip] & 0x00FFFFFF);

            Debug.Assert(Enum.IsDefined(typeof(AGSOpcodes), opcodeRaw));

            AGSOpcodes opcode = (AGSOpcodes)(opcodeRaw);

            for (int i = 0; i < Instructions.Length; ++i)
            {
                if (Instructions[i].Opcode == opcode)
                {
                    instruction.InstanceId = instanceId;
                    instruction.Opcode     = opcode;
                    instruction.Mnemonic   = Instructions[i].Mnemonic;

                    Debug.Assert((ip + Instructions[i].ArgumentsCount) < code.Length);

                    instruction.Arguments = new AGSArgument[Instructions[i].ArgumentsCount];
                    for (int arg = 0; arg < instruction.ArgumentsCount; ++arg)
                    {
                        int index = ip + arg + 1;
                        int value = code[index];

                        instruction.Arguments[arg].Type       = AGSArgumentType.None;
                        instruction.Arguments[arg].IntValue   = 0;
                        instruction.Arguments[arg].FloatValue = float.NaN;
                        instruction.Arguments[arg].Name       = string.Empty;

                        switch (Instructions[i].Arguments[arg])
                        {
                        //NOTE(adm244): integer literal can also store a float number
                        // e.g. movlit instruction can load floats as well as ints
                        case AGSBinaryArgumentType.IntLiteral:
                        {
                            AGSFixupType fixuptype = fixups[index];
                            //Debug.Assert(Enum.IsDefined(typeof(AGSArgumentType), type));

                            AGSArgumentType type = GetArgumentType(fixuptype, Instructions[i].Arguments[arg]);
                            instruction.Arguments[arg].Type = type;

                            switch (type)
                            {
                            case AGSArgumentType.IntConstant:
                            case AGSArgumentType.StackOffset:
                                //FIX(adm244): get actual stack value from StackOffset
                                instruction.Arguments[arg].IntValue = value;
                                break;

                            case AGSArgumentType.ImportsOffset:
                                instruction.Arguments[arg].Name = script.Imports[value];
                                break;

                            case AGSArgumentType.FunctionOffset:
                                int exportIndex = GetExportIndex(script, value);
                                instruction.Arguments[arg].Name = script.Exports[exportIndex].Name;
                                break;

                            case AGSArgumentType.StringsOffset:
                                int stringIndex = GetStringIndex(script, value);
                                instruction.Arguments[arg].Name = '"' + script.Strings[stringIndex] + '"';
                                break;

                            default:
                                Debug.Assert(false, "Unknown argument type!");
                                break;
                            }
                        }
                        break;

                        case AGSBinaryArgumentType.FloatLiteral:
                            instruction.Arguments[arg].Type       = AGSArgumentType.FloatConstant;
                            instruction.Arguments[arg].FloatValue = IEEE754Utils.Int32BitsToFloat(value);
                            break;

                        case AGSBinaryArgumentType.Register:
                            instruction.Arguments[arg].Type     = AGSArgumentType.RegisterIndex;
                            instruction.Arguments[arg].IntValue = value;
                            instruction.Arguments[arg].Name     = RegisterNames[value];
                            break;

                        default:
                            Debug.Assert(false, "Unknown binary argument type!");
                            break;
                        }

                        Debug.Assert(instruction.Arguments[arg].Type != AGSArgumentType.None);
                    }

                    break;
                }
            }

            //NOTE(adm244): swap arguments to match "mov <dest>, <src>" pattern
            if (instruction.Opcode == AGSOpcodes.REGTOREG)
            {
                Debug.Assert(instruction.ArgumentsCount == 2);

                AGSArgument temp = instruction.Arguments[0];
                instruction.Arguments[0] = instruction.Arguments[1];
                instruction.Arguments[1] = temp;
            }

            return(instruction);
        }