Added OO-based basic parts of AMD64 jitter:

[+] Registers enumeration (only GPRs)
[+] Basic class ProcessorInstruction
[+] Base class InstructionOperand it's child GeneralPurposeRegister
[+] Added some abstraction to DestSourceInstruction
[+] Added stub for first instruction - AddWithCarry
This commit is contained in:
LostTheBlack_cp 2008-03-31 06:59:34 +00:00
parent 779bbdb31a
commit 498f293c8a
15 changed files with 451 additions and 308 deletions

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Lost.JIT.AMD64
{
[Serializable]
public sealed class AddWithCarry: DestSourceInstruction
{
public AddWithCarry(InstructionOperand dest, InstructionOperand source): base(dest, source)
{
}
public override void Compile(Stream dest)
{
throw new NotImplementedException();
}
public override int? Size
{
get { throw new NotImplementedException(); }
}
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lost.JIT.AMD64
{
[Serializable]
public abstract class DestSourceInstruction: ProcessorInstruction
{
public DestSourceInstruction(InstructionOperand dest, InstructionOperand source)
{
this.Dest = dest;
this.Source = source;
}
public InstructionOperand Dest { get; private set; }
public InstructionOperand Source { get; private set; }
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lost.JIT.AMD64
{
[Serializable]
public sealed class GeneralPurposeRegister: InstructionOperand
{
public GeneralPurposeRegister(Registers register, int size)
{
this.Register = register;
this.Size = size;
}
public int Size { get; private set; }
public Registers Register { get; private set; }
}
}

View file

@ -2,108 +2,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
namespace Lost.JIT.AMD64
{
class InstructionOperand
[Serializable]
public class InstructionOperand
{
public InstructionOperand(string value)
{
_stringValue = value;
}
static readonly Regex _regex = new Regex(
@"^(\s*(?<operand>(\w|\[|\]|\+|\-)+)\s*\,)*\s*$",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
internal static InstructionOperand[] GetOperands(string code)
{
if (code.Trim() != "") code += ",";
var match = _regex.Match(code);
var result = new InstructionOperand[match.Groups["operand"].Captures.Count];
for (int i = 0; i < result.Length; i++)
result[i] = InstructionOperand.Parse(match.Groups["operand"].Captures[i].Value);
return result;
}
private static InstructionOperand Parse(string operand)
{
return new InstructionOperand(operand);
}
string _stringValue;
public override string ToString()
{
return _stringValue;
}
#region Parsing stuff
public bool IsGeneralPurposeRegister
{
get
{
if (_isGeneralPurposeRegister == null)
throw new NotImplementedException();
return _isGeneralPurposeRegister.Value;
}
} bool? _isGeneralPurposeRegister;
public int Size
{
get
{
if (_size == null)
throw new NotImplementedException();
return _size.Value;
}
} int? _size;
public ulong Value
{
get
{
if (_value == null) throw new NotImplementedException();
return _value.Value;
}
} ulong? _value;
public Register Register
{
get
{
if (_register == null)
throw new NotImplementedException();
return _register.Value;
}
} Register? _register;
public bool IsImmediate
{
get
{
if (_immediate == null)
throw new NotImplementedException();
return _immediate.Value;
}
} bool? _immediate;
public void WriteTo(Stream dest)
{
Debug.Assert(IsImmediate);
ulong value = Value;
for (int i = 0; i < Size; i++, value >>= 8)
dest.WriteByte((byte)(value & 0xFF));
}
#endregion
}
}

View file

@ -2,200 +2,14 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
namespace Lost.JIT.AMD64
{
class ProcessorInstruction
[Serializable]
public abstract class ProcessorInstruction
{
const byte Lock = 0xF0;
const byte OperandSizeOverride = 0x66;
const byte AddressSizeOverride = 0x67;
const byte Rep = 0xF3;
const byte RepE = 0xF3;
const byte RepNE = 0xF2;
internal ProcessorInstruction()
{
_labels = new HashSet<InstructionLabel>();
_prefixes = new HashSet<InstructionPrefix>();
}
internal ProcessorInstruction(string opCode, InstructionOperand[] operands, InstructionLabel[] labels, InstructionPrefix[] prefixes, string comments)
{
_opCode = opCode;
_operands = new List<InstructionOperand>(operands);
_labels = new HashSet<InstructionLabel>(labels);
_prefixes = new HashSet<InstructionPrefix>(prefixes);
_comments = comments;
}
ICollection<InstructionLabel> Labels
{
get { return _labels; }
} HashSet<InstructionLabel> _labels;
ICollection<InstructionPrefix> Prefixes
{
get { return _prefixes; }
} HashSet<InstructionPrefix> _prefixes;
IList<InstructionOperand> Operands
{
get { return _operands; }
} List<InstructionOperand> _operands;
string OpCode
{
get { return _opCode; }
} string _opCode;
string Comments
{
get { return _comments; }
} string _comments;
#region Encoding
InstructionOperand Dest
{
get { return _operands[0]; }
}
InstructionOperand Source
{
get { return _operands[1]; }
}
#region Instructions
void AddWithCarry(Stream dest)
{
if (Dest.IsGeneralPurposeRegister)
if (Dest.Register == Register.AX && Source.IsImmediate)
{
switch (Dest.Size)
{
case 1:
if (Source.Size != null)
Debug.Assert(Source.Size == 1);
dest.WriteByte(0x14);
break;
case 2:
if (Source.Size != null)
Debug.Assert(Source.Size == 2);
dest.WriteByte(OperandSizeOverride);
dest.WriteByte(0x15);
break;
case 4:
if (Source.Size != null)
Debug.Assert(Source.Size == 4);
dest.WriteByte(0x15);
break;
case 8:
if (Source.Size != null)
Debug.Assert(Source.Size == 4);
dest.WriteByte((byte)Rex.Wide);
dest.WriteByte(0x15);
break;
default:
throw new NotSupportedException();
}
Source.WriteTo(dest);
return;
} //adc al/ax/etc, imm
if (Source.IsImmediate)
{
switch (Dest.Size)
{
case 1:
if (Source.Size != null)
Debug.Assert(Source.Size == 4);
dest.WriteByte(AddressSizeOverride);
dest.WriteByte(0x80);
dest.EncodeIndirectMemory(2, Dest.Register);
break;
}
Source.WriteTo(dest);
return;
}
Debug.Assert(false);
}
#endregion
public void Encode(Stream dest)
{
switch (_opCode)
{
case "adc":
AddWithCarry(dest);
break;
default:
throw new NotSupportedException(_opCode);
}
}
static void EncodeRegisterRegister(Rex rex, Register dest, Register source, byte opcode, Stream stream)
{
if (rex != Rex.None) stream.WriteByte((byte)rex);
stream.WriteByte(opcode);
stream.EncodeRegisters(dest, source);
}
static void EncodeRegister(Rex rex, Register dest, byte opcode, Stream stream)
{
if (rex != Rex.None) stream.WriteByte((byte)rex);
dest &= Register.Legacy;
Debug.Assert((opcode | (byte)Register.Legacy) == 0);
opcode |= (byte)dest;
stream.WriteByte(opcode);
}
#endregion
#region Parsing
public static ProcessorInstruction Parse(string code)
{
var labels = InstructionLabel.ExtractLabels(ref code);
var prefixes = InstructionPrefix.ExtractPrefixes(ref code);
var instr = ExtractInstruction(ref code);
var comments = ExtractComments(ref code);
var operands = InstructionOperand.GetOperands(code);
var result = new ProcessorInstruction(instr.ToUpper(), operands, labels, prefixes, comments);
return result;
}
static readonly Regex _regexComments = new Regex(
@"^(?<rest>.*)\/\/\s*(?<comments>.*)\s*$",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static string ExtractComments(ref string code)
{
var match = _regexComments.Match(code);
if (match == null) return null;
if (!match.Success) return null;
var value = match.Groups["comments"].Value;
code = match.Groups["rest"].Value;
return value;
}
static readonly Regex _regexInstruction = new Regex(
@"^\s*(?<instr>\w+)(?<rest>.*$)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static string ExtractInstruction(ref string code)
{
var match = _regexInstruction.Match(code);
var value = match.Groups["instr"].Value;
code = match.Groups["rest"].Value;
return value;
}
#endregion
public abstract int? Size { get; }
public abstract void Compile(Stream dest);
}
}

View file

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lost.JIT.AMD64
{
[Flags, Serializable]
public enum Registers
{
AX = 1 << 0,
BX = 1 << 3,
CX = 1 << 1,
DX = 1 << 2,
SI = 1 << 6,
DI = 1 << 7,
SP = 1 << 4,
BP = 1 << 5,
R8 = 1 << 8,
R9 = 1 << 9,
R10 = 1 << 10,
R11 = 1 << 11,
R12 = 1 << 12,
R13 = 1 << 13,
R14 = 1 << 14,
R15 = 1 << 15,
OldRegsMask = AX | BX | CX | DX | SI | DI | SP | BP,
}
public static class RegistersExtensions
{
static readonly Dictionary<int, int> regIndex = new Dictionary<int, int>();
static RegistersExtensions()
{
for (int i = 0; i < 16; i++)
regIndex.Add(1 << i, i);
}
public static int GetIndex(this Registers register)
{
register &= Registers.OldRegsMask;
return regIndex[(int)register];
}
}
}

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lost.JIT.AMD64
namespace Lost.JIT.AMD64OLD
{
[Flags]
enum Register: byte

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lost.JIT.AMD64
namespace Lost.JIT.AMD64OLD
{
[Obsolete("")]
class ImmediateOperand: InstructionOperand

View file

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Lost.JIT.AMD64
namespace Lost.JIT.AMD64OLD
{
class InstructionLabel
{

View file

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
namespace Lost.JIT.AMD64OLD
{
class InstructionOperand
{
public InstructionOperand(string value)
{
_stringValue = value;
}
static readonly Regex _regex = new Regex(
@"^(\s*(?<operand>(\w|\[|\]|\+|\-)+)\s*\,)*\s*$",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
internal static InstructionOperand[] GetOperands(string code)
{
if (code.Trim() != "") code += ",";
var match = _regex.Match(code);
var result = new InstructionOperand[match.Groups["operand"].Captures.Count];
for (int i = 0; i < result.Length; i++)
result[i] = InstructionOperand.Parse(match.Groups["operand"].Captures[i].Value);
return result;
}
private static InstructionOperand Parse(string operand)
{
return new InstructionOperand(operand);
}
string _stringValue;
public override string ToString()
{
return _stringValue;
}
#region Parsing stuff
public bool IsGeneralPurposeRegister
{
get
{
if (_isGeneralPurposeRegister == null)
throw new NotImplementedException();
return _isGeneralPurposeRegister.Value;
}
} bool? _isGeneralPurposeRegister;
public int Size
{
get
{
if (_size == null)
throw new NotImplementedException();
return _size.Value;
}
} int? _size;
public ulong Value
{
get
{
if (_value == null) throw new NotImplementedException();
return _value.Value;
}
} ulong? _value;
public Register Register
{
get
{
if (_register == null)
throw new NotImplementedException();
return _register.Value;
}
} Register? _register;
public bool IsImmediate
{
get
{
if (_immediate == null)
throw new NotImplementedException();
return _immediate.Value;
}
} bool? _immediate;
public void WriteTo(Stream dest)
{
Debug.Assert(IsImmediate);
ulong value = Value;
for (int i = 0; i < Size; i++, value >>= 8)
dest.WriteByte((byte)(value & 0xFF));
}
#endregion
}
}

View file

@ -5,7 +5,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
namespace Lost.JIT.AMD64
namespace Lost.JIT.AMD64OLD
{
class InstructionPrefix
{

View file

@ -5,7 +5,7 @@ using System.Text;
using System.Diagnostics;
using System.IO;
namespace Lost.JIT.AMD64
namespace Lost.JIT.AMD64OLD
{
static class ModRM
{

View file

@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
namespace Lost.JIT.AMD64OLD
{
class ProcessorInstruction
{
const byte Lock = 0xF0;
const byte OperandSizeOverride = 0x66;
const byte AddressSizeOverride = 0x67;
const byte Rep = 0xF3;
const byte RepE = 0xF3;
const byte RepNE = 0xF2;
internal ProcessorInstruction()
{
_labels = new HashSet<InstructionLabel>();
_prefixes = new HashSet<InstructionPrefix>();
}
internal ProcessorInstruction(string opCode, InstructionOperand[] operands, InstructionLabel[] labels, InstructionPrefix[] prefixes, string comments)
{
_opCode = opCode;
_operands = new List<InstructionOperand>(operands);
_labels = new HashSet<InstructionLabel>(labels);
_prefixes = new HashSet<InstructionPrefix>(prefixes);
_comments = comments;
}
ICollection<InstructionLabel> Labels
{
get { return _labels; }
} HashSet<InstructionLabel> _labels;
ICollection<InstructionPrefix> Prefixes
{
get { return _prefixes; }
} HashSet<InstructionPrefix> _prefixes;
IList<InstructionOperand> Operands
{
get { return _operands; }
} List<InstructionOperand> _operands;
string OpCode
{
get { return _opCode; }
} string _opCode;
string Comments
{
get { return _comments; }
} string _comments;
#region Encoding
InstructionOperand Dest
{
get { return _operands[0]; }
}
InstructionOperand Source
{
get { return _operands[1]; }
}
#region Instructions
void AddWithCarry(Stream dest)
{
if (Dest.IsGeneralPurposeRegister)
if (Dest.Register == Register.AX && Source.IsImmediate)
{
switch (Dest.Size)
{
case 1:
if (Source.Size != null)
Debug.Assert(Source.Size == 1);
dest.WriteByte(0x14);
break;
case 2:
if (Source.Size != null)
Debug.Assert(Source.Size == 2);
dest.WriteByte(OperandSizeOverride);
dest.WriteByte(0x15);
break;
case 4:
if (Source.Size != null)
Debug.Assert(Source.Size == 4);
dest.WriteByte(0x15);
break;
case 8:
if (Source.Size != null)
Debug.Assert(Source.Size == 4);
dest.WriteByte((byte)Rex.Wide);
dest.WriteByte(0x15);
break;
default:
throw new NotSupportedException();
}
Source.WriteTo(dest);
return;
} //adc al/ax/etc, imm
if (Source.IsImmediate)
{
switch (Dest.Size)
{
case 1:
if (Source.Size != null)
Debug.Assert(Source.Size == 4);
dest.WriteByte(AddressSizeOverride);
dest.WriteByte(0x80);
dest.EncodeIndirectMemory(2, Dest.Register);
break;
}
Source.WriteTo(dest);
return;
}
Debug.Assert(false);
}
#endregion
public void Encode(Stream dest)
{
switch (_opCode)
{
case "adc":
AddWithCarry(dest);
break;
default:
throw new NotSupportedException(_opCode);
}
}
static void EncodeRegisterRegister(Rex rex, Register dest, Register source, byte opcode, Stream stream)
{
if (rex != Rex.None) stream.WriteByte((byte)rex);
stream.WriteByte(opcode);
stream.EncodeRegisters(dest, source);
}
static void EncodeRegister(Rex rex, Register dest, byte opcode, Stream stream)
{
if (rex != Rex.None) stream.WriteByte((byte)rex);
dest &= Register.Legacy;
Debug.Assert((opcode | (byte)Register.Legacy) == 0);
opcode |= (byte)dest;
stream.WriteByte(opcode);
}
#endregion
#region Parsing
public static ProcessorInstruction Parse(string code)
{
var labels = InstructionLabel.ExtractLabels(ref code);
var prefixes = InstructionPrefix.ExtractPrefixes(ref code);
var instr = ExtractInstruction(ref code);
var comments = ExtractComments(ref code);
var operands = InstructionOperand.GetOperands(code);
var result = new ProcessorInstruction(instr.ToUpper(), operands, labels, prefixes, comments);
return result;
}
static readonly Regex _regexComments = new Regex(
@"^(?<rest>.*)\/\/\s*(?<comments>.*)\s*$",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static string ExtractComments(ref string code)
{
var match = _regexComments.Match(code);
if (match == null) return null;
if (!match.Success) return null;
var value = match.Groups["comments"].Value;
code = match.Groups["rest"].Value;
return value;
}
static readonly Regex _regexInstruction = new Regex(
@"^\s*(?<instr>\w+)(?<rest>.*$)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static string ExtractInstruction(ref string code)
{
var match = _regexInstruction.Match(code);
var value = match.Groups["instr"].Value;
code = match.Groups["rest"].Value;
return value;
}
#endregion
}
}

View file

@ -50,12 +50,18 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="JIT\AMD64\Enumerations.cs" />
<Compile Include="JIT\AMD64\ImmediateOperand.cs" />
<Compile Include="JIT\AMD64\InstructionLabel.cs" />
<Compile Include="JIT\AMD64OLD\Enumerations.cs" />
<Compile Include="JIT\AMD64OLD\ImmediateOperand.cs" />
<Compile Include="JIT\AMD64OLD\InstructionLabel.cs" />
<Compile Include="JIT\AMD64OLD\InstructionOperand.cs" />
<Compile Include="JIT\AMD64OLD\InstructionPrefix.cs" />
<Compile Include="JIT\AMD64OLD\ModRM.cs" />
<Compile Include="JIT\AMD64OLD\ProcessorInstruction.cs" />
<Compile Include="JIT\AMD64\AddWithCarry.cs" />
<Compile Include="JIT\AMD64\DestSourceInstruction.cs" />
<Compile Include="JIT\AMD64\Registers.cs" />
<Compile Include="JIT\AMD64\GeneralPurposeRegister.cs" />
<Compile Include="JIT\AMD64\InstructionOperand.cs" />
<Compile Include="JIT\AMD64\InstructionPrefix.cs" />
<Compile Include="JIT\AMD64\ModRM.cs" />
<Compile Include="JIT\AMD64\ProcessorInstruction.cs" />
<Compile Include="LostTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -13,15 +13,15 @@ namespace Lost
[STAThread]
static void Main(string[] args)
{
using (var source = new StreamReader(args[0]))
{
string srcLine;
while ((srcLine = source.ReadLine()) != null)
{
var op = ProcessorInstruction.Parse(srcLine);
Console.WriteLine(op);
}
}
//using (var source = new StreamReader(args[0]))
//{
// string srcLine;
// while ((srcLine = source.ReadLine()) != null)
// {
// var op = ProcessorInstruction.Parse(srcLine);
// Console.WriteLine(op);
// }
//}
Console.ReadKey();
}