private static void ParseArgument([NotNull] IInstructionFetcher fetcher, OpCodeFlag flag, out int argument, out int argumentValue, out int argumentDisplacement, int argumentType, byte modrm) { var mod = (byte)((modrm >> 6) & 7); var reg = (byte)((modrm >> 3) & 7); var rm = (byte)(modrm & 7); switch (argumentType) { case ARG_AX: case ARG_CX: case ARG_DX: case ARG_BX: case ARG_SP: case ARG_BP: case ARG_SI: case ARG_DI: case ARG_IP: case ARG_CS: case ARG_DS: case ARG_ES: case ARG_SS: case ARG_FLAGS: argument = argumentType; argumentValue = ARG_NONE; argumentDisplacement = ARG_NONE; break; case ARG_AL: case ARG_CL: case ARG_DL: case ARG_BL: case ARG_AH: case ARG_CH: case ARG_DH: case ARG_BH: argument = ARG_BYTE_REGISTER; argumentValue = argumentType; argumentDisplacement = ARG_NONE; break; case ARG_1: argument = ARG_CONSTANT; argumentValue = 1; argumentDisplacement = ARG_NONE; break; case ARG_3: argument = ARG_CONSTANT; argumentValue = 3; argumentDisplacement = ARG_NONE; break; case ARG_IB: argument = ARG_CONSTANT; argumentValue = fetcher.FetchU8(); argumentDisplacement = ARG_NONE; if (flag.Has(OpCodeFlag.Signed)) { argumentValue = (sbyte)(byte)argumentValue; } break; case ARG_IW: argument = ARG_CONSTANT; argumentValue = fetcher.FetchU16(); argumentDisplacement = ARG_NONE; break; case ARG_JB: argument = ARG_CONSTANT; argumentValue = (sbyte)fetcher.FetchU8(); argumentDisplacement = ARG_NONE; break; case ARG_JW: argument = ARG_CONSTANT; argumentValue = fetcher.FetchU16(); argumentDisplacement = ARG_NONE; break; case ARG_S: Debug.Assert(reg < 4); argument = reg + ARG_ES; argumentValue = ARG_NONE; argumentDisplacement = ARG_NONE; break; case ARG_GB: argument = ARG_BYTE_REGISTER; argumentValue = ARG_AL + reg; argumentDisplacement = ARG_NONE; break; case ARG_GW: argument = reg; argumentValue = ARG_NONE; argumentDisplacement = ARG_NONE; break; case ARG_OB: case ARG_OW: argument = ARG_MEMORY; argumentValue = fetcher.FetchU16(); argumentDisplacement = ARG_NONE; break; case ARG_A: argument = ARG_FAR_MEMORY; var address = fetcher.FetchU16(); var segment = fetcher.FetchU16(); argumentValue = (int)(((uint)segment << 16) | address); argumentDisplacement = ARG_NONE; break; case ARG_EB: case ARG_EW: case ARG_M: switch (mod) { case 0: if (rm == 6) { argument = ARG_MEMORY; argumentValue = fetcher.FetchU16(); argumentDisplacement = ARG_NONE; } else { argument = ARG_DEREFERENCE; argumentValue = rm; argumentDisplacement = 0; } break; case 1: argument = ARG_DEREFERENCE; argumentValue = rm; argumentDisplacement = (sbyte)fetcher.FetchU8(); break; case 2: argument = ARG_DEREFERENCE; argumentValue = rm; argumentDisplacement = fetcher.FetchU16(); break; case 3: Debug.Assert(argumentType != ARG_M); if (argumentType == ARG_EB) { argument = ARG_BYTE_REGISTER; argumentValue = ARG_AL + rm; } else { argument = rm; argumentValue = ARG_NONE; } argumentDisplacement = ARG_NONE; break; default: throw new NotImplementedException(); } break; case ARG_NONE: argument = ARG_NONE; argumentValue = ARG_NONE; argumentDisplacement = ARG_NONE; break; default: throw new NotImplementedException(); } }
public static Instruction Decode([NotNull] IInstructionFetcher fetcher) { Instruction instruction; var opcode = fetcher.FetchU8(); instruction.Type = opCodes[opcode].Type; instruction.SegmentPrefix = Cpu8086.Register.Invalid; instruction.OpcodePrefix = 0; while (instruction.Type == InstructionType.Prefix) { switch (opcode) { case 0x26: instruction.SegmentPrefix = Cpu8086.Register.ES; break; case 0x2E: instruction.SegmentPrefix = Cpu8086.Register.CS; break; case 0x36: instruction.SegmentPrefix = Cpu8086.Register.SS; break; case 0x3E: instruction.SegmentPrefix = Cpu8086.Register.DS; break; case 0xF0: case 0xF2: case 0xF3: instruction.OpcodePrefix = opcode; break; default: throw new NotImplementedException(); } opcode = fetcher.FetchU8(); instruction.Type = opCodes[opcode].Type; } if (instruction.Type == InstructionType.EmulatorSpecial) { var opcode2 = fetcher.FetchU8(); Debug.Assert(opcode2 == 0x0F); } Debug.Assert(instruction.Type != InstructionType.Invalid); var argument1Type = opCodes[opcode].Argument1Type; var argument2Type = opCodes[opcode].Argument2Type; instruction.Flag = opCodes[opcode].Flag; byte rm = 0xFF; if (instruction.Flag.Has(OpCodeFlag.HasRM)) { rm = fetcher.FetchU8(); } if (instruction.Type == InstructionType.Group) { instruction.Type = ConvertFromGroup(opcode, rm); Debug.Assert(instruction.Type != InstructionType.Invalid); var reg = (byte)((rm >> 3) & 7); if (opcode == 0xF6 && reg == 0) { argument2Type = ARG_IB; } else if (opcode == 0xF7 && reg == 0) { argument2Type = ARG_IW; } else if (opcode == 0xFF && (reg == 3 || reg == 5)) { argument1Type = ARG_M; } } ParseArgument(fetcher, instruction.Flag, out instruction.Argument1, out instruction.Argument1Value, out instruction.Argument1Displacement, argument1Type, rm); ParseArgument(fetcher, instruction.Flag, out instruction.Argument2, out instruction.Argument2Value, out instruction.Argument2Displacement, argument2Type, rm); return(instruction); }