/// <summary> /// Gets a random number generator. /// </summary> /// <param name="variant">The opcode variant.</param> /// <returns>A <see cref="Random"/> object.</returns> /// <remarks> /// The seed of the RNG depends on the operands used by the opcode variant, /// but is constant across uses. /// </remarks> Random GetRandom(X86OpcodeVariantSpec variant) { string name = string.Join("_", from o in variant.Operands.Cast <X86OperandSpec>() select GetOperandManualName(o)); return(new Random(name.GetHashCode())); }
/// <summary> /// Writes a single test for a specific opcode variant. /// </summary> /// <param name="spec">The opcode spec.</param> /// <param name="variant">The opcode variant.</param> /// <param name="writer">The text writer to write to.</param> void WriteTest(X86OpcodeSpec spec, X86OpcodeVariantSpec variant, TextWriter writer) { var operandStrings = from o in variant.Operands.Cast <X86OperandSpec>() select GetOperandStrings(o.Type, o.Size, o.FixedRegister, GetRandom(variant)); string operands = string.Join(", ", from o in operandStrings select o.Item1); string instruction = spec.Mnemonic.ToUpperInvariant(); if (operandStrings.Any()) { instruction += " " + string.Join(", ", from o in operandStrings select o.Item2); } string feedback16; byte[] bytes16 = GetEncodedInstruction(DataSize.Bit16, instruction, out feedback16); string feedback32; byte[] bytes32 = GetEncodedInstruction(DataSize.Bit32, instruction, out feedback32); string feedback64; byte[] bytes64 = GetEncodedInstruction(DataSize.Bit64, instruction, out feedback64); string methodName = spec.Mnemonic.ToUpperInvariant(); if (variant.Operands.Any()) { methodName += "_" + string.Join("_", from o in variant.Operands.Cast <X86OperandSpec>() select IdentifierValidation.Replace(GetOperandManualName(o), "")); } writer.WriteLine(T + T + "[Test]"); writer.WriteLine(T + T + "public void {0}()", AsValidIdentifier(methodName)); writer.WriteLine(T + T + "{"); writer.WriteLine(T + T + T + "var instruction = Instr.{0}({1});", AsValidIdentifier(spec.Name), operands); writer.WriteLine(); writer.WriteLine(T + T + T + "// " + instruction); if (bytes16 != null) { writer.WriteLine(T + T + T + "AssertInstruction(instruction, DataSize.Bit16, new byte[] { " + string.Join(", ", from b in bytes16 select string.Format("0x{0:X2}", b)) + " });"); } else { writer.WriteLine(T + T + T + "AssertInstructionFail(instruction, DataSize.Bit16);"); } if (bytes32 != null) { writer.WriteLine(T + T + T + "AssertInstruction(instruction, DataSize.Bit32, new byte[] { " + string.Join(", ", from b in bytes32 select string.Format("0x{0:X2}", b)) + " });"); } else { writer.WriteLine(T + T + T + "AssertInstructionFail(instruction, DataSize.Bit32);"); } if (bytes64 != null) { writer.WriteLine(T + T + T + "AssertInstruction(instruction, DataSize.Bit64, new byte[] { " + string.Join(", ", from b in bytes64 select string.Format("0x{0:X2}", b)) + " });"); } else { writer.WriteLine(T + T + T + "AssertInstructionFail(instruction, DataSize.Bit64);"); } if (bytes16 == null && bytes32 == null && bytes64 == null) { throw new ScriptException(string.Format("Assembling {0} for the tests failed with the following messages:\n" + "16-bit: {1}\n32-bit: {2}\n64-bit: {3}", instruction, ProcessFeedback(feedback16), ProcessFeedback(feedback32), ProcessFeedback(feedback64))); } writer.WriteLine(T + T + "}"); }