mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 05:52:11 +00:00
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:
parent
779bbdb31a
commit
498f293c8a
15 changed files with 451 additions and 308 deletions
25
source/Tests/MathTest/Lost/JIT/AMD64/AddWithCarry.cs
Normal file
25
source/Tests/MathTest/Lost/JIT/AMD64/AddWithCarry.cs
Normal 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(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,108 +2,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,200 +2,14 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
namespace Lost.JIT.AMD64
|
||||||
{
|
{
|
||||||
class ProcessorInstruction
|
[Serializable]
|
||||||
|
public abstract class ProcessorInstruction
|
||||||
{
|
{
|
||||||
const byte Lock = 0xF0;
|
public abstract int? Size { get; }
|
||||||
const byte OperandSizeOverride = 0x66;
|
public abstract void Compile(Stream dest);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
source/Tests/MathTest/Lost/JIT/AMD64/Registers.cs
Normal file
45
source/Tests/MathTest/Lost/JIT/AMD64/Registers.cs
Normal 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
namespace Lost.JIT.AMD64OLD
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
enum Register: byte
|
enum Register: byte
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
namespace Lost.JIT.AMD64OLD
|
||||||
{
|
{
|
||||||
[Obsolete("")]
|
[Obsolete("")]
|
||||||
class ImmediateOperand: InstructionOperand
|
class ImmediateOperand: InstructionOperand
|
||||||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
namespace Lost.JIT.AMD64OLD
|
||||||
{
|
{
|
||||||
class InstructionLabel
|
class InstructionLabel
|
||||||
{
|
{
|
||||||
109
source/Tests/MathTest/Lost/JIT/AMD64OLD/InstructionOperand.cs
Normal file
109
source/Tests/MathTest/Lost/JIT/AMD64OLD/InstructionOperand.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
namespace Lost.JIT.AMD64OLD
|
||||||
{
|
{
|
||||||
class InstructionPrefix
|
class InstructionPrefix
|
||||||
{
|
{
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Text;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Lost.JIT.AMD64
|
namespace Lost.JIT.AMD64OLD
|
||||||
{
|
{
|
||||||
static class ModRM
|
static class ModRM
|
||||||
{
|
{
|
||||||
201
source/Tests/MathTest/Lost/JIT/AMD64OLD/ProcessorInstruction.cs
Normal file
201
source/Tests/MathTest/Lost/JIT/AMD64OLD/ProcessorInstruction.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,12 +50,18 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="JIT\AMD64\Enumerations.cs" />
|
<Compile Include="JIT\AMD64OLD\Enumerations.cs" />
|
||||||
<Compile Include="JIT\AMD64\ImmediateOperand.cs" />
|
<Compile Include="JIT\AMD64OLD\ImmediateOperand.cs" />
|
||||||
<Compile Include="JIT\AMD64\InstructionLabel.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\InstructionOperand.cs" />
|
||||||
<Compile Include="JIT\AMD64\InstructionPrefix.cs" />
|
|
||||||
<Compile Include="JIT\AMD64\ModRM.cs" />
|
|
||||||
<Compile Include="JIT\AMD64\ProcessorInstruction.cs" />
|
<Compile Include="JIT\AMD64\ProcessorInstruction.cs" />
|
||||||
<Compile Include="LostTest.cs" />
|
<Compile Include="LostTest.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ namespace Lost
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
using (var source = new StreamReader(args[0]))
|
//using (var source = new StreamReader(args[0]))
|
||||||
{
|
//{
|
||||||
string srcLine;
|
// string srcLine;
|
||||||
while ((srcLine = source.ReadLine()) != null)
|
// while ((srcLine = source.ReadLine()) != null)
|
||||||
{
|
// {
|
||||||
var op = ProcessorInstruction.Parse(srcLine);
|
// var op = ProcessorInstruction.Parse(srcLine);
|
||||||
Console.WriteLine(op);
|
// Console.WriteLine(op);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue