2025-07-20 20:45:10 +08:00
|
|
|
|
using SVM.Core;
|
2025-07-21 01:47:31 +08:00
|
|
|
|
using System;
|
2025-07-20 20:45:10 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-07-27 04:15:34 +10:00
|
|
|
|
using System.Diagnostics;
|
2025-07-21 01:47:31 +08:00
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Xml;
|
2025-07-21 04:06:11 +08:00
|
|
|
|
using System.Xml.Linq;
|
2025-07-21 01:47:31 +08:00
|
|
|
|
using System.Xml.Serialization;
|
2025-07-20 20:45:10 +08:00
|
|
|
|
|
|
|
|
|
|
namespace SVM.Assembler.Core
|
|
|
|
|
|
{
|
2025-07-21 01:47:31 +08:00
|
|
|
|
[Serializable]
|
2025-07-20 20:45:10 +08:00
|
|
|
|
public class ISADefinition
|
|
|
|
|
|
{
|
2025-07-24 23:09:01 +10:00
|
|
|
|
public Dictionary<string, byte> RegisterNames = new Dictionary<string, byte>();
|
2025-07-23 00:33:42 +10:00
|
|
|
|
public Dictionary<string, Dictionary<string, string>> Enums = new Dictionary<string, Dictionary<string, string>>();
|
2025-07-21 01:47:31 +08:00
|
|
|
|
public Dictionary<PrimaryInstruction, InstructionDefinition> InstructionDefinitions = new Dictionary<PrimaryInstruction, InstructionDefinition>();
|
|
|
|
|
|
[NonSerialized]
|
|
|
|
|
|
public Dictionary<string, InstructionDefinition> InstructionDefinitionAliases = new Dictionary<string, InstructionDefinition>();
|
2025-07-20 20:45:10 +08:00
|
|
|
|
public void Init()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in InstructionDefinitions)
|
|
|
|
|
|
{
|
2025-07-21 04:06:11 +08:00
|
|
|
|
foreach (var alias in item.Value.Aliases)
|
2025-07-20 20:45:10 +08:00
|
|
|
|
{
|
2025-07-21 01:47:31 +08:00
|
|
|
|
if (!InstructionDefinitionAliases.TryAdd(alias, item.Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
InstructionDefinitionAliases[alias] = item.Value;
|
|
|
|
|
|
}
|
2025-07-20 20:45:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-21 01:47:31 +08:00
|
|
|
|
static void PrintDepth(int depth)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < depth; i++)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.Write("\t");
|
2025-07-21 01:47:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
static void ShowNode(XmlNode node, int depth = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
PrintDepth(depth);
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"[+]{node.NodeType}:{node.Name}");
|
2025-07-21 01:47:31 +08:00
|
|
|
|
foreach (XmlAttribute item in node.Attributes)
|
|
|
|
|
|
{
|
|
|
|
|
|
PrintDepth(depth + 1);
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"[i]{item.NodeType}:{item.Name}={item.InnerText}");
|
2025-07-21 01:47:31 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (XmlElement item in node.ChildNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item is XmlNode cnode)
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowNode(cnode, depth + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
PrintDepth(depth + 1);
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.Write($"[?]{item.NodeType}:{item.Name}");
|
2025-07-21 01:47:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-22 22:27:15 +10:00
|
|
|
|
static bool ParseParameter(XmlNode node, ref InstructionDefinition instruction)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine("Parse:Parameter");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
InstructionParameter parameter = new InstructionParameter();
|
|
|
|
|
|
foreach (XmlNode subNode in node)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (subNode.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "MatchingItems":
|
|
|
|
|
|
foreach (XmlNode item in subNode.ChildNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item.Name == "Item")
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = item.Attributes.GetNamedItem("Id");
|
|
|
|
|
|
if (result == null) return false;
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"Item:{result.InnerText}");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
parameter.AllowedTokenIds.Add(result.InnerText);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "ExpectedValue":
|
|
|
|
|
|
{
|
|
|
|
|
|
var TypeAttr = subNode.Attributes.GetNamedItem("Type");
|
|
|
|
|
|
var PosAttr = subNode.Attributes.GetNamedItem("Pos");
|
|
|
|
|
|
var ConverterAttr = subNode.Attributes.GetNamedItem("Converter");
|
|
|
|
|
|
if (TypeAttr == null) return false;
|
|
|
|
|
|
if (PosAttr == null) return false;
|
|
|
|
|
|
if (ConverterAttr == null) return false;
|
|
|
|
|
|
if (!Enum.TryParse<SVMNativeTypes>(TypeAttr.InnerText, out var nType))
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"ParseSVMNativeTypes:{TypeAttr.InnerText}");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!int.TryParse(PosAttr.InnerText, out var pos))
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"ParseInt:{PosAttr.InnerText}");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
parameter.ExpectdValue.Type = nType;
|
|
|
|
|
|
parameter.ExpectdValue.Pos = pos;
|
|
|
|
|
|
parameter.ExpectdValue.Converter = ConverterAttr.InnerText;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2025-07-21 04:06:11 +08:00
|
|
|
|
static bool ParseDefinition(XmlNode node, ref ISADefinition definition)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"ParseDefinition:{node.Name}");
|
2025-07-21 04:06:11 +08:00
|
|
|
|
InstructionDefinition instDefinition = new InstructionDefinition();
|
2025-07-23 00:33:42 +10:00
|
|
|
|
var PIAttr = node.Attributes.GetNamedItem("PrimaryInstruction");
|
|
|
|
|
|
if (PIAttr == null) return false;
|
|
|
|
|
|
if (!Enum.TryParse<PrimaryInstruction>(PIAttr.InnerText, out var pi))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-07-27 04:43:13 +10:00
|
|
|
|
Console.WriteLine($"Definition of: {pi}");
|
2025-07-23 00:33:42 +10:00
|
|
|
|
instDefinition.PrimaryInstruction = pi;
|
2025-07-21 04:06:11 +08:00
|
|
|
|
foreach (XmlNode item in node.ChildNodes)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"{item.Name}");
|
2025-07-21 04:06:11 +08:00
|
|
|
|
switch (item.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Aliases":
|
|
|
|
|
|
foreach (XmlNode aliasNode in item.ChildNodes)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"Aliases->{aliasNode.Name}");
|
2025-07-21 04:06:11 +08:00
|
|
|
|
if (aliasNode.Name == "Alias")
|
|
|
|
|
|
{
|
|
|
|
|
|
instDefinition.Aliases.Add(aliasNode.Attributes["Name"].Value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "Parameters":
|
2025-07-22 22:27:15 +10:00
|
|
|
|
foreach (XmlNode parameterNode in item.ChildNodes)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"Parameters->{parameterNode.Name}");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
if (parameterNode.Name == "InstructionParameter")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ParseParameter(parameterNode, ref instDefinition))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-21 04:06:11 +08:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"???{item.Name}");
|
2025-07-21 04:06:11 +08:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-23 00:33:42 +10:00
|
|
|
|
definition.InstructionDefinitions.Add(pi, instDefinition);
|
2025-07-27 04:43:13 +10:00
|
|
|
|
foreach (var item in instDefinition.Aliases)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
definition.InstructionDefinitionAliases.Add(item, instDefinition);
|
|
|
|
|
|
}
|
2025-07-21 04:06:11 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
static bool ParseDefinitions(XmlNode node, ref ISADefinition definition)
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine("Parse:Definitions");
|
2025-07-21 04:06:11 +08:00
|
|
|
|
foreach (XmlNode item in node.ChildNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item.Name != "InstructionDefinition")
|
|
|
|
|
|
{
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine($"Not Matching:{item.Name}");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
|
2025-07-21 04:06:11 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-07-22 22:27:15 +10:00
|
|
|
|
if (ParseDefinition(item, ref definition) == false)
|
2025-07-21 04:06:11 +08:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2025-07-21 01:47:31 +08:00
|
|
|
|
public static bool TryParse(Stream inputStream, [MaybeNullWhen(false)] out ISADefinition definition)
|
|
|
|
|
|
{
|
|
|
|
|
|
XmlDocument xmlDocument = new XmlDocument();
|
|
|
|
|
|
xmlDocument.Load(inputStream);
|
2025-07-21 04:06:11 +08:00
|
|
|
|
ISADefinition isaDefinition = new ISADefinition();
|
2025-07-22 22:27:15 +10:00
|
|
|
|
foreach (XmlNode rootNode in xmlDocument.ChildNodes)
|
2025-07-21 01:47:31 +08:00
|
|
|
|
{
|
2025-07-22 22:27:15 +10:00
|
|
|
|
//ShowNode(rootNode, 0);
|
|
|
|
|
|
if (rootNode.Name == "ISARoot")
|
2025-07-21 04:06:11 +08:00
|
|
|
|
{
|
2025-07-22 22:27:15 +10:00
|
|
|
|
foreach (XmlNode item in rootNode)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
switch (item.Name)
|
2025-07-21 04:06:11 +08:00
|
|
|
|
{
|
2025-07-22 22:27:15 +10:00
|
|
|
|
case "Enums":
|
2025-07-23 00:33:42 +10:00
|
|
|
|
{
|
|
|
|
|
|
foreach (XmlNode enumNode in item.ChildNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (enumNode.Name == "Enum")
|
|
|
|
|
|
{
|
|
|
|
|
|
Dictionary<string, string> enumItem = new Dictionary<string, string>();
|
|
|
|
|
|
var EnumNameAttr = enumNode.Attributes.GetNamedItem("Name");
|
|
|
|
|
|
if (EnumNameAttr == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (XmlNode enumItemNode in enumNode.ChildNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
if (enumItemNode.Name == "Item")
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var keyAttr = enumItemNode.Attributes.GetNamedItem("Key");
|
|
|
|
|
|
var valueAttr = enumItemNode.Attributes.GetNamedItem("Value");
|
|
|
|
|
|
if (keyAttr == null || valueAttr == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
enumItem.Add(keyAttr.InnerText, valueAttr.InnerText);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
isaDefinition.Enums.Add(EnumNameAttr.InnerText, enumItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-22 22:27:15 +10:00
|
|
|
|
break;
|
2025-07-24 23:09:01 +10:00
|
|
|
|
case "Registers":
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (XmlNode enumNode in item.ChildNodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (enumNode.Name == "Item")
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var keyAttr = enumNode.Attributes.GetNamedItem("Key");
|
|
|
|
|
|
var valueAttr = enumNode.Attributes.GetNamedItem("Value");
|
|
|
|
|
|
if (keyAttr == null || valueAttr == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!byte.TryParse(valueAttr.InnerText, out var RegID))
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
isaDefinition.RegisterNames.Add(keyAttr.InnerText, RegID);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2025-07-22 22:27:15 +10:00
|
|
|
|
case "Definitions":
|
|
|
|
|
|
if (ParseDefinitions(item, ref isaDefinition) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
definition = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2025-07-27 04:15:34 +10:00
|
|
|
|
Trace.WriteLine("Unknown Node!");
|
2025-07-22 22:27:15 +10:00
|
|
|
|
break;
|
2025-07-21 04:06:11 +08:00
|
|
|
|
}
|
2025-07-22 22:27:15 +10:00
|
|
|
|
}
|
2025-07-21 04:06:11 +08:00
|
|
|
|
}
|
2025-07-21 01:47:31 +08:00
|
|
|
|
}
|
2025-07-22 22:27:15 +10:00
|
|
|
|
definition = isaDefinition;
|
|
|
|
|
|
return true;
|
2025-07-21 01:47:31 +08:00
|
|
|
|
}
|
2025-07-20 20:45:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|