mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 22:12:25 +00:00
885 lines
No EOL
49 KiB
C#
885 lines
No EOL
49 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using Indy.IL2CPU.Assembler.X86;
|
|
|
|
namespace Indy.IL2CPU.Tests.AssemblerTests.X86 {
|
|
public static partial class TestCodeGenerator {
|
|
private static string mOutFile;
|
|
class ConstraintsContainer {
|
|
public Constraints SourceInfo;
|
|
public Constraints DestInfo;
|
|
public Instruction.InstructionSizes InvalidSizes = Instruction.InstructionSizes.None;
|
|
public bool MemToMem = false;
|
|
public bool ImmediateToImmediate = false;
|
|
public bool CRToCR = false;
|
|
public InstructionPrefixes ValidPrefixes = InstructionPrefixes.None;
|
|
public Func<string, bool> TestIsValid;
|
|
}
|
|
|
|
public class TestState {
|
|
public string Description;
|
|
public bool Success;
|
|
public string Message;
|
|
}
|
|
|
|
class Constraints {
|
|
public bool TestMem32 = true;
|
|
public bool TestMem16 = true;
|
|
public bool TestMem8 = true;
|
|
public bool TestImmediate8 = true;
|
|
public bool TestImmediate16 = true;
|
|
public bool TestImmediate32 = true;
|
|
public bool TestRegisters = true;
|
|
public bool TestCR = false;
|
|
public bool TestSegments = false;
|
|
public IEnumerable<RegistersEnum> InvalidRegisters = new RegistersEnum[0];
|
|
}
|
|
|
|
private static Dictionary<Type, ConstraintsContainer> opcodesException;
|
|
|
|
private static void Initialize() {
|
|
var xTempPath = typeof(TestCodeGenerator).Assembly.Location;
|
|
xTempPath = xTempPath.Substring(0, xTempPath.LastIndexOf("source", StringComparison.InvariantCultureIgnoreCase) + "source".Length);
|
|
xTempPath = Path.Combine(xTempPath, "Indy.IL2CPU.Tests");
|
|
xTempPath = Path.Combine(xTempPath, "AssemblerTests");
|
|
xTempPath = Path.Combine(xTempPath, "X86");
|
|
mOutFile = Path.Combine(xTempPath, "AutoGeneratedTests.cs");
|
|
opcodesException = new Dictionary<Type, ConstraintsContainer>();
|
|
AddExceptions();
|
|
}
|
|
|
|
public static void Execute() {
|
|
Initialize();
|
|
if ((File.GetAttributes(mOutFile) & FileAttributes.ReadOnly) != 0) {
|
|
throw new Exception(String.Format("File '{0}' is readonly, please check the file out!", mOutFile));
|
|
}
|
|
using (var xOutput = new StreamWriter(mOutFile, false)) {
|
|
xOutput.WriteLine("using System;");
|
|
xOutput.WriteLine("using System.Collections.Generic;");
|
|
xOutput.WriteLine("using System.Linq;");
|
|
xOutput.WriteLine("using System.Text;");
|
|
xOutput.WriteLine("using Indy.IL2CPU.Assembler.X86;");
|
|
xOutput.WriteLine("using NUnit.Framework;");
|
|
xOutput.WriteLine();
|
|
xOutput.WriteLine("namespace Indy.IL2CPU.Tests.AssemblerTests.X86 {");
|
|
|
|
foreach (Type type in typeof(Instruction).Assembly.GetTypes()) {
|
|
GenerateSingle(type, xOutput);
|
|
}
|
|
xOutput.WriteLine("}");
|
|
}
|
|
}
|
|
|
|
private static void GenerateSingle(Type aType, StreamWriter aOutput) {
|
|
if (aType.IsAbstract) {
|
|
return;
|
|
}
|
|
if (!aType.IsSubclassOf(typeof(Instruction))) {
|
|
return;
|
|
}
|
|
//if (!Instruction.HasEncodingOptions(aType)) {
|
|
// WriteTestFixtureHeader(aType, aOutput);
|
|
// {
|
|
// aOutput.WriteLine("[Test]");
|
|
// aOutput.WriteLine("[Category(\"MissingEncodingOptions\")]");
|
|
// aOutput.WriteLine("public void DoTest(){");
|
|
// aOutput.WriteLine("Assert.Fail(\"No Encoding Options specified\");");
|
|
// aOutput.WriteLine("}");
|
|
// }
|
|
// WriteTestFixtureFooter(aType, aOutput);
|
|
// return;
|
|
//}
|
|
if (aType.IsSubclassOf(typeof(Assembler.X86.InstructionWithDestinationAndSourceAndSize))) {
|
|
if (aType.GetInterfaces().Contains(typeof(IInstructionWithCondition))) {
|
|
GenerateInstructionWithDestinationAndSourceAndSizeAndCondition(aType, aOutput);
|
|
} else {
|
|
GenerateInstructionWithDestinationAndSourceAndSize(aType, aOutput);
|
|
}
|
|
return;
|
|
}
|
|
if (aType.IsSubclassOf(typeof(Assembler.X86.InstructionWithDestinationAndSource))) {
|
|
GenerateInstructionWithDestinationAndSource(aType,
|
|
aOutput);
|
|
return;
|
|
}
|
|
if (aType.IsSubclassOf(typeof(Assembler.X86.InstructionWithDestinationAndSize))) {
|
|
GenerateInstructionWithDestinationAndSize(aType,
|
|
aOutput);
|
|
return;
|
|
}
|
|
if (aType.IsSubclassOf(typeof(Assembler.X86.InstructionWithDestination))) {
|
|
GenerateInstructionWithDestination(aType,
|
|
aOutput);
|
|
return;
|
|
}
|
|
if (aType.IsSubclassOf(typeof(Assembler.X86.InstructionWithSize))) {
|
|
if (aType.GetInterfaces().Contains(typeof(IInstructionWithPrefix))) {
|
|
GenerateInstructionWithSizeAndPrefixes(aType, aOutput);
|
|
} else {
|
|
GenerateInstructionWithSize(aType,
|
|
aOutput);
|
|
}
|
|
return;
|
|
}
|
|
if (aType.IsSubclassOf(typeof(Assembler.X86.Instruction))) {
|
|
GenerateSimpleInstruction(aType, aOutput);
|
|
return;
|
|
}
|
|
throw new Exception("Type not handled: " + aType.FullName);
|
|
}
|
|
|
|
private static void WriteTestFixtureHeader(Type aType, StreamWriter aOutput) {
|
|
aOutput.WriteLine("\t[TestFixture]");
|
|
aOutput.WriteLine("\tpublic partial class {0}Tests: BaseTest {{", aType.Name);
|
|
}
|
|
|
|
private static void WriteTestFixtureFooter(Type aType, StreamWriter aOutput) {
|
|
aOutput.WriteLine("\t}");
|
|
}
|
|
|
|
private static void WriteTestMethodHeader(string aName, StreamWriter aOutput) {
|
|
aOutput.WriteLine("\t\t[Test]");
|
|
aOutput.WriteLine("\t\tpublic void Test{0}() {{", aName);
|
|
}
|
|
|
|
private static void WriteTestMethodFooter(string aName, StreamWriter aOutput) {
|
|
aOutput.WriteLine("\t\t\tVerify();");
|
|
aOutput.WriteLine("\t\t}");
|
|
}
|
|
|
|
private static void WriteTestLine(StreamWriter aOutput, Type aType, string aFormat, params object[] aParams) {
|
|
string xLine = string.Format(aFormat, aParams);
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
var xData = opcodesException[aType];
|
|
if (xData.TestIsValid != null) {
|
|
if (!xData.TestIsValid(xLine)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
aOutput.WriteLine(xLine);
|
|
}
|
|
|
|
|
|
private static void GenerateSimpleInstruction(Type aType, StreamWriter aOutput) {
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
WriteTestMethodHeader("Instruction", aOutput);
|
|
{
|
|
aOutput.WriteLine("\t\t\tnew global::{0}();", aType.FullName);
|
|
}
|
|
WriteTestMethodFooter("Instruction", aOutput);
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
// todo: prefixes should be combined too.
|
|
private static IEnumerable<KeyValuePair<string, string[]>> GetPrefixPossibilities(Type aType) {
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].ValidPrefixes == InstructionPrefixes.None) {
|
|
yield return new KeyValuePair<string, string[]>("PrefixNone", new[] { "Prefixes = InstructionPrefixes.None" });
|
|
yield break;
|
|
}
|
|
var xResult = new List<string>();
|
|
foreach (InstructionPrefixes xValue in Enum.GetValues(typeof(InstructionPrefixes))) {
|
|
if ((opcodesException[aType].ValidPrefixes & xValue) == xValue) {
|
|
yield return new KeyValuePair<string, string[]>("Prefix" + xValue.ToString(), new[] { "Prefixes = InstructionPrefixes." + xValue.ToString() });
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void GenerateInstructionWithSizeAndPrefixes(Type aType, StreamWriter aOutput) {
|
|
ConstraintsContainer xInfo = null;
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
xInfo = opcodesException[aType];
|
|
}
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
foreach (var xPrefix in GetPrefixPossibilities(aType)) {
|
|
if (!(xInfo != null && ((xInfo.InvalidSizes & Instruction.InstructionSizes.DWord) != 0))) {
|
|
WriteTestMethodHeader(xPrefix.Key + "InstructionSize32", aOutput);
|
|
{
|
|
foreach (var xPrefixLine in xPrefix.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{Size = 32, {1}}};", aType.FullName, xPrefixLine);
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xPrefix.Key + "InstructionSize32", aOutput);
|
|
}
|
|
if (!(xInfo != null && ((xInfo.InvalidSizes & Instruction.InstructionSizes.Word) != 0))) {
|
|
WriteTestMethodHeader(xPrefix.Key + "InstructionSize16", aOutput);
|
|
{
|
|
foreach (var xPrefixLine in xPrefix.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{Size = 16, {1}}};", aType.FullName, xPrefixLine);
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xPrefix.Key + "InstructionSize16", aOutput);
|
|
}
|
|
if (!(xInfo != null && ((xInfo.InvalidSizes & Instruction.InstructionSizes.Byte) != 0))) {
|
|
WriteTestMethodHeader(xPrefix.Key + "InstructionSize8", aOutput);
|
|
{
|
|
foreach (var xPrefixLine in xPrefix.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{Size = 8, {1}}};", aType.FullName, xPrefixLine);
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xPrefix.Key + "InstructionSize8", aOutput);
|
|
}
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
private static void GenerateInstructionWithSize(Type aType, StreamWriter aOutput) {
|
|
ConstraintsContainer xInfo = null;
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
xInfo = opcodesException[aType];
|
|
}
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
if (!(xInfo != null && ((xInfo.InvalidSizes & Instruction.InstructionSizes.DWord) != 0))) {
|
|
WriteTestMethodHeader("InstructionSize32", aOutput);
|
|
{
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{Size = 32}};", aType.FullName);
|
|
}
|
|
WriteTestMethodFooter("InstructionSize32", aOutput);
|
|
}
|
|
if (!(xInfo != null && ((xInfo.InvalidSizes & Instruction.InstructionSizes.Word) != 0))) {
|
|
WriteTestMethodHeader("InstructionSize16", aOutput);
|
|
{
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{Size = 16}};", aType.FullName);
|
|
}
|
|
WriteTestMethodFooter("InstructionSize16", aOutput);
|
|
}
|
|
if (!(xInfo != null && ((xInfo.InvalidSizes & Instruction.InstructionSizes.Byte) != 0))) {
|
|
WriteTestMethodHeader("InstructionSize8", aOutput);
|
|
{
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{Size = 8}};", aType.FullName);
|
|
}
|
|
WriteTestMethodFooter("InstructionSize8", aOutput);
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
private static void GenerateInstructionWithDestination(Type aType, StreamWriter aOutput) {
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
foreach (var xItem in GetDestinationPossibilities(aType)) {
|
|
if (xItem.Value.Length > 0) {
|
|
WriteTestMethodHeader(xItem.Key, aOutput);
|
|
{
|
|
foreach (var xLine in xItem.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{{1}}};", aType.FullName, xLine);
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xItem.Key, aOutput);
|
|
}
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
private static bool ShouldTestMemorySource(Type aType, byte aSize) {
|
|
if (!opcodesException.ContainsKey(aType)) {
|
|
return true;
|
|
}
|
|
if (opcodesException[aType].SourceInfo == null) {
|
|
return true;
|
|
}
|
|
switch (aSize) {
|
|
case 8:
|
|
return opcodesException[aType].SourceInfo.TestMem8;
|
|
case 16:
|
|
return opcodesException[aType].SourceInfo.TestMem16;
|
|
case 32:
|
|
return opcodesException[aType].SourceInfo.TestMem32;
|
|
default:
|
|
throw new Exception("Wrong Size: " + aSize);
|
|
}
|
|
}
|
|
|
|
private static bool ShouldTestImmediateSource(Type aType, byte aSize) {
|
|
if (!opcodesException.ContainsKey(aType)) {
|
|
return true;
|
|
}
|
|
if (opcodesException[aType].SourceInfo == null) {
|
|
return true;
|
|
}
|
|
switch (aSize) {
|
|
case 8:
|
|
return opcodesException[aType].SourceInfo.TestImmediate8;
|
|
case 16:
|
|
return opcodesException[aType].SourceInfo.TestImmediate16;
|
|
case 32:
|
|
return opcodesException[aType].SourceInfo.TestImmediate32;
|
|
default:
|
|
throw new Exception("Wrong Size: " + aSize);
|
|
}
|
|
}
|
|
|
|
private static bool ShouldTestMemoryDestination(Type aType, byte aSize) {
|
|
if (!opcodesException.ContainsKey(aType)) {
|
|
return true;
|
|
}
|
|
if (opcodesException[aType].DestInfo == null) {
|
|
return true;
|
|
}
|
|
switch (aSize) {
|
|
case 8:
|
|
return opcodesException[aType].DestInfo.TestMem8;
|
|
case 16:
|
|
return opcodesException[aType].DestInfo.TestMem16;
|
|
case 32:
|
|
return opcodesException[aType].DestInfo.TestMem32;
|
|
default:
|
|
throw new Exception("Wrong Size: " + aSize);
|
|
}
|
|
}
|
|
|
|
private static bool ShouldTestImmediateDestination(Type aType, byte aSize) {
|
|
if (!opcodesException.ContainsKey(aType)) {
|
|
return true;
|
|
}
|
|
if (opcodesException[aType].DestInfo == null) {
|
|
return true;
|
|
}
|
|
switch (aSize) {
|
|
case 8:
|
|
return opcodesException[aType].DestInfo.TestImmediate8;
|
|
case 16:
|
|
return opcodesException[aType].DestInfo.TestImmediate16;
|
|
case 32:
|
|
return opcodesException[aType].DestInfo.TestImmediate32;
|
|
default:
|
|
throw new Exception("Wrong Size: " + aSize);
|
|
}
|
|
}
|
|
|
|
private static void GenerateInstructionWithDestinationAndSize(Type aType, StreamWriter aOutput) {
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
foreach (var xSize in new byte[] { 8, 16, 32 }) {
|
|
foreach (var xItem in GetDestinationWithSizePossibilities(aType, xSize)) {
|
|
if (xItem.Value.Length == 0) {
|
|
continue;
|
|
}
|
|
WriteTestMethodHeader(xItem.Key + "Size" + xSize, aOutput);
|
|
{
|
|
foreach (var xLine in xItem.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{{1}, Size = {2}}};", aType.FullName, xLine, xSize);
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xItem.Key + "Size" + xSize, aOutput);
|
|
}
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
private static IEnumerable<KeyValuePair<string, string[]>> GetDestinationPossibilities(Type aType) {
|
|
var xResult = new List<string>();
|
|
bool xFlag = true;
|
|
if (opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo != null) {
|
|
xFlag = false;
|
|
}
|
|
if (xFlag || opcodesException[aType].DestInfo.TestImmediate32) {
|
|
xResult.Add("DestinationValue = 300000");
|
|
}
|
|
if (xFlag || opcodesException[aType].DestInfo.TestImmediate16) {
|
|
xResult.Add("DestinationValue=30000");
|
|
}
|
|
if (xFlag || opcodesException[aType].DestInfo.TestImmediate8) {
|
|
xResult.Add("DestinationValue=30");
|
|
}
|
|
if (xResult.Count > 0) {
|
|
yield return new KeyValuePair<string, string[]>("ImmediateDestination",
|
|
xResult.ToArray());
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].DestInfo == null || opcodesException[aType].DestInfo.TestMem32) {
|
|
yield return new KeyValuePair<string, string[]>("8BitMemoryAddressDestination",
|
|
new string[] { "DestinationValue = 65, DestinationIsIndirect = true" });
|
|
yield return new KeyValuePair<string, string[]>("16BitMemoryAddressDestination",
|
|
new string[] { "DestinationValue = 650, DestinationIsIndirect = true" });
|
|
yield return new KeyValuePair<string, string[]>("32BitMemoryAddressDestination",
|
|
new string[] { "DestinationValue = 650000, DestinationIsIndirect = true" });
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].DestInfo.TestMem32) {
|
|
var xRegistersToSkip = new List<RegistersEnum>();
|
|
if (opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.InvalidRegisters != null) {
|
|
xRegistersToSkip.AddRange(opcodesException[aType].DestInfo.InvalidRegisters);
|
|
}
|
|
foreach (var xReg in Registers.GetRegisters()) {
|
|
if (xRegistersToSkip.Contains(xReg)) {
|
|
continue;
|
|
}
|
|
if (!Registers.Is32Bit(xReg)) {
|
|
continue;
|
|
}
|
|
if (Registers.IsCR(xReg)) {
|
|
continue;
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || (opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.TestMem32)) {
|
|
yield return new KeyValuePair<string, string[]>("MemoryAtRegister" + Registers.GetRegisterName(xReg) + "Destination",
|
|
new string[] {
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect=true", Registers.GetRegisterName(xReg)),
|
|
//offset 8
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect=true, DestinationDisplacement = 203", Registers.GetRegisterName(xReg)),
|
|
//offset 16
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect=true, DestinationDisplacement = 2030", Registers.GetRegisterName(xReg)),
|
|
//offset 32
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect=true, DestinationDisplacement = 203000", Registers.GetRegisterName(xReg))});
|
|
}
|
|
}
|
|
}
|
|
if(!opcodesException.ContainsKey(aType) || opcodesException[aType].DestInfo.TestRegisters) {
|
|
var xItems = new List<string>();
|
|
foreach (RegistersEnum register in Registers.GetRegisters())
|
|
{
|
|
if (!aType.Namespace.Contains("SSE") && (Registers.getXMMs().Contains(register)))
|
|
continue;
|
|
if (Registers.GetCRs().Contains(register) && (!opcodesException.ContainsKey(aType) || (opcodesException.ContainsKey(aType) && (!opcodesException[aType].DestInfo.TestCR))))
|
|
continue;
|
|
if ((!opcodesException.ContainsKey(aType) ||
|
|
(opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.InvalidRegisters != null &&
|
|
(opcodesException[aType].DestInfo.InvalidRegisters.Contains(register)))))
|
|
continue;
|
|
if (Registers.IsSegment(register) && !(opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.TestSegments)) {
|
|
continue;
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].DestInfo.InvalidRegisters.Count() == 0) {
|
|
if (Registers.GetSize(register) != 32) {
|
|
continue;
|
|
}
|
|
}
|
|
xItems.Add("DestinationReg = Registers." + Registers.GetRegisterName(register));
|
|
}
|
|
if (xItems.Count > 0) {
|
|
yield return new KeyValuePair<string, string[]>("RegisterDestination",
|
|
xItems.ToArray());
|
|
}
|
|
}
|
|
yield break;
|
|
}
|
|
|
|
private static IEnumerable<KeyValuePair<string, string[]>> GetSourcePossibilities(Type aType) {
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].SourceInfo == null || opcodesException[aType].SourceInfo.TestImmediate32) {
|
|
yield return new KeyValuePair<string, string[]>("ImmediateSource",
|
|
new string[] { "SourceValue = 30", "SourceValue = 300", "SourceValue = 300000" });
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].SourceInfo == null || opcodesException[aType].SourceInfo.TestMem32) {
|
|
yield return new KeyValuePair<string, string[]>("8BitMemoryAddressSource",
|
|
new string[] { "SourceValue = 65, SourceIsIndirect = true" });
|
|
yield return new KeyValuePair<string, string[]>("16BitMemoryAddressSource",
|
|
new string[] { "SourceValue = 650, SourceIsIndirect = true" });
|
|
yield return new KeyValuePair<string, string[]>("32BitMemoryAddressSource",
|
|
new string[] { "SourceValue = 650000, SourceIsIndirect = true" });
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].SourceInfo.TestMem32) {
|
|
var xRegistersToSkip = new List<RegistersEnum>();
|
|
if (opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.InvalidRegisters != null) {
|
|
xRegistersToSkip.AddRange(opcodesException[aType].SourceInfo.InvalidRegisters);
|
|
}
|
|
foreach (var xReg in Registers.GetRegisters()) {
|
|
if (xRegistersToSkip.Contains(xReg)) {
|
|
continue;
|
|
}
|
|
if (!Registers.Is32Bit(xReg)) {
|
|
continue;
|
|
}
|
|
if (Registers.IsCR(xReg)) {
|
|
continue;
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || (opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.TestMem32)) {
|
|
yield return new KeyValuePair<string, string[]>("MemoryAtRegister" + Registers.GetRegisterName(xReg) + "Source",
|
|
new string[] {
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect=true", Registers.GetRegisterName(xReg)),
|
|
//offset 8
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect=true, SourceDisplacement = 203", Registers.GetRegisterName(xReg)),
|
|
//offset 16
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect=true, SourceDisplacement = 2030", Registers.GetRegisterName(xReg)),
|
|
//offset 32
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect=true, SourceDisplacement = 203000", Registers.GetRegisterName(xReg))});
|
|
}
|
|
}
|
|
}
|
|
if(!opcodesException.ContainsKey(aType) || opcodesException[aType].SourceInfo.TestRegisters) {
|
|
var xItems = new List<string>();
|
|
foreach (RegistersEnum register in Registers.GetRegisters())
|
|
{
|
|
if (!aType.Namespace.Contains("SSE") && (Registers.getXMMs().Contains(register)))
|
|
continue;
|
|
if (Registers.GetCRs().Contains(register) && (!opcodesException.ContainsKey(aType) || (opcodesException.ContainsKey(aType) && (!opcodesException[aType].SourceInfo.TestCR))))
|
|
continue;
|
|
if ((!opcodesException.ContainsKey(aType) ||
|
|
(opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.InvalidRegisters != null &&
|
|
(opcodesException[aType].SourceInfo.InvalidRegisters.Contains(register)))))
|
|
continue;
|
|
if (Registers.IsSegment(register) && !(opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.TestSegments)) {
|
|
continue;
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].SourceInfo.InvalidRegisters.Count() == 0) {
|
|
if (Registers.GetSize(register) != 32) {
|
|
continue;
|
|
}
|
|
}
|
|
xItems.Add("SourceReg = Registers." + Registers.GetRegisterName(register));
|
|
}
|
|
if (xItems.Count > 0) {
|
|
yield return new KeyValuePair<string, string[]>("RegisterSource",
|
|
xItems.ToArray());
|
|
}
|
|
}
|
|
yield break;
|
|
}
|
|
private static IEnumerable<KeyValuePair<string, string[]>> GetDestinationWithSizePossibilities(Type aType, byte aSize) {
|
|
var xItems = new List<string>();
|
|
{
|
|
if (aSize == 8 && ShouldTestImmediateDestination(aType, aSize)) {
|
|
//Test Immediate 8
|
|
xItems.Add(String.Format("DestinationValue = 30"));
|
|
}
|
|
|
|
if (aSize == 16 && ShouldTestImmediateDestination(aType, aSize)) {
|
|
//Test Immediate 16
|
|
xItems.Add(String.Format("DestinationValue = 300"));
|
|
}
|
|
if (aSize == 32 && ShouldTestImmediateDestination(aType, aSize)) {
|
|
//Test Immediate 32
|
|
xItems.Add(String.Format("DestinationValue = 300000"));
|
|
}
|
|
}
|
|
yield return new KeyValuePair<string, string[]>("ImmediateDestination", xItems.ToArray());
|
|
xItems.Clear();
|
|
if (ShouldTestMemoryDestination(aType, aSize)) {
|
|
yield return new KeyValuePair<string, string[]>(String.Format("MemoryDestination", aSize),
|
|
new string[]{
|
|
//memory 8 bits address
|
|
//no offset
|
|
String.Format("DestinationValue = 65, DestinationIsIndirect = true"),
|
|
//memory 16 bits address
|
|
//no offset
|
|
String.Format("DestinationValue = 650, DestinationIsIndirect = true"),
|
|
// memory 32 bits address
|
|
//no offset
|
|
String.Format("DestinationValue = 650000, DestinationIsIndirect = true")});
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].DestInfo.TestRegisters) {
|
|
var xRegistersToSkip = new List<RegistersEnum>();
|
|
if (opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.InvalidRegisters != null) {
|
|
xRegistersToSkip.AddRange(opcodesException[aType].DestInfo.InvalidRegisters);
|
|
}
|
|
foreach (var xReg in Registers.GetRegisters()) {
|
|
if (xRegistersToSkip.Contains(xReg)) {
|
|
continue;
|
|
}
|
|
if (!Registers.Is32Bit(xReg)) {
|
|
continue;
|
|
}
|
|
if (Registers.IsCR(xReg)) {
|
|
continue;
|
|
}
|
|
if (ShouldTestMemoryDestination(aType, aSize)) {
|
|
yield return new KeyValuePair<string, string[]>("MemoryAtRegister" + Registers.GetRegisterName(xReg) + "Destination",
|
|
new string[] {
|
|
//memory
|
|
//no offset
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect = true", Registers.GetRegisterName(xReg)),
|
|
//offset 8
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect = true, DestinationDisplacement = 203", Registers.GetRegisterName(xReg)),
|
|
//offset 16
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect = true, DestinationDisplacement = 2030", Registers.GetRegisterName(xReg)),
|
|
//offset 32
|
|
String.Format("DestinationReg = Registers.{0}, DestinationIsIndirect = true, DestinationDisplacement = 203000", Registers.GetRegisterName(xReg))
|
|
});
|
|
}
|
|
}
|
|
xItems.Clear();
|
|
foreach (RegistersEnum register in Registers.GetRegisters())
|
|
{
|
|
if (!aType.Namespace.Contains("SSE") && (Registers.getXMMs().Contains(register)))
|
|
continue;
|
|
if (Registers.GetCRs().Contains(register) && (!opcodesException.ContainsKey(aType) || (opcodesException.ContainsKey(aType) && (!opcodesException[aType].DestInfo.TestCR))))
|
|
continue;
|
|
if ((!opcodesException.ContainsKey(aType) ||
|
|
(opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.InvalidRegisters != null &&
|
|
(opcodesException[aType].DestInfo.InvalidRegisters.Contains(register)))))
|
|
continue;
|
|
if (Registers.IsSegment(register) && !(opcodesException.ContainsKey(aType) && opcodesException[aType].DestInfo.TestSegments)) {
|
|
continue;
|
|
}
|
|
if (Registers.GetSize(register) == aSize) {
|
|
xItems.Add(String.Format("DestinationReg = Registers.{0}", Registers.GetRegisterName(register)));
|
|
}
|
|
}
|
|
if (xItems.Count > 0) {
|
|
yield return new KeyValuePair<string, string[]>("RegisterDestination", xItems.ToArray());
|
|
}
|
|
}
|
|
}
|
|
|
|
private static IEnumerable<KeyValuePair<string, string[]>> GetSourceWithSizePossibilities(Type aType, byte aSize) {
|
|
var xItems = new List<string>();
|
|
{
|
|
if (aSize == 8 && ShouldTestImmediateSource(aType, aSize)) {
|
|
//Test Immediate 8
|
|
xItems.Add(String.Format("SourceValue = 30"));
|
|
}
|
|
|
|
if (aSize == 16 && ShouldTestImmediateSource(aType, aSize)) {
|
|
//Test Immediate 16
|
|
xItems.Add(String.Format("SourceValue = 300"));
|
|
}
|
|
if (aSize == 32 && ShouldTestImmediateSource(aType, aSize)) {
|
|
//Test Immediate 32
|
|
xItems.Add(String.Format("SourceValue = 300000"));
|
|
}
|
|
}
|
|
yield return new KeyValuePair<string, string[]>("ImmediateSource", xItems.ToArray());
|
|
xItems.Clear();
|
|
if (ShouldTestMemorySource(aType, aSize)) {
|
|
yield return new KeyValuePair<string, string[]>(String.Format("MemorySource", aSize),
|
|
new string[]{
|
|
//memory 8 bits address
|
|
//no offset
|
|
String.Format("SourceValue = 65, SourceIsIndirect = true"),
|
|
//memory 16 bits address
|
|
//no offset
|
|
String.Format("SourceValue = 650, SourceIsIndirect = true"),
|
|
// memory 32 bits address
|
|
//no offset
|
|
String.Format("SourceValue = 650000, SourceIsIndirect = true"),
|
|
});
|
|
}
|
|
if (!opcodesException.ContainsKey(aType) || opcodesException[aType].SourceInfo.TestRegisters) {
|
|
var xRegistersToSkip = new List<RegistersEnum>();
|
|
if (opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.InvalidRegisters != null) {
|
|
xRegistersToSkip.AddRange(opcodesException[aType].SourceInfo.InvalidRegisters);
|
|
}
|
|
foreach (var xReg in Registers.GetRegisters()) {
|
|
if (xRegistersToSkip.Contains(xReg)) {
|
|
continue;
|
|
}
|
|
if (!Registers.Is32Bit(xReg)) {
|
|
continue;
|
|
}
|
|
if (Registers.IsCR(xReg)) {
|
|
continue;
|
|
}
|
|
if (ShouldTestMemorySource(aType, aSize)) {
|
|
yield return new KeyValuePair<string, string[]>("MemoryAtRegister" + Registers.GetRegisterName(xReg) + "Source",
|
|
new string[] {
|
|
//memory
|
|
//no offset
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect = true", Registers.GetRegisterName(xReg)),
|
|
//offset 8
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect = true, SourceDisplacement = 203", Registers.GetRegisterName(xReg)),
|
|
//offset 16
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect = true, SourceDisplacement = 2030", Registers.GetRegisterName(xReg)),
|
|
//offset 32
|
|
String.Format("SourceReg = Registers.{0}, SourceIsIndirect = true, SourceDisplacement = 203000", Registers.GetRegisterName(xReg))
|
|
});
|
|
}
|
|
}
|
|
xItems.Clear();
|
|
foreach (RegistersEnum register in Registers.GetRegisters())
|
|
{
|
|
if (!aType.Namespace.Contains("SSE") && (Registers.getXMMs().Contains(register)))
|
|
continue;
|
|
if (Registers.GetCRs().Contains(register) && (!opcodesException.ContainsKey(aType) || (opcodesException.ContainsKey(aType) && (!opcodesException[aType].SourceInfo.TestCR))))
|
|
continue;
|
|
if ((!opcodesException.ContainsKey(aType) ||
|
|
(opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.InvalidRegisters != null &&
|
|
(opcodesException[aType].SourceInfo.InvalidRegisters.Contains(register)))))
|
|
continue;
|
|
if (Registers.IsSegment(register) && !(opcodesException.ContainsKey(aType) && opcodesException[aType].SourceInfo.TestSegments)) {
|
|
continue;
|
|
}
|
|
if (Registers.GetSize(register) == aSize) {
|
|
xItems.Add(String.Format("SourceReg = Registers.{0}", Registers.GetRegisterName(register)));
|
|
}
|
|
}
|
|
if (xItems.Count > 0) {
|
|
yield return new KeyValuePair<string, string[]>("RegisterSource", xItems.ToArray());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private static void GenerateInstructionWithDestinationAndSource(Type aType, StreamWriter aOutput) {
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
if (aType == typeof(Out)) {
|
|
System.Diagnostics.Debugger.Break();
|
|
}
|
|
foreach (var xSourceItem in GetSourcePossibilities(aType)) {
|
|
foreach (var xDestItem in GetDestinationPossibilities(aType)) {
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
if (!opcodesException[aType].MemToMem) {
|
|
if (xSourceItem.Key.Contains("Memory") && xDestItem.Key.Contains("Memory")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (!opcodesException[aType].ImmediateToImmediate) {
|
|
if (xSourceItem.Key.Contains("Value") && xDestItem.Key.Contains("Value") &&
|
|
!xSourceItem.Key.Contains("IsIndirect") && !xDestItem.Key.Contains("IsIndirect")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (!opcodesException[aType].CRToCR) {
|
|
bool xSourceContainsCR = false;
|
|
xSourceContainsCR |= xSourceItem.Key.Contains("CR0");
|
|
xSourceContainsCR |= xSourceItem.Key.Contains("CR1");
|
|
xSourceContainsCR |= xSourceItem.Key.Contains("CR2");
|
|
xSourceContainsCR |= xSourceItem.Key.Contains("CR3");
|
|
xSourceContainsCR |= xSourceItem.Key.Contains("CR4");
|
|
bool xDestContainsCR = false;
|
|
xDestContainsCR |= xDestItem.Key.Contains("CR0");
|
|
xDestContainsCR |= xDestItem.Key.Contains("CR1");
|
|
xDestContainsCR |= xDestItem.Key.Contains("CR2");
|
|
xDestContainsCR |= xDestItem.Key.Contains("CR3");
|
|
xDestContainsCR |= xDestItem.Key.Contains("CR4");
|
|
if (xSourceContainsCR && xDestContainsCR) {
|
|
continue;
|
|
}
|
|
}
|
|
} else {
|
|
// if no exceptions known for this opcode, we dont emit tests for Memory to Memory and Immediate to Immediate
|
|
if (xSourceItem.Key.Contains("Memory") && xDestItem.Key.Contains("Memory")) {
|
|
continue;
|
|
}
|
|
if (xSourceItem.Key.Contains("Value") && xDestItem.Key.Contains("Value") &&
|
|
!xSourceItem.Key.Contains("IsIndirect") && !xDestItem.Key.Contains("IsIndirect")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (xSourceItem.Value.Length == 0 || xDestItem.Value.Length == 0) {
|
|
continue;
|
|
}
|
|
WriteTestMethodHeader(xSourceItem.Key + xDestItem.Key, aOutput);
|
|
{
|
|
foreach (var xSourceLine in xSourceItem.Value) {
|
|
{
|
|
foreach (var xLine in xDestItem.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{{1}, {2}}};", aType.FullName, xSourceLine, xLine);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xSourceItem.Key + xDestItem.Key, aOutput);
|
|
}
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
private static IEnumerable<KeyValuePair<string, string[]>> GetConditionPossibilities(Type aType) {
|
|
foreach (var xValue in Enum.GetNames(typeof(ConditionalTestEnum))) {
|
|
yield return new KeyValuePair<string, string[]>("Condition" + xValue, new string[] { "Condition = ConditionalTestEnum." + xValue });
|
|
}
|
|
}
|
|
|
|
private static void GenerateInstructionWithDestinationAndSourceAndSizeAndCondition(Type aType, StreamWriter aOutput) {
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
foreach (var xSize in new byte[] { 8, 16, 32 }) {
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
if ((opcodesException[aType].InvalidSizes & ((Instruction.InstructionSizes)xSize)) == ((Instruction.InstructionSizes)xSize)) {
|
|
continue;
|
|
}
|
|
}
|
|
foreach (var xCondition in GetConditionPossibilities(aType)) {
|
|
foreach (var xSourceItem in GetSourceWithSizePossibilities(aType, xSize)) {
|
|
foreach (var xDestItem in GetDestinationWithSizePossibilities(aType, xSize)) {
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
if (!opcodesException[aType].MemToMem) {
|
|
if (xSourceItem.Key.Contains("Memory") && xDestItem.Key.Contains("Memory")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (!opcodesException[aType].ImmediateToImmediate) {
|
|
if (xSourceItem.Key.Contains("Value") && xDestItem.Key.Contains("Value") &&
|
|
!xSourceItem.Key.Contains("IsIndirect") && !xDestItem.Key.Contains("IsIndirect")) {
|
|
continue;
|
|
}
|
|
}
|
|
} else {
|
|
// if no exceptions known for this opcode, we dont emit tests for Memory to Memory and Immediate to Immediate
|
|
if (xSourceItem.Key.Contains("Memory") && xDestItem.Key.Contains("Memory")) {
|
|
continue;
|
|
}
|
|
if (xSourceItem.Key.Contains("Immediate") && xDestItem.Key.Contains("Immediate") &&
|
|
!xSourceItem.Key.Contains("IsIndirect") && !xDestItem.Key.Contains("IsIndirect")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (xSourceItem.Value.Length == 0 || xDestItem.Value.Length == 0 || xCondition.Value.Length == 0) {
|
|
continue;
|
|
}
|
|
WriteTestMethodHeader(xCondition.Key + xSourceItem.Key + xDestItem.Key + "Size" + xSize, aOutput);
|
|
{
|
|
foreach (var xCondLine in xCondition.Value) {
|
|
foreach (var xSourceLine in xSourceItem.Value) {
|
|
foreach (var xLine in xDestItem.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{{1}, {2}, Size = {3}, {4}}};", aType.FullName, xSourceLine, xLine, xSize, xCondLine);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xSourceItem.Key + xDestItem.Key + "Size" + xSize, aOutput);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
|
|
private static void GenerateInstructionWithDestinationAndSourceAndSize(Type aType, StreamWriter aOutput) {
|
|
WriteTestFixtureHeader(aType, aOutput);
|
|
{
|
|
foreach (var xSize in new byte[] { 8, 16, 32 }) {
|
|
foreach (var xSourceItem in GetSourceWithSizePossibilities(aType, xSize)) {
|
|
foreach (var xDestItem in GetDestinationWithSizePossibilities(aType, xSize)) {
|
|
if (opcodesException.ContainsKey(aType)) {
|
|
if (!opcodesException[aType].MemToMem) {
|
|
if (xSourceItem.Key.Contains("Memory") && xDestItem.Key.Contains("Memory")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (!opcodesException[aType].ImmediateToImmediate) {
|
|
if (xSourceItem.Key.Contains("Value") && xDestItem.Key.Contains("Value") &&
|
|
!xSourceItem.Key.Contains("IsIndirect") && !xDestItem.Key.Contains("IsIndirect")) {
|
|
continue;
|
|
}
|
|
}
|
|
} else {
|
|
// if no exceptions known for this opcode, we dont emit tests for Memory to Memory and Immediate to Immediate
|
|
if (xSourceItem.Key.Contains("Memory") && xDestItem.Key.Contains("Memory")) {
|
|
continue;
|
|
}
|
|
if (xSourceItem.Key.Contains("Immediate") && xDestItem.Key.Contains("Immediate") &&
|
|
!xSourceItem.Key.Contains("IsIndirect") && !xDestItem.Key.Contains("IsIndirect")) {
|
|
continue;
|
|
}
|
|
}
|
|
if (xSourceItem.Value.Length == 0 || xDestItem.Value.Length == 0) {
|
|
continue;
|
|
}
|
|
WriteTestMethodHeader(xSourceItem.Key + xDestItem.Key + "Size" + xSize, aOutput);
|
|
{
|
|
foreach (var xSourceLine in xSourceItem.Value) {
|
|
foreach (var xLine in xDestItem.Value) {
|
|
WriteTestLine(aOutput, aType, "\t\t\tnew global::{0}{{{1}, {2}, Size = {3}}};", aType.FullName, xSourceLine, xLine, xSize);
|
|
}
|
|
}
|
|
}
|
|
WriteTestMethodFooter(xSourceItem.Key + xDestItem.Key + "Size" + xSize, aOutput);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
WriteTestFixtureFooter(aType, aOutput);
|
|
}
|
|
}
|
|
} |