mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 20:39:01 +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.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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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.Text;
|
||||
|
||||
namespace Lost.JIT.AMD64
|
||||
namespace Lost.JIT.AMD64OLD
|
||||
{
|
||||
[Flags]
|
||||
enum Register: byte
|
||||
|
|
@ -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
|
||||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Lost.JIT.AMD64
|
||||
namespace Lost.JIT.AMD64OLD
|
||||
{
|
||||
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.Diagnostics;
|
||||
|
||||
namespace Lost.JIT.AMD64
|
||||
namespace Lost.JIT.AMD64OLD
|
||||
{
|
||||
class InstructionPrefix
|
||||
{
|
||||
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Lost.JIT.AMD64
|
||||
namespace Lost.JIT.AMD64OLD
|
||||
{
|
||||
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" />
|
||||
</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" />
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue