using X86Disassembler.X86.Operands; namespace X86Disassembler.X86.Handlers.FloatingPoint; /// /// Handler for floating-point load/store int16 and miscellaneous operations (DF opcode) /// public class LoadStoreInt16Handler : InstructionHandler { // Memory operand instruction types for DF opcode - load/store int16, misc private static readonly InstructionType[] MemoryInstructionTypes = [ InstructionType.Unknown, // fild - not in enum InstructionType.Unknown, // ?? InstructionType.Unknown, // fist - not in enum InstructionType.Unknown, // fistp - not in enum InstructionType.Unknown, // fbld - not in enum InstructionType.Unknown, // fild - 64-bit integer - not in enum InstructionType.Unknown, // fbstp - not in enum InstructionType.Unknown // fistp - 64-bit integer - not in enum ]; // Register-register operations mapping (mod=3) private static readonly Dictionary<(RegisterIndex Reg, RegisterIndex Rm), (InstructionType Type, FpuRegisterIndex OperandIndex, FpuRegisterIndex? SrcIndex)> RegisterOperations = new() { // FFREEP ST(i) { (RegisterIndex.A, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, null) }, { (RegisterIndex.A, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST1, null) }, { (RegisterIndex.A, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST2, null) }, { (RegisterIndex.A, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST3, null) }, { (RegisterIndex.A, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST4, null) }, { (RegisterIndex.A, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST5, null) }, { (RegisterIndex.A, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST6, null) }, { (RegisterIndex.A, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST7, null) }, // Special cases { (RegisterIndex.B, RegisterIndex.A), (InstructionType.Fxch, FpuRegisterIndex.ST0, null) }, { (RegisterIndex.C, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST1, null) }, { (RegisterIndex.D, RegisterIndex.A), (InstructionType.Fstp, FpuRegisterIndex.ST1, null) }, // FUCOMIP ST(0), ST(i) { (RegisterIndex.Di, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.Di, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.Di, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.Di, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.Di, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.Di, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.Di, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.Di, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) }, // FCOMIP ST(0), ST(i) { (RegisterIndex.Sp, RegisterIndex.A), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST0) }, { (RegisterIndex.Sp, RegisterIndex.C), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST1) }, { (RegisterIndex.Sp, RegisterIndex.D), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST2) }, { (RegisterIndex.Sp, RegisterIndex.B), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST3) }, { (RegisterIndex.Sp, RegisterIndex.Sp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST4) }, { (RegisterIndex.Sp, RegisterIndex.Bp), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST5) }, { (RegisterIndex.Sp, RegisterIndex.Si), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST6) }, { (RegisterIndex.Sp, RegisterIndex.Di), (InstructionType.Unknown, FpuRegisterIndex.ST0, FpuRegisterIndex.ST7) } }; /// /// Initializes a new instance of the LoadStoreInt16Handler class /// /// The instruction decoder that owns this handler public LoadStoreInt16Handler(InstructionDecoder decoder) : base(decoder) { } /// /// Checks if this handler can decode the given opcode /// /// The opcode to check /// True if this handler can decode the opcode public override bool CanHandle(byte opcode) { return opcode == 0xDF; } /// /// Decodes a floating-point instruction for load/store int16 and miscellaneous operations /// /// The opcode of the instruction /// The instruction object to populate /// True if the instruction was successfully decoded public override bool Decode(byte opcode, Instruction instruction) { if (!Decoder.CanReadByte()) { return false; } // Read the ModR/M byte var (mod, reg, rm, memoryOperand) = ModRMDecoder.ReadModRM(); // Check for FNSTSW AX (DF E0) if (mod == 3 && reg == RegisterIndex.Bp && rm == RegisterIndex.A) { // This is handled by the FnstswHandler, so we should not handle it here return false; } // Handle based on addressing mode if (mod != 3) // Memory operand { // Set the instruction type based on the reg field instruction.Type = MemoryInstructionTypes[(int)reg]; // Set the size based on the operation if (reg == RegisterIndex.A || reg == RegisterIndex.C || reg == RegisterIndex.D) // 16-bit integer operations { // Set to 16-bit for integer operations memoryOperand.Size = 16; } else if (reg == RegisterIndex.Di || reg == RegisterIndex.Bp) // 64-bit integer operations { // Set to 64-bit for integer operations memoryOperand.Size = 64; } else if (reg == RegisterIndex.Si || reg == RegisterIndex.Sp) // 80-bit packed BCD operations { // Set to 80-bit for BCD operations memoryOperand.Size = 80; } // Set the structured operands instruction.StructuredOperands = [ memoryOperand ]; } else // Register operand (ST(i)) { // Look up the instruction type in the register operations dictionary if (RegisterOperations.TryGetValue((reg, rm), out var operation)) { instruction.Type = operation.Type; // Create the FPU register operands var destOperand = OperandFactory.CreateFPURegisterOperand(operation.OperandIndex); // Set the structured operands if (operation.SrcIndex.HasValue) { var srcOperand = OperandFactory.CreateFPURegisterOperand(operation.SrcIndex.Value); instruction.StructuredOperands = [ destOperand, srcOperand ]; } else { instruction.StructuredOperands = [ destOperand ]; } } else { // Unknown instruction instruction.Type = InstructionType.Unknown; instruction.StructuredOperands = []; } } return true; } }