/// <summary> /// Takes several opcode information and returns the best match of InstructionFormKind and InstructionOperandCountKind. /// </summary> /// <param name="opcodeNumber">The opcode number.</param> /// <param name="opcodeType">The opcode type as written in the table of opcodes.</param> /// <param name="operands">The operands to use.</param> /// <returns>A tuple of InstructionFormKind and InstructionOperandCountKind.</returns> /// <exception cref="ArgumentOutOfRangeException"> If <paramref name="opcodeNumber"/> has an invalid value or <paramref name="operands"/> an invalid count of operands.</exception> /// <exception cref="ArgumentException"> If <paramref name="operands"/> contains an unknown enum value.</exception> public static Tuple<InstructionFormKind, InstructionOperandCountKind> GetFormAndCount(byte opcodeNumber, OpcodeTypeKind opcodeType, ZOperand[] operands) { InstructionFormKind instructionForm; InstructionOperandCountKind operandCount; if (opcodeType == OpcodeTypeKind.ZeroOP) { if (opcodeNumber > 0xF) throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.ZeroOP must be in range of 0x0 - 0xF."); if (operands.Count() > 0) throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.ZeroOP no operands must be given."); instructionForm = InstructionFormKind.Short; operandCount = InstructionOperandCountKind.ZeroOP; } else if (opcodeType == OpcodeTypeKind.OneOP) { if (opcodeNumber > 0xF) throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.OneOP must be in range of 0x0 - 0xF."); if (operands.Count() != 1) throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.OneOP excactly operands must be given."); instructionForm = InstructionFormKind.Short; operandCount = InstructionOperandCountKind.OneOP; } else if (opcodeType == OpcodeTypeKind.TwoOP) { if (opcodeNumber > 0x1F) throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.TwoOP must be in range of 0x00 - 0x1F."); if (operands.Count() != 2) throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.TwoOP exactly two operands must be given."); // Could be in long form for two small constants or variables // But let's keep this logic dumb // We could save 1 byte per OpcodeTypeKind.TwoOP at best instructionForm = InstructionFormKind.Variable; operandCount = InstructionOperandCountKind.TwoOP; } else if (opcodeType == OpcodeTypeKind.Var) { if (opcodeNumber > 0x1F) throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.Var must be in range of 0x00-0x1F."); if (operands.Count() > 4) { if (operands.Count() <= 8) throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.Var only 0 to 4 operands can be given. Up to 8 operands are not supported yet (only call_vs2 and call_vn2 make use of this)."); else throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.Var only 0 to 4 operands can be given."); } instructionForm = InstructionFormKind.Variable; operandCount = InstructionOperandCountKind.Var; } else if (opcodeType == OpcodeTypeKind.Ext) { if (operands.Count() > 4) throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.Ext only 0 to 4 operands can be given."); instructionForm = InstructionFormKind.Extended; operandCount = InstructionOperandCountKind.Var; } else throw new ArgumentException(String.Format("Unknown OpcodeTypeKind '{0}'", opcodeType.ToString()), "opcodeType"); return new Tuple<InstructionFormKind, InstructionOperandCountKind>(instructionForm, operandCount); }