diff --git a/source/XSharp/XSharp/Assembler/Gen1/Assembler.cs b/source/XSharp/XSharp/Assembler/Gen1/Assembler.cs index b5391550..cc7dee1d 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/Assembler.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/Assembler.cs @@ -173,7 +173,7 @@ public void Add(params Instruction[] aReaders) } // Allows to emit footers to the code and datamember sections - protected virtual void OnBeforeFlush() + protected virtual void OnBeforeFlush(TextWriter output) { } @@ -188,43 +188,20 @@ public string GetIdentifier(string aPrefix) private bool mFlushInitializationDone = false; - protected void BeforeFlush() + protected void BeforeFlush(TextWriter output) { if (mFlushInitializationDone) { return; } mFlushInitializationDone = true; - OnBeforeFlush(); + OnBeforeFlush(output); //MergeAllElements(); } - public virtual void FlushBinary(Stream aOutput, ulong aBaseAddress) - { - BeforeFlush(); - var xMax = AllAssemblerElementCount; - var xCurrentAddresss = aBaseAddress; - for (int i = 0; i < xMax; i++) - { - GetAssemblerElement(i).UpdateAddress(this, ref xCurrentAddresss); - } - aOutput.SetLength(aOutput.Length + (long) (xCurrentAddresss - aBaseAddress)); - for (int i = 0; i < xMax; i++) - { - var xItem = GetAssemblerElement(i); - if (!xItem.IsComplete(this)) - { - throw new Exception("Incomplete element encountered."); - } - //var xBuff = xItem.GetData(this); - //aOutput.Write(xBuff, 0, xBuff.Length); - xItem.WriteData(this, aOutput); - } - } - public virtual void FlushText(TextWriter aOutput) { - BeforeFlush(); + BeforeFlush(aOutput); BeforeFlushText(aOutput); // Write out data declarations aOutput.WriteLine(); diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/JumpToSegment.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/JumpToSegment.cs index aa5275dc..48882da9 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/JumpToSegment.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/JumpToSegment.cs @@ -1,66 +1,70 @@ -using System; - -namespace XSharp.Assembler.x86 -{ - [XSharp.Assembler.OpCode("jmp")] - public class JumpToSegment : Instruction { - public XSharp.Assembler.ElementReference DestinationRef { - get; - set; - } - - public ushort Segment { - get; - set; - } - - public override void WriteText( XSharp.Assembler.Assembler aAssembler, System.IO.TextWriter aOutput ) - { - if (DestinationRef != null) { - aOutput.Write("jmp "); - aOutput.Write(Segment); - aOutput.Write(":"); - aOutput.Write(DestinationRef.ToString()); - } else { - aOutput.Write("jmp "); - aOutput.Write(Segment); - aOutput.Write(":0x0"); - } - } - - public string DestinationLabel { - get { - if (DestinationRef != null) { - return DestinationRef.Name; - } - return String.Empty; - } - set { - DestinationRef = XSharp.Assembler.ElementReference.New(value); - } - } - - public override bool IsComplete( XSharp.Assembler.Assembler aAssembler ) - { - ulong xAddress; - return DestinationRef == null || DestinationRef.Resolve(aAssembler, out xAddress); - } - - public override void UpdateAddress(XSharp.Assembler.Assembler aAssembler, ref ulong aAddress) { - base.UpdateAddress(aAssembler, ref aAddress); - aAddress += 7; - } - - //public override byte[] GetData(Assembler aAssembler) { - public override void WriteData( XSharp.Assembler.Assembler aAssembler, System.IO.Stream aOutput ) - { - aOutput.WriteByte(0xEA); - ulong xAddress = 0; - if (DestinationRef != null && DestinationRef.Resolve(aAssembler, out xAddress)) { - xAddress = (ulong)(((long)xAddress) + DestinationRef.Offset); - } - aOutput.Write(BitConverter.GetBytes((uint)(xAddress)), 0, 4); - aOutput.Write(BitConverter.GetBytes(Segment), 0, 2); - } - } -} \ No newline at end of file +using System; + +namespace XSharp.Assembler.x86 +{ + [XSharp.Assembler.OpCode("jmp")] + public class JumpToSegment : Instruction { + public XSharp.Assembler.ElementReference DestinationRef { + get; + set; + } + + public ushort Segment { + get; + set; + } + + public JumpToSegment() + { + ; + } + public override void WriteText( XSharp.Assembler.Assembler aAssembler, System.IO.TextWriter aOutput ) + { + if (DestinationRef != null) { + aOutput.Write("jmp "); + aOutput.Write(Segment); + aOutput.Write(":"); + aOutput.Write(DestinationRef.ToString()); + } else { + aOutput.Write("jmp "); + aOutput.Write(Segment); + aOutput.Write(":0x0"); + } + } + + public string DestinationLabel { + get { + if (DestinationRef != null) { + return DestinationRef.Name; + } + return String.Empty; + } + set { + DestinationRef = XSharp.Assembler.ElementReference.New(value); + } + } + + public override bool IsComplete( XSharp.Assembler.Assembler aAssembler ) + { + ulong xAddress; + return DestinationRef == null || DestinationRef.Resolve(aAssembler, out xAddress); + } + + public override void UpdateAddress(XSharp.Assembler.Assembler aAssembler, ref ulong aAddress) { + base.UpdateAddress(aAssembler, ref aAddress); + aAddress += 7; + } + + //public override byte[] GetData(Assembler aAssembler) { + public override void WriteData( XSharp.Assembler.Assembler aAssembler, System.IO.Stream aOutput ) + { + aOutput.WriteByte(0xEA); + ulong xAddress = 0; + if (DestinationRef != null && DestinationRef.Resolve(aAssembler, out xAddress)) { + xAddress = (ulong)(((long)xAddress) + DestinationRef.Offset); + } + aOutput.Write(BitConverter.GetBytes((uint)(xAddress)), 0, 4); + aOutput.Write(BitConverter.GetBytes(Segment), 0, 2); + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/Push.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/Push.cs index 64e4f1f4..0affe574 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/Push.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/Push.cs @@ -1,10 +1,10 @@ -namespace XSharp.Assembler.x86 -{ - [XSharp.Assembler.OpCode("push")] - public class Push : InstructionWithDestinationAndSize { - - public Push():base("push") { - Size = 32; - } - } -} +namespace XSharp.Assembler.x86 +{ + [XSharp.Assembler.OpCode("push")] + public class Push : InstructionWithDestinationAndSize { + + public Push():base("push") { + Size = 64; + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/Registers.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/Registers.cs index b925ea90..fd62931e 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/Registers.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/Registers.cs @@ -324,7 +324,8 @@ public static string GetRegisterName(RegistersEnum aRegister) public static byte GetSize(RegistersEnum aRegister) { if (Is128Bit(aRegister)) { return 128; } - if (Is80Bit(aRegister)) { return 80; } + if (Is64Bit(aRegister)) { return 64; } + if (Is80Bit(aRegister)) { return 80; } if (Is32Bit(aRegister)) { return 32; } if (Is16Bit(aRegister)) { return 16; } if (Is8Bit(aRegister)) { return 8; } @@ -369,6 +370,12 @@ public static bool IsSegment(RegistersEnum aRegister) return aRegister == RegistersEnum.CS || aRegister == RegistersEnum.DS || aRegister == RegistersEnum.ES || aRegister == RegistersEnum.FS || aRegister == RegistersEnum.GS || aRegister == RegistersEnum.SS; } + public static bool Is64Bit(RegistersEnum aRegister) + { + return aRegister == RegistersEnum.RAX || aRegister == RegistersEnum.RBX || aRegister == RegistersEnum.RCX || aRegister == RegistersEnum.RDX || aRegister == RegistersEnum.RSP || aRegister == RegistersEnum.RBP || aRegister == RegistersEnum.RSI || aRegister == RegistersEnum.RDI || aRegister == RegistersEnum.CR0 || aRegister == RegistersEnum.CR1 || aRegister == RegistersEnum.CR2 || aRegister == RegistersEnum.CR3 || aRegister == RegistersEnum.CR4 + || aRegister == RegistersEnum.RIP || aRegister == RegistersEnum.R9 || aRegister == RegistersEnum.R10 || aRegister == RegistersEnum.R11 || aRegister == RegistersEnum.R12 || aRegister == RegistersEnum.R13 || aRegister == RegistersEnum.R14 || aRegister == RegistersEnum.R15; + } + public static bool Is32Bit(RegistersEnum aRegister) { return aRegister == RegistersEnum.EAX || aRegister == RegistersEnum.EBX || aRegister == RegistersEnum.ECX || aRegister == RegistersEnum.EDX || aRegister == RegistersEnum.ESP || aRegister == RegistersEnum.EBP || aRegister == RegistersEnum.ESI || aRegister == RegistersEnum.EDI || aRegister == RegistersEnum.CR0 || aRegister == RegistersEnum.CR1 || aRegister == RegistersEnum.CR2 || aRegister == RegistersEnum.CR3 || aRegister == RegistersEnum.CR4 diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/SSE2/ConvertSI2SD.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/SSE2/ConvertSI2SD.cs index 0fe104e0..4e6c83d9 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/SSE2/ConvertSI2SD.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/SSE2/ConvertSI2SD.cs @@ -1,7 +1,11 @@ -namespace XSharp.Assembler.x86.SSE -{ - [XSharp.Assembler.OpCode("cvtsi2sd")] - public class ConvertSI2SD : InstructionWithDestinationAndSource - { - } -} \ No newline at end of file +namespace XSharp.Assembler.x86.SSE +{ + [XSharp.Assembler.OpCode("cvtsi2sd")] + public class ConvertSI2SD : InstructionWithDestinationAndSource + { + public ConvertSI2SD() + { + SourceRequiresSize = true; + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/SignExtendAX.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/SignExtendAX.cs index 2b128020..75fc40d8 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/SignExtendAX.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/SignExtendAX.cs @@ -1,24 +1,27 @@ -using System; - -namespace XSharp.Assembler.x86 -{ - [XSharp.Assembler.OpCode("cdq")] - public class SignExtendAX : InstructionWithSize { - public override void WriteText( XSharp.Assembler.Assembler aAssembler, System.IO.TextWriter aOutput ) - { - switch (Size) { - case 32: - aOutput.Write("cdq"); - return; - case 16: - aOutput.Write("cwde"); - return; - case 8: - aOutput.Write("cbw"); - return; - default: - throw new NotSupportedException(); - } - } - } -} \ No newline at end of file +using System; + +namespace XSharp.Assembler.x86 +{ + [XSharp.Assembler.OpCode("cdq")] + public class SignExtendAX : InstructionWithSize { + public override void WriteText( XSharp.Assembler.Assembler aAssembler, System.IO.TextWriter aOutput ) + { + switch (Size) { + case 64: + aOutput.Write("cqo"); + return; + case 32: + aOutput.Write("cdq"); + return; + case 16: + aOutput.Write("cwde"); + return; + case 8: + aOutput.Write("cbw"); + return; + default: + throw new NotSupportedException(); + } + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Extensions.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Extensions.cs index 4c2b85c8..fae25108 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Extensions.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Extensions.cs @@ -1,112 +1,119 @@ -using System; - -namespace XSharp.Assembler.x86 -{ - public static class InfraExtensions - { - public static string GetDestinationAsString(this IInstructionWithDestination aThis) - { - string xDest = string.Empty; - if ((aThis.DestinationValue.HasValue || aThis.DestinationRef != null) && - aThis.DestinationIsIndirect && - aThis.DestinationReg != null && aThis.DestinationDisplacement > 0) - { - throw new Exception("[Scale*index+base] style addressing not supported at the moment"); - } - if (aThis.DestinationRef != null) - { - xDest = aThis.DestinationRef.ToString(); - } - else - { - if (aThis.DestinationReg != null) - { - xDest = Registers.GetRegisterName(aThis.DestinationReg.Value); - } - else - { - if (aThis.DestinationValue.HasValue) - xDest = "0x" + aThis.DestinationValue.GetValueOrDefault().ToString("X").ToUpperInvariant(); - } - } - if (aThis.DestinationDisplacement != null && aThis.DestinationDisplacement != 0) - { - if (aThis.DestinationDisplacement > 255) - { - xDest += " + 0x" + aThis.DestinationDisplacement.Value.ToString("X"); - } - else - { - xDest += (aThis.DestinationDisplacement < 0 ? " - " : " + ") + Math.Abs(aThis.DestinationDisplacement.Value); - } - } - if (aThis.DestinationIsIndirect) - { - return "[" + xDest + "]"; - } - return xDest; - } - - public static void DetermineSize(this IInstructionWithDestination aThis, IInstructionWithSize aThis2, byte aSize) - { - if (aSize == 0) - { - if (aThis.DestinationReg != null && !aThis.DestinationIsIndirect) - { - aThis2.Size = Registers.GetSize(aThis.DestinationReg.Value); - return; - } - if (aThis.DestinationRef != null && !aThis.DestinationIsIndirect) - { - aThis2.Size = 32; - return; - } - } - } - - public static string GetMnemonic(this ConditionalTestEnum aThis) - { - switch (aThis) - { - case ConditionalTestEnum.Overflow: - return "o"; - case ConditionalTestEnum.NoOverflow: - return "no"; - case ConditionalTestEnum.Below: - return "b"; - case ConditionalTestEnum.NotBelow: - return "nb"; - case ConditionalTestEnum.Equal: - return "e"; - case ConditionalTestEnum.NotEqual: - return "ne"; - case ConditionalTestEnum.BelowOrEqual: - return "be"; - case ConditionalTestEnum.NotBelowOrEqual: - return "nbe"; - case ConditionalTestEnum.Sign: - return "s"; - case ConditionalTestEnum.NotSign: - return "ns"; - case ConditionalTestEnum.Parity: - return "p"; - case ConditionalTestEnum.NotParity: - return "np"; - case ConditionalTestEnum.LessThan: - return "l"; - case ConditionalTestEnum.NotLessThan: - return "nl"; - case ConditionalTestEnum.LessThanOrEqualTo: - return "le"; - case ConditionalTestEnum.NotLessThanOrEqualTo: - return "nle"; - case ConditionalTestEnum.CXRegisterEqualOrZeroTo: - return "cxe"; - case ConditionalTestEnum.ECXRegisterEqualOrZeroTo: - return "ecxe"; - default: - throw new NotImplementedException(); - } - } - } -} +using System; + +namespace XSharp.Assembler.x86 +{ + public static class InfraExtensions + { + public static string GetDestinationAsString(this IInstructionWithDestination aThis) + { + string xDest = string.Empty; + if ((aThis.DestinationValue.HasValue || aThis.DestinationRef != null) && + aThis.DestinationIsIndirect && + aThis.DestinationReg != null && aThis.DestinationDisplacement > 0) + { + throw new Exception("[Scale*index+base] style addressing not supported at the moment"); + } + if (aThis.DestinationRef != null) + { + if (aThis.DestinationIsIndirect) + { + xDest = "rel " + aThis.DestinationRef.ToString(); + } + else + { + xDest = aThis.DestinationRef.ToString(); + } + } + else + { + if (aThis.DestinationReg != null) + { + xDest = Registers.GetRegisterName(aThis.DestinationReg.Value); + } + else + { + if (aThis.DestinationValue.HasValue) + xDest = "0x" + aThis.DestinationValue.GetValueOrDefault().ToString("X").ToUpperInvariant(); + } + } + if (aThis.DestinationDisplacement != null && aThis.DestinationDisplacement != 0) + { + if (aThis.DestinationDisplacement > 255) + { + xDest += " + 0x" + aThis.DestinationDisplacement.Value.ToString("X"); + } + else + { + xDest += (aThis.DestinationDisplacement < 0 ? " - " : " + ") + Math.Abs(aThis.DestinationDisplacement.Value); + } + } + if (aThis.DestinationIsIndirect) + { + return "[" + xDest + "]"; + } + return xDest; + } + + public static void DetermineSize(this IInstructionWithDestination aThis, IInstructionWithSize aThis2, byte aSize) + { + if (aSize == 0) + { + if (aThis.DestinationReg != null && !aThis.DestinationIsIndirect) + { + aThis2.Size = Registers.GetSize(aThis.DestinationReg.Value); + return; + } + if (aThis.DestinationRef != null && !aThis.DestinationIsIndirect) + { + aThis2.Size = 64; + return; + } + } + } + + public static string GetMnemonic(this ConditionalTestEnum aThis) + { + switch (aThis) + { + case ConditionalTestEnum.Overflow: + return "o"; + case ConditionalTestEnum.NoOverflow: + return "no"; + case ConditionalTestEnum.Below: + return "b"; + case ConditionalTestEnum.NotBelow: + return "nb"; + case ConditionalTestEnum.Equal: + return "e"; + case ConditionalTestEnum.NotEqual: + return "ne"; + case ConditionalTestEnum.BelowOrEqual: + return "be"; + case ConditionalTestEnum.NotBelowOrEqual: + return "nbe"; + case ConditionalTestEnum.Sign: + return "s"; + case ConditionalTestEnum.NotSign: + return "ns"; + case ConditionalTestEnum.Parity: + return "p"; + case ConditionalTestEnum.NotParity: + return "np"; + case ConditionalTestEnum.LessThan: + return "l"; + case ConditionalTestEnum.NotLessThan: + return "nl"; + case ConditionalTestEnum.LessThanOrEqualTo: + return "le"; + case ConditionalTestEnum.NotLessThanOrEqualTo: + return "nle"; + case ConditionalTestEnum.CXRegisterEqualOrZeroTo: + return "cxe"; + case ConditionalTestEnum.ECXRegisterEqualOrZeroTo: + return "ecxe"; + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Instruction.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Instruction.cs index f7ac1091..020a0360 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Instruction.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/Instruction.cs @@ -1,54 +1,54 @@ -using System; - -namespace XSharp.Assembler.x86 -{ - // todo: cache the EncodingOption and InstructionData instances.. - public abstract class Instruction : XSharp.Assembler.Instruction { - - [Flags] - public enum InstructionSizes { - None, - Byte = 8, - Word = 16, - DWord = 32, - QWord = 64, - All = Byte | Word | DWord - } - - public enum InstructionSize { - None = 0, - Byte = 8, - Word = 16, - DWord = 32, - QWord = 64 - } - - [Flags] - public enum OperandMemoryKinds { - Default = Address | IndirectReg | IndirectRegOffset, - Address = 1, - IndirectReg = 2, - IndirectRegOffset = 4 - } - - protected Instruction(string mnemonic = null) { } - protected Instruction(bool aAddToAssembler, string mnemonic = null):base(aAddToAssembler, mnemonic) { } - - protected static string SizeToString(byte aSize) { - switch (aSize) { - case 8: - return "byte"; - case 16: - return "word"; - case 32: - return "dword"; - case 64: - return "qword"; - case 80: - return string.Empty; - default: - return "dword"; - } - } - } -} +using System; + +namespace XSharp.Assembler.x86 +{ + // todo: cache the EncodingOption and InstructionData instances.. + public abstract class Instruction : XSharp.Assembler.Instruction { + + [Flags] + public enum InstructionSizes { + None, + Byte = 8, + Word = 16, + DWord = 32, + QWord = 64, + All = Byte | Word | DWord + } + + public enum InstructionSize { + None = 0, + Byte = 8, + Word = 16, + DWord = 32, + QWord = 64 + } + + [Flags] + public enum OperandMemoryKinds { + Default = Address | IndirectReg | IndirectRegOffset, + Address = 1, + IndirectReg = 2, + IndirectRegOffset = 4 + } + + protected Instruction(string mnemonic = null) { } + protected Instruction(bool aAddToAssembler, string mnemonic = null):base(aAddToAssembler, mnemonic) { } + + protected static string SizeToString(byte aSize) { + switch (aSize) { + case 8: + return "byte"; + case 16: + return "word"; + case 32: + return "dword"; + case 64: + return "qword"; + case 80: + return string.Empty; + default: + return "dword"; + } + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSize.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSize.cs index 8c63f74c..f9bb9328 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSize.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSize.cs @@ -1,34 +1,35 @@ -namespace XSharp.Assembler.x86 -{ - public abstract class InstructionWithDestinationAndSize : InstructionWithDestination, IInstructionWithSize { - public InstructionWithDestinationAndSize(string mnemonic = null) : base(mnemonic) - { - } - - private byte mSize; - public byte Size { - get { - this.DetermineSize(this, mSize); - return mSize; - } - set { - if (value > 0) { - SizeToString(value); - } - mSize = value; - } - } - - public override void WriteText( XSharp.Assembler.Assembler aAssembler, System.IO.TextWriter aOutput ) -{ - aOutput.Write(mMnemonic); - aOutput.Write(" "); - aOutput.Write(SizeToString(Size)); - if (!DestinationEmpty) - { - aOutput.Write(" "); - aOutput.Write(this.GetDestinationAsString()); - } - } - } -} +namespace XSharp.Assembler.x86 +{ + public abstract class InstructionWithDestinationAndSize : InstructionWithDestination, IInstructionWithSize { + public InstructionWithDestinationAndSize(string mnemonic = null) : base(mnemonic) + { + } + + private byte mSize; + public byte Size { + get { + this.DetermineSize(this, mSize); + return mSize; + } + set { + if (value > 0) { + SizeToString(value); + } + mSize = value; + } + } + + public override void WriteText( XSharp.Assembler.Assembler aAssembler, System.IO.TextWriter aOutput ) +{ + aOutput.Write(mMnemonic); + aOutput.Write(" "); + if (DestinationIsIndirect) + aOutput.Write(SizeToString(Size)); + if (!DestinationEmpty) + { + aOutput.Write(" "); + aOutput.Write(this.GetDestinationAsString()); + } + } + } +} diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSource.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSource.cs index 09151452..fdb8dcf7 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSource.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSource.cs @@ -36,6 +36,8 @@ public bool SourceIsIndirect { set; } + public bool SourceRequiresSize { get; set; } + public int? SourceDisplacement { get; set; @@ -53,7 +55,8 @@ protected string GetSourceAsString() { // throw new Exception("[Scale*index+base] style addressing not supported at the moment"); //} if (SourceRef != null) { - xDest = SourceRef.ToString(); + SourceIsIndirect = true; + xDest = " rel "+SourceRef.ToString(); } else { if (SourceReg != null) { xDest = Registers.GetRegisterName(SourceReg.Value); @@ -65,9 +68,16 @@ protected string GetSourceAsString() { if (SourceDisplacement != null && SourceDisplacement != 0) { xDest += (SourceDisplacement < 0 ? " - " : " + ") + Math.Abs(SourceDisplacement.Value); } - if (SourceIsIndirect) { - return "[" + xDest + "]"; - } else { + if (SourceIsIndirect && SourceRequiresSize) + { + return SizeToString(64) + " [" + xDest + "]"; + } + else if (SourceIsIndirect) + { + return " [" + xDest + "]"; ; + } + else + { return xDest; } } diff --git a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSourceAndSize.cs b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSourceAndSize.cs index 0117569a..e4a62f8b 100644 --- a/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSourceAndSize.cs +++ b/source/XSharp/XSharp/Assembler/Gen1/x86/_Infra/InstructionWithDestinationAndSourceAndSize.cs @@ -56,7 +56,7 @@ protected virtual void DetermineSize() } if ((SourceRef != null && !SourceIsIndirect) || (DestinationRef != null && !DestinationIsIndirect)) { - Size = 32; + Size = 64; return; } } @@ -67,8 +67,7 @@ public override void WriteText(Assembler aAssembler, System.IO.TextWriter aOutpu { if (Size == 0) { - Size = 32; - //Console.WriteLine("ERRROR no size set for Instruction - set to 4 InstructionWithDestinationAndSourceAndSize") ; + Size = 64; } aOutput.Write(mMnemonic); diff --git a/source/XSharp/XSharp/Assembler/x86/Register.cs b/source/XSharp/XSharp/Assembler/x86/Register.cs index ef6eea4c..5850505e 100644 --- a/source/XSharp/XSharp/Assembler/x86/Register.cs +++ b/source/XSharp/XSharp/Assembler/x86/Register.cs @@ -1,120 +1,126 @@ -using System; -using System.Linq; - -namespace XSharp.x86 -{ - public class Register - { - public static class Names - { - public static readonly string[] Reg08 = "AH,AL,BH,BL,CH,CL,DH,DL".Split(','); - public static readonly string[] Reg16 = "AX,BX,CX,DX".Split(','); - public static readonly string[] Reg32 = "EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI".Split(','); - } - - // These statics are not used much now but will be used even with NASM - // and will become far important wtih binary assembler. - public static readonly Register EAX = new Register("EAX"); - - public static readonly Register EBX = new Register("EBX"); - public static readonly Register ECX = new Register("ECX"); - public static readonly Register EDX = new Register("EDX"); - public static readonly Register ESP = new Register("ESP"); - public static readonly Register EBP = new Register("EBP"); - public static readonly Register ESI = new Register("ESI"); - - public static readonly Register EDI = new Register("EDI"); - - // - public static readonly Register AX = new Register("AX"); - - public static readonly Register BX = new Register("BX"); - public static readonly Register CX = new Register("CX"); - - public static readonly Register DX = new Register("DX"); - - // - public static readonly Register AH = new Register("AH"); - - public static readonly Register AL = new Register("AL"); - public static readonly Register BH = new Register("BH"); - public static readonly Register BL = new Register("BL"); - public static readonly Register CH = new Register("CH"); - public static readonly Register CL = new Register("CL"); - public static readonly Register DH = new Register("DH"); - public static readonly Register DL = new Register("DL"); - - public bool IsGenPurpose { get; } - public string Name { get; } - public int Size { get; } - - public Register(string aName) - { - Name = aName.ToUpper(); - - //TODO Add special registers and leave IsGenPurpose = false - if (Names.Reg32.Contains(Name)) - { - IsGenPurpose = true; - Size = 32; - } - else if (Names.Reg16.Contains(Name)) - { - IsGenPurpose = true; - Size = 16; - } - else if (Names.Reg08.Contains(Name)) - { - IsGenPurpose = true; - Size = 8; - } - else - { - throw new Exception(aName + " is not a recognized register name."); - } - } - - public bool CheckIs(string aValidRegs, bool throwException = false) - { - if (!(aValidRegs + ",").Contains(Name + ",")) - { - if (throwException) - { - throw new Exception("Invalid register: {Name}.\r\nMust be one of: {aValidRegs}"); - } - - return false; - } - return true; - } - - public void CheckIsDX() - { - CheckIs("DX", true); - } - - public void CheckIsAccumulator() - { - CheckIs("EAX,AX,AL", true); - } - - public bool IsReg08 => Names.Reg08.Contains(Name); - - public bool IsReg16 => Names.Reg16.Contains(Name); - - public bool IsReg32 => Names.Reg32.Contains(Name); - - public string RegSize => IsReg08 - ? "byte" - : IsReg16 - ? "word" - : IsReg32 - ? "dword" - : throw new NotSupportedException("Unknown register size"); - - public override string ToString() - { - return Name; - } - } -} +using System; +using System.Linq; + +namespace XSharp.x86 +{ + public class Register + { + public static class Names + { + public static readonly string[] Reg08 = "AH,AL,BH,BL,CH,CL,DH,DL".Split(','); + public static readonly string[] Reg16 = "AX,BX,CX,DX".Split(','); + public static readonly string[] Reg32 = "EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI".Split(','); + public static readonly string[] Reg64 = "RAX,RBX,RCX,RDX,RSP,RBP,RSI,RDI".Split(','); + } + + // These statics are not used much now but will be used even with NASM + // and will become far important wtih binary assembler. + public static readonly Register EAX = new Register("EAX"); + + public static readonly Register EBX = new Register("EBX"); + public static readonly Register ECX = new Register("ECX"); + public static readonly Register EDX = new Register("EDX"); + public static readonly Register ESP = new Register("ESP"); + public static readonly Register EBP = new Register("EBP"); + public static readonly Register ESI = new Register("ESI"); + + public static readonly Register EDI = new Register("EDI"); + + // + public static readonly Register AX = new Register("AX"); + + public static readonly Register BX = new Register("BX"); + public static readonly Register CX = new Register("CX"); + + public static readonly Register DX = new Register("DX"); + + // + public static readonly Register AH = new Register("AH"); + + public static readonly Register AL = new Register("AL"); + public static readonly Register BH = new Register("BH"); + public static readonly Register BL = new Register("BL"); + public static readonly Register CH = new Register("CH"); + public static readonly Register CL = new Register("CL"); + public static readonly Register DH = new Register("DH"); + public static readonly Register DL = new Register("DL"); + + public bool IsGenPurpose { get; } + public string Name { get; } + public int Size { get; } + + public Register(string aName) + { + Name = aName.ToUpper(); + + //TODO Add special registers and leave IsGenPurpose = false + if (Names.Reg64.Contains(Name)) + { + IsGenPurpose = true; + Size = 64; + } + else if (Names.Reg32.Contains(Name)) + { + IsGenPurpose = true; + Size = 32; + } + else if (Names.Reg16.Contains(Name)) + { + IsGenPurpose = true; + Size = 16; + } + else if (Names.Reg08.Contains(Name)) + { + IsGenPurpose = true; + Size = 8; + } + else + { + throw new Exception(aName + " is not a recognized register name."); + } + } + + public bool CheckIs(string aValidRegs, bool throwException = false) + { + if (!(aValidRegs + ",").Contains(Name + ",")) + { + if (throwException) + { + throw new Exception("Invalid register: {Name}.\r\nMust be one of: {aValidRegs}"); + } + + return false; + } + return true; + } + + public void CheckIsDX() + { + CheckIs("DX", true); + } + + public void CheckIsAccumulator() + { + CheckIs("EAX,AX,AL", true); + } + + public bool IsReg08 => Names.Reg08.Contains(Name); + + public bool IsReg16 => Names.Reg16.Contains(Name); + + public bool IsReg32 => Names.Reg32.Contains(Name); + + public string RegSize => IsReg08 + ? "byte" + : IsReg16 + ? "word" + : IsReg32 + ? "dword" + : throw new NotSupportedException("Unknown register size"); + + public override string ToString() + { + return Name; + } + } +} diff --git a/source/XSharp/XSharp/Gen1/Parser.cs b/source/XSharp/XSharp/Gen1/Parser.cs index 230fd0e4..ac939e68 100644 --- a/source/XSharp/XSharp/Gen1/Parser.cs +++ b/source/XSharp/XSharp/Gen1/Parser.cs @@ -1,391 +1,391 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace XSharp { - /// - /// Parser recognizes the following tokens: - /// - _123 -> Number - /// - _REG -> All registers - /// - _REGADDR -> All 32-bit registers - /// - 1 -> Number as well - /// - _ABC -> Random label, used indirectly (ie, used as a field) - /// - #_ABC -> Random label, used for the value (ie, pointer to the field) - /// - public class Parser { - /// Index in of the first yet unconsumed character. - protected int mStart = 0; - - /// Initial text provided as a constructor parameter. - protected string mData; - - /// true if whitespace tokens should be kept and propagated to the next parsing - /// stage. - protected bool mIncludeWhiteSpace; - - /// true while every token encountered until so far by this parser are whitespace - /// tokens. - protected bool mAllWhitespace; - - /// true if the parser supports patterns recognition. - protected bool mAllowPatterns; - - /// Tokens retrieved so far by the parser. - protected TokenList mTokens; - - /// Get a list of tokens that has been built at class instanciation. - public TokenList Tokens { - get { return mTokens; } - } - - protected static readonly char[] mComma = new char[] { ',' }; - protected static readonly char[] mSpace = new char[] { ' ' }; - - public static string[] mKeywords = ( - "As,All" - + ",BYTE" - + ",CALL,CONST" - + ",DWORD" - + ",exit" - + ",function" - + ",goto" - + ",IF,INTERRUPT,iret" - + ",namespace" - + ",PORT" - + ",return,ret,REPEAT" - + ",times" - + ",var" - + ",word,while" - ).ToUpper().Split(mComma); - - public static readonly Dictionary Registers; - public static readonly Dictionary RegistersAddr; - public static readonly Dictionary Registers8; - public static readonly Dictionary Registers16; - public static readonly Dictionary Registers32; - public static readonly Dictionary RegistersIdx; - public static readonly string[] RegisterPatterns = "_REG,_REG8,_REG16,_REG32,_REGIDX,_REGADDR".Split(mComma); - - public static readonly string[] Delimiters = ",".Split(mSpace); - - // _.$ are AlphaNum. See comments in Parser - // # is comment and literal, but could be reused when not first char - // string[] is used instead of string because operators can be multi char, != >= etc - public static readonly string[] Operators = - "( ) () ! = != >= <= [ [- ] + - * : { } < > ?= ?& @ ~> <~ >> << ++ -- # +# & | ^".Split(mSpace); - - static Parser() { - Registers8 = new Dictionary() - { - {"AL", XSRegisters.AL}, - {"AH", XSRegisters.AH}, - {"BL", XSRegisters.BL}, - {"BH", XSRegisters.BH}, - {"CL", XSRegisters.CL}, - {"CH", XSRegisters.CH}, - {"DL", XSRegisters.DL}, - {"DH", XSRegisters.DH}, - }; - - Registers16 = new Dictionary() - { - {"AX", XSRegisters.AX}, - {"BX", XSRegisters.BX}, - {"CX", XSRegisters.CX}, - {"DX", XSRegisters.DX}, - }; - - Registers32 = new Dictionary() - { - {"EAX", XSRegisters.EAX}, - {"EBX", XSRegisters.EBX}, - {"ECX", XSRegisters.ECX}, - {"EDX", XSRegisters.EDX}, - }; - - RegistersIdx = new Dictionary() - { - {"ESI", XSRegisters.ESI}, - {"EDI", XSRegisters.EDI}, - {"ESP", XSRegisters.ESP}, - {"EBP", XSRegisters.EBP}, - }; - - var xRegisters = new Dictionary(); - xRegisters.AddRange(Registers8); - xRegisters.AddRange(Registers16); - xRegisters.AddRange(Registers32); - xRegisters.AddRange(RegistersIdx); - Registers = xRegisters; - - var xRegistersAddr = new Dictionary(); - xRegistersAddr.AddRange(Registers32); - xRegistersAddr.AddRange(RegistersIdx); - RegistersAddr = xRegistersAddr; - } - - /// Parse next token from currently parsed line, starting at given position and - /// add the retrieved token at end of given token list. - /// The token list where to add the newly recognized token. - /// Line number for diagnostics and debugging purpose. - /// The index in current source code line of the first not yet consumed - /// character. On return this parameter will be updated to account for characters that would - /// have been consumed. - protected void NextToken(TokenList aList, ref int rPos) { - #region Pattern Notes - - // All patterns start with _, this makes them reserved. User can use too, but at own risk of conflict. - // - // Wildcards - // -_REG or ??X - // -_REG8 or ?H,?L - // -_REG16 or ?X - // -_REG32 or E?X - // - ? based ones are ugly and less clear - // -_Keyword - // -_ABC - // - // - // Multiple Options (All caps only) - Registers only - // Used to suport EAX,EBX - ie lists. But found out wasnt really needed. May add again later. - // - // -AX/AL - Conflict if we ever use / - // -AX|AL - Conflict if we ever use | - // -AX,AL - , is unlikely to ever be used as an operator and is logical as a separator. Method calls might use, but likely better to use a space - // since we will only allow simple arguments, not compound. - // -_REG:AX|AL - End terminator issue - // -_REG[AX|AL] - Conflict with existing indirect access. Is indirect access always numeric? I think x86 has some register based ones too. - // - // - // Specific: Register, Keyword, AlphaNum - // -EAX - - #endregion - - string xString = null; - char xChar1 = mData[mStart]; - var xToken = new Token(); - - // Directives and literal assembler code. - if (mAllWhitespace) { - if (xChar1 == '!' || xChar1 == '/') { - rPos = mData.Length; // This will account for the dummy whitespace at the end. - xString = mData.Substring(mStart + 1, rPos - mStart - 1).Trim(); - // So ToString/Format wont generate error - xString = xString.Replace("{", "{{"); - xString = xString.Replace("}", "}}"); - - // Fix issue #15662 with string length check. - // Fix issue #15663 with comparing from mData and not from xString anymore. - if (xChar1 == '!') { - // Literal assembler code. - xToken.Type = TokenType.Line_LiteralAsm; - } else if (xString.Length > 0) { - char xChar2 = xString[0]; - xString = xString.Substring(1); - if (xChar2 == '/') { - xToken.Type = TokenType.Line_Comment; - } else if (xChar2 == '!') { - xToken.Type = TokenType.Line_Directive; - } - } - } - } - - if (xToken.Type == TokenType.Unknown) { - xString = mData.Substring(mStart, rPos - mStart); - - if (string.IsNullOrWhiteSpace(xString) && xString.Length > 0) { - xToken.Type = TokenType.WhiteSpace; - - } else if (xChar1 == '\'') { - xToken.Type = TokenType.ValueString; - xString = xString.Substring(1, xString.Length - 2); - - } else if (char.IsDigit(xChar1)) { - xToken.Type = TokenType.ValueInt; - if (xString.StartsWith("0x")) { - xToken.SetIntValue(Convert.ToUInt32(xString, 16)); - } else { - xToken.SetIntValue(uint.Parse(xString)); - } - } else if (xChar1 == '$') { - xToken.Type = TokenType.ValueInt; - // Remove surrounding ' - xString = "0x" + xString.Substring(1); - if (xString.StartsWith("0x")) { - xToken.SetIntValue(Convert.ToUInt32(xString, 16)); - } else { - xToken.SetIntValue(uint.Parse(xString)); - } - } else if (IsAlphaNum(xChar1)) { - // This must be after check for ValueInt - string xUpper = xString.ToUpper(); - - // Special parsing when in pattern mode. We recognize some special strings - // which would otherwise be considered as simple AlphaNum token otherwise. - if (mAllowPatterns) { - if (RegisterPatterns.Contains(xUpper)) { - xToken.Type = TokenType.Register; - } else if (xUpper == "_KEYWORD") { - xToken.Type = TokenType.Keyword; - xString = null; - } else if (xUpper == "_ABC") { - xToken.Type = TokenType.AlphaNum; - xString = null; - } else if (xUpper == "_PCALL") { - xString = null; - xToken.Type = TokenType.Call; - } - } - - if (xToken.Type == TokenType.Unknown) { - XSRegisters.Register xRegister; - if (Registers.TryGetValue(xUpper, out xRegister)) { - xToken.Type = TokenType.Register; - xToken.SetRegister(xRegister); - } else if (mKeywords.Contains(xUpper)) { - xToken.Type = TokenType.Keyword; - } else if (xString.Contains("(") && xString.Contains(")") && IsAlphaNum(xChar1)) { - xToken.Type = TokenType.Call; - } else { - xToken.Type = TokenType.AlphaNum; - } - } - - } else if (Delimiters.Contains(xString)) { - xToken.Type = TokenType.Delimiter; - } else if (Operators.Contains(xString)) { - xToken.Type = TokenType.Operator; - } - } - - xToken.RawValue = xString; - xToken.SrcPosStart = mStart; - xToken.SrcPosEnd = xToken.Type == TokenType.Call ? rPos : rPos - 1; - if (mAllWhitespace && (xToken.Type != TokenType.WhiteSpace)) { - mAllWhitespace = false; - } - mStart = xToken.Type == TokenType.Call ? rPos + 1 : rPos; - - if (mIncludeWhiteSpace || (xToken.Type != TokenType.WhiteSpace)) { - aList.Add(xToken); - } - } - - protected enum CharType { - WhiteSpace, - Identifier, - Symbol, - String - }; - - protected bool IsAlphaNum(char aChar) { - return char.IsLetterOrDigit(aChar) || aChar == '_' || aChar == '.' || aChar == '$'; - } - - /// Consume text that has been provided to the class constructor, splitting it into - /// a list of tokens. - /// Line number for diagnostics and debugging. - /// The resulting tokens list. - protected TokenList Parse() { - // Save in comment, might be useful in future. Already had to dig it out of TFS once - //var xRegex = new System.Text.RegularExpressions.Regex(@"(\W)"); - - var xResult = new TokenList(); - CharType xLastCharType = CharType.WhiteSpace; - CharType xCharType = CharType.WhiteSpace; - int i = 0; - for (i = 0; i < mData.Length; i++) { - char xChar = mData[i]; - // Extract string literal (surrounded with single quote characters). - if (xChar == '\'') { - // Take data before the ' as a token. - NextToken(xResult, ref i); - // Now scan to the next ' taking into account escaped single quotes. - bool escapedCharacter = false; - for (i = i + 1; i < mData.Length; i++) { - bool done = false; - switch (mData[i]) { - case '\'': - if (!escapedCharacter) { - done = true; - } - break; - case '\\': - escapedCharacter = !escapedCharacter; - break; - default: - escapedCharacter = false; - break; - } - if (done) { - break; - } - } - if (i == mData.Length) { - throw new Exception("Unterminated string."); - } - i++; - xCharType = CharType.String; - } else if (xChar == '(') { - for (i += 1; i < mData.Length; i++) { - if (mData[i] == ')' && mData.LastIndexOf(")") <= i) { - i++; - NextToken(xResult, ref i); - break; - } - } - } else if (char.IsWhiteSpace(xChar)) { - xCharType = CharType.WhiteSpace; - } else if (IsAlphaNum(xChar)) { - // _ and . were never likely to stand on their own. ie ESP _ 2 and ESP . 2 are never likely to be used. - // Having them on their own required a lot of code - // to treat them as a single unit where we did use them. So we treat them as AlphaNum. - xCharType = CharType.Identifier; - } else { - xCharType = CharType.Symbol; - } - - // i > 0 - Never do NewToken on first char. i = 0 is just a pass to get char and set lastchar. - // But its faster as the second short circuit rather than a separate if. - if ((xCharType != xLastCharType) && (0 < i)) { - NextToken(xResult, ref i); - } - - xLastCharType = xCharType; - } - - // Last token - if (mStart < mData.Length) { - NextToken(xResult, ref i); - } - - return xResult; - } - - /// Create a new Parser instance and immediately consume the given - /// string. On return the property is available for enumeration. - /// The text to be parsed. WARNING : This is expected to be a single full line - /// of text. The parser can be create with a special "pattern recognition" mode. - /// - /// True if is a pattern and thus the parsing - /// should be performed specifically. - /// At least one unrecognized token has been parsed. - public Parser(string aData, bool aIncludeWhiteSpace, bool aAllowPatterns) { - mData = aData; - mIncludeWhiteSpace = aIncludeWhiteSpace; - mAllowPatterns = aAllowPatterns; - mAllWhitespace = true; - - mTokens = Parse(); - if (mTokens.Count(q => q.Type == TokenType.Unknown) > 0) { - foreach (var xToken in mTokens) { - if (xToken.Type == TokenType.Unknown) { - throw new Exception(string.Format("Unknown token '{0}' found at {1}.", xToken.RawValue ?? "NULL", xToken.SrcPosStart)); - } - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; + +namespace XSharp { + /// + /// Parser recognizes the following tokens: + /// - _123 -> Number + /// - _REG -> All registers + /// - _REGADDR -> All 32-bit registers + /// - 1 -> Number as well + /// - _ABC -> Random label, used indirectly (ie, used as a field) + /// - #_ABC -> Random label, used for the value (ie, pointer to the field) + /// + public class Parser { + /// Index in of the first yet unconsumed character. + protected int mStart = 0; + + /// Initial text provided as a constructor parameter. + protected string mData; + + /// true if whitespace tokens should be kept and propagated to the next parsing + /// stage. + protected bool mIncludeWhiteSpace; + + /// true while every token encountered until so far by this parser are whitespace + /// tokens. + protected bool mAllWhitespace; + + /// true if the parser supports patterns recognition. + protected bool mAllowPatterns; + + /// Tokens retrieved so far by the parser. + protected TokenList mTokens; + + /// Get a list of tokens that has been built at class instanciation. + public TokenList Tokens { + get { return mTokens; } + } + + protected static readonly char[] mComma = new char[] { ',' }; + protected static readonly char[] mSpace = new char[] { ' ' }; + + public static string[] mKeywords = ( + "As,All" + + ",BYTE" + + ",CALL,CONST" + + ",DWORD" + + ",exit" + + ",function" + + ",goto" + + ",IF,INTERRUPT,iret" + + ",namespace" + + ",PORT" + + ",return,ret,REPEAT" + + ",times" + + ",var" + + ",word,while" + ).ToUpper().Split(mComma); + + public static readonly Dictionary Registers; + public static readonly Dictionary RegistersAddr; + public static readonly Dictionary Registers8; + public static readonly Dictionary Registers16; + public static readonly Dictionary Registers32; + public static readonly Dictionary RegistersIdx; + public static readonly string[] RegisterPatterns = "_REG,_REG8,_REG16,_REG32,_REGIDX,_REGADDR".Split(mComma); + + public static readonly string[] Delimiters = ",".Split(mSpace); + + // _.$ are AlphaNum. See comments in Parser + // # is comment and literal, but could be reused when not first char + // string[] is used instead of string because operators can be multi char, != >= etc + public static readonly string[] Operators = + "( ) () ! = != >= <= [ [- ] + - * : { } < > ?= ?& @ ~> <~ >> << ++ -- # +# & | ^".Split(mSpace); + + static Parser() { + Registers8 = new Dictionary() + { + {"AL", XSRegisters.AL}, + {"AH", XSRegisters.AH}, + {"BL", XSRegisters.BL}, + {"BH", XSRegisters.BH}, + {"CL", XSRegisters.CL}, + {"CH", XSRegisters.CH}, + {"DL", XSRegisters.DL}, + {"DH", XSRegisters.DH}, + }; + + Registers16 = new Dictionary() + { + {"AX", XSRegisters.AX}, + {"BX", XSRegisters.BX}, + {"CX", XSRegisters.CX}, + {"DX", XSRegisters.DX}, + }; + + Registers32 = new Dictionary() + { + {"EAX", XSRegisters.RAX}, + {"EBX", XSRegisters.RBX}, + {"ECX", XSRegisters.RCX}, + {"EDX", XSRegisters.RDX}, + }; + + RegistersIdx = new Dictionary() + { + {"ESI", XSRegisters.RSI}, + {"EDI", XSRegisters.RDI}, + {"ESP", XSRegisters.RSP}, + {"EBP", XSRegisters.RBP}, + }; + + var xRegisters = new Dictionary(); + xRegisters.AddRange(Registers8); + xRegisters.AddRange(Registers16); + xRegisters.AddRange(Registers32); + xRegisters.AddRange(RegistersIdx); + Registers = xRegisters; + + var xRegistersAddr = new Dictionary(); + xRegistersAddr.AddRange(Registers32); + xRegistersAddr.AddRange(RegistersIdx); + RegistersAddr = xRegistersAddr; + } + + /// Parse next token from currently parsed line, starting at given position and + /// add the retrieved token at end of given token list. + /// The token list where to add the newly recognized token. + /// Line number for diagnostics and debugging purpose. + /// The index in current source code line of the first not yet consumed + /// character. On return this parameter will be updated to account for characters that would + /// have been consumed. + protected void NextToken(TokenList aList, ref int rPos) { + #region Pattern Notes + + // All patterns start with _, this makes them reserved. User can use too, but at own risk of conflict. + // + // Wildcards + // -_REG or ??X + // -_REG8 or ?H,?L + // -_REG16 or ?X + // -_REG32 or E?X + // - ? based ones are ugly and less clear + // -_Keyword + // -_ABC + // + // + // Multiple Options (All caps only) - Registers only + // Used to suport EAX,EBX - ie lists. But found out wasnt really needed. May add again later. + // + // -AX/AL - Conflict if we ever use / + // -AX|AL - Conflict if we ever use | + // -AX,AL - , is unlikely to ever be used as an operator and is logical as a separator. Method calls might use, but likely better to use a space + // since we will only allow simple arguments, not compound. + // -_REG:AX|AL - End terminator issue + // -_REG[AX|AL] - Conflict with existing indirect access. Is indirect access always numeric? I think x86 has some register based ones too. + // + // + // Specific: Register, Keyword, AlphaNum + // -EAX + + #endregion + + string xString = null; + char xChar1 = mData[mStart]; + var xToken = new Token(); + + // Directives and literal assembler code. + if (mAllWhitespace) { + if (xChar1 == '!' || xChar1 == '/') { + rPos = mData.Length; // This will account for the dummy whitespace at the end. + xString = mData.Substring(mStart + 1, rPos - mStart - 1).Trim(); + // So ToString/Format wont generate error + xString = xString.Replace("{", "{{"); + xString = xString.Replace("}", "}}"); + + // Fix issue #15662 with string length check. + // Fix issue #15663 with comparing from mData and not from xString anymore. + if (xChar1 == '!') { + // Literal assembler code. + xToken.Type = TokenType.Line_LiteralAsm; + } else if (xString.Length > 0) { + char xChar2 = xString[0]; + xString = xString.Substring(1); + if (xChar2 == '/') { + xToken.Type = TokenType.Line_Comment; + } else if (xChar2 == '!') { + xToken.Type = TokenType.Line_Directive; + } + } + } + } + + if (xToken.Type == TokenType.Unknown) { + xString = mData.Substring(mStart, rPos - mStart); + + if (string.IsNullOrWhiteSpace(xString) && xString.Length > 0) { + xToken.Type = TokenType.WhiteSpace; + + } else if (xChar1 == '\'') { + xToken.Type = TokenType.ValueString; + xString = xString.Substring(1, xString.Length - 2); + + } else if (char.IsDigit(xChar1)) { + xToken.Type = TokenType.ValueInt; + if (xString.StartsWith("0x")) { + xToken.SetIntValue(Convert.ToUInt32(xString, 16)); + } else { + xToken.SetIntValue(uint.Parse(xString)); + } + } else if (xChar1 == '$') { + xToken.Type = TokenType.ValueInt; + // Remove surrounding ' + xString = "0x" + xString.Substring(1); + if (xString.StartsWith("0x")) { + xToken.SetIntValue(Convert.ToUInt32(xString, 16)); + } else { + xToken.SetIntValue(uint.Parse(xString)); + } + } else if (IsAlphaNum(xChar1)) { + // This must be after check for ValueInt + string xUpper = xString.ToUpper(); + + // Special parsing when in pattern mode. We recognize some special strings + // which would otherwise be considered as simple AlphaNum token otherwise. + if (mAllowPatterns) { + if (RegisterPatterns.Contains(xUpper)) { + xToken.Type = TokenType.Register; + } else if (xUpper == "_KEYWORD") { + xToken.Type = TokenType.Keyword; + xString = null; + } else if (xUpper == "_ABC") { + xToken.Type = TokenType.AlphaNum; + xString = null; + } else if (xUpper == "_PCALL") { + xString = null; + xToken.Type = TokenType.Call; + } + } + + if (xToken.Type == TokenType.Unknown) { + XSRegisters.Register xRegister; + if (Registers.TryGetValue(xUpper, out xRegister)) { + xToken.Type = TokenType.Register; + xToken.SetRegister(xRegister); + } else if (mKeywords.Contains(xUpper)) { + xToken.Type = TokenType.Keyword; + } else if (xString.Contains("(") && xString.Contains(")") && IsAlphaNum(xChar1)) { + xToken.Type = TokenType.Call; + } else { + xToken.Type = TokenType.AlphaNum; + } + } + + } else if (Delimiters.Contains(xString)) { + xToken.Type = TokenType.Delimiter; + } else if (Operators.Contains(xString)) { + xToken.Type = TokenType.Operator; + } + } + + xToken.RawValue = xString; + xToken.SrcPosStart = mStart; + xToken.SrcPosEnd = xToken.Type == TokenType.Call ? rPos : rPos - 1; + if (mAllWhitespace && (xToken.Type != TokenType.WhiteSpace)) { + mAllWhitespace = false; + } + mStart = xToken.Type == TokenType.Call ? rPos + 1 : rPos; + + if (mIncludeWhiteSpace || (xToken.Type != TokenType.WhiteSpace)) { + aList.Add(xToken); + } + } + + protected enum CharType { + WhiteSpace, + Identifier, + Symbol, + String + }; + + protected bool IsAlphaNum(char aChar) { + return char.IsLetterOrDigit(aChar) || aChar == '_' || aChar == '.' || aChar == '$'; + } + + /// Consume text that has been provided to the class constructor, splitting it into + /// a list of tokens. + /// Line number for diagnostics and debugging. + /// The resulting tokens list. + protected TokenList Parse() { + // Save in comment, might be useful in future. Already had to dig it out of TFS once + //var xRegex = new System.Text.RegularExpressions.Regex(@"(\W)"); + + var xResult = new TokenList(); + CharType xLastCharType = CharType.WhiteSpace; + CharType xCharType = CharType.WhiteSpace; + int i = 0; + for (i = 0; i < mData.Length; i++) { + char xChar = mData[i]; + // Extract string literal (surrounded with single quote characters). + if (xChar == '\'') { + // Take data before the ' as a token. + NextToken(xResult, ref i); + // Now scan to the next ' taking into account escaped single quotes. + bool escapedCharacter = false; + for (i = i + 1; i < mData.Length; i++) { + bool done = false; + switch (mData[i]) { + case '\'': + if (!escapedCharacter) { + done = true; + } + break; + case '\\': + escapedCharacter = !escapedCharacter; + break; + default: + escapedCharacter = false; + break; + } + if (done) { + break; + } + } + if (i == mData.Length) { + throw new Exception("Unterminated string."); + } + i++; + xCharType = CharType.String; + } else if (xChar == '(') { + for (i += 1; i < mData.Length; i++) { + if (mData[i] == ')' && mData.LastIndexOf(")") <= i) { + i++; + NextToken(xResult, ref i); + break; + } + } + } else if (char.IsWhiteSpace(xChar)) { + xCharType = CharType.WhiteSpace; + } else if (IsAlphaNum(xChar)) { + // _ and . were never likely to stand on their own. ie ESP _ 2 and ESP . 2 are never likely to be used. + // Having them on their own required a lot of code + // to treat them as a single unit where we did use them. So we treat them as AlphaNum. + xCharType = CharType.Identifier; + } else { + xCharType = CharType.Symbol; + } + + // i > 0 - Never do NewToken on first char. i = 0 is just a pass to get char and set lastchar. + // But its faster as the second short circuit rather than a separate if. + if ((xCharType != xLastCharType) && (0 < i)) { + NextToken(xResult, ref i); + } + + xLastCharType = xCharType; + } + + // Last token + if (mStart < mData.Length) { + NextToken(xResult, ref i); + } + + return xResult; + } + + /// Create a new Parser instance and immediately consume the given + /// string. On return the property is available for enumeration. + /// The text to be parsed. WARNING : This is expected to be a single full line + /// of text. The parser can be create with a special "pattern recognition" mode. + /// + /// True if is a pattern and thus the parsing + /// should be performed specifically. + /// At least one unrecognized token has been parsed. + public Parser(string aData, bool aIncludeWhiteSpace, bool aAllowPatterns) { + mData = aData; + mIncludeWhiteSpace = aIncludeWhiteSpace; + mAllowPatterns = aAllowPatterns; + mAllWhitespace = true; + + mTokens = Parse(); + if (mTokens.Count(q => q.Type == TokenType.Unknown) > 0) { + foreach (var xToken in mTokens) { + if (xToken.Type == TokenType.Unknown) { + throw new Exception(string.Format("Unknown token '{0}' found at {1}.", xToken.RawValue ?? "NULL", xToken.SrcPosStart)); + } + } + } + } + } +} diff --git a/source/XSharp/XSharp/Gen1/TokenPatterns.cs b/source/XSharp/XSharp/Gen1/TokenPatterns.cs index 9e548493..be38ec5b 100644 --- a/source/XSharp/XSharp/Gen1/TokenPatterns.cs +++ b/source/XSharp/XSharp/Gen1/TokenPatterns.cs @@ -1,1160 +1,1160 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using XSharp.Assembler.x86; - -namespace XSharp -{ - /// This class is able to translate a single X# source code line into one or more - /// target assembler source code and data lines. The class is a group of pattern each of - /// which defines a transformation function from the X# syntax to the target assembler - /// syntax. - public class TokenPatterns { - /// Describe a single pattern with its list of tokens that might include pattern - /// reserved syntax token and a transformation function. For ease of search and performance - /// an hashcode value is computed on the tokens list content and later used for searching - /// a pattern matching an actual line of X# code source. - protected class Pattern { - public readonly TokenList Tokens; - public readonly int Hash; - public readonly CodeFunc Code; - public readonly string PatternString; - - public Pattern(TokenList aTokens, CodeFunc aCode, string patternString) { - Tokens = aTokens; - Hash = aTokens.GetHashCode(); - Code = aCode; - PatternString = patternString; - } - } - - /// The set of blocks for the currently assembled function. Each time we begin - /// assembling a new function this blocks collection is reset to an empty state. - protected Blocks mBlocks = new Blocks(); - - protected class Blocks : List { - protected int mCurrentLabelID = 0; - - public void Reset() { - mCurrentLabelID = 0; - } - - public Block Current() { - return base[Count - 1]; - } - - public void Start(TokenList aTokens, bool aIsCollector) { - var xBlock = new Block(); - mCurrentLabelID++; - xBlock.LabelID = mCurrentLabelID; - xBlock.StartTokens = aTokens; - - // Last because we use Current() above - Add(xBlock); - xBlock.ParentAssembler = Assembler.Assembler.CurrentInstance; - new Assembler.Assembler(); - } - - public void End() { - Assembler.Assembler.ClearCurrentInstance(); - RemoveAt(Count - 1); - } - } - protected class Block { - public TokenList StartTokens; - public int LabelID; - - public Assembler.Assembler ParentAssembler; - - public void AddContentsToParentAssembler() { - ParentAssembler.Instructions.AddRange(Assembler.Assembler.CurrentInstance.Instructions); - } - } - - protected string mFuncName = null; - protected bool mFuncExitFound = false; - - public bool EmitUserComments = true; - public delegate void CodeFunc(TokenList aTokens); - protected List mPatterns = new List(); - protected bool mInIntHandler; - protected string[] mCompareOps; - protected List mCompares = new List(); - - protected string mNamespace = null; - protected string GetNamespace() { - if (mNamespace == null) { - throw new Exception("A namespace has not been defined."); - } - return mNamespace; - } - - public TokenPatterns() { - mCompareOps = "< > = != <= >= 0 !0".Split(' '); - var xSizes = "byte , word , dword ".Split(',').ToList(); - // We must add this empty size so that we allow constructs where the size is not - // explicitly defined in source code. For example : while eax < 0 - // otherwise we would have to write : while dword eax < 0 - xSizes.Add(""); - foreach (var xSize in xSizes) { - foreach (var xComparison in mCompareOps) { - // Skip 0 and !0 - if (!xComparison.Contains("0")) { - mCompares.Add(xSize + "_REG " + xComparison + " 123"); - mCompares.Add(xSize + "_REG " + xComparison + " _REG"); - mCompares.Add(xSize + "_REG " + xComparison + " _REGADDR[1]"); - mCompares.Add(xSize + "_REG " + xComparison + " _REGADDR[-1]"); - mCompares.Add(xSize + "_REG " + xComparison + " _ABC"); - mCompares.Add(xSize + "_REG " + xComparison + " #_ABC"); - // - mCompares.Add(xSize + "_REGADDR[1] " + xComparison + " 123"); - mCompares.Add(xSize + "_REGADDR[-1] " + xComparison + " 123"); - mCompares.Add(xSize + "_REGADDR[1] " + xComparison + " _REG"); - mCompares.Add(xSize + "_REGADDR[-1] " + xComparison + " _REG"); - mCompares.Add(xSize + "_REGADDR[1] " + xComparison + " #_ABC"); - mCompares.Add(xSize + "_REGADDR[-1] " + xComparison + " #_ABC"); - // - mCompares.Add(xSize + "_ABC " + xComparison + " 123"); - mCompares.Add(xSize + "_ABC " + xComparison + " _REG"); - mCompares.Add(xSize + "_ABC " + xComparison + " #_ABC"); - } - } - } - - AddPatterns(); - } - - /// Builds a label that is suitable to denote a constant which name is given by the - /// token. - /// - /// - protected string ConstLabel(Token aToken) { - return GroupLabel("Const_" + aToken); - } - - /// Builds a label at namespace level having the given name. - /// Local label name at namespace level. - /// The label name - protected string GroupLabel(string aLabel) { - return GetNamespace() + "_" + aLabel; - } - - /// Builds a label at function level having the given name. - /// Local label name at function level. - /// The label name - protected string FuncLabel(string aLabel) { - return GetNamespace() + "_" + mFuncName + "_" + aLabel; - } - - /// Builds a label having the given name at current function block level. - /// Local label name at function block level. - /// The label name. - protected string BlockLabel(string aLabel) { - return FuncLabel("Block" + mBlocks.Current().LabelID + "_" + aLabel); - } - - /// Build a label name for the given token. This method enforce the rule for . - /// and .. prefixes and build the label at appropriate level. - /// - /// - protected string GetLabel(Token aToken) { - if ((aToken.Type != TokenType.AlphaNum) && !aToken.Matches("exit")) { - throw new Exception("Label must be AlphaNum."); - } - - string xValue = aToken.RawValue; - if (!InFunctionBody) { - if (xValue.StartsWith(".")) { - return xValue.Substring(1); - } - return GroupLabel(xValue); - } else { - if (xValue.StartsWith("..")) { - return xValue.Substring(2); - } else if (xValue.StartsWith(".")) { - return GroupLabel(xValue.Substring(1)); - } - return FuncLabel(xValue); - } - } - - /// Get a flag that tell if we are in a function body or not. This is used by the - /// assembler generator when end of source file is reached to make sure the last function - /// or interrupt handler is properly closed (see issue #15666) - internal bool InFunctionBody { - get { return !string.IsNullOrEmpty(mFuncName); } - } - - /// Start a new function having the given name. The current blocks collection is - /// reset to an empty state and the function name is saved for later reuse in local to function - /// labels' name construction. - /// Function name. - protected void StartFunc(string aName) { - if (InFunctionBody) { - throw new Exception( - "Found a function/interrupt handler definition embedded inside another function/interrupt handler."); - } - mFuncName = aName; - mFuncExitFound = false; - mBlocks.Reset(); - } - - /// Terminate assembling current function. If a local to function exit label has not - /// been explicitly defined a new one is automatically created. This is because some "return" - /// keyword might have been used in function X# code. This keyword requires an exit label to - /// be defined at function level. This method also automatically insert an IRET or RET instruction - /// depending on whether the function is an interrupt handler or a standard function. - protected void EndFunc() { - if (null == mFuncName) { - throw new Exception("Found a closing curly brace that doesn't match an opening curly brace."); - } - if (!mFuncExitFound) { - XS.Label(GetNamespace() + "_" + mFuncName + "_Exit"); - } - if (mInIntHandler) { - XS.InterruptReturn(); - } else { - // TODO: this shouldn't be here - XS.Set("INTs_LastKnownAddress", GetNamespace() + "_" + mFuncName + "_Exit", destinationIsIndirect: true, size: XSRegisters.RegisterSize.Int32); - XS.Return(); - } - mFuncName = null; - } - - protected string GetSimpleRef(Token aToken) { - return GetLabel(aToken); - } - - private static XSRegisters.RegisterSize GetSize(Token aToken) { - return GetSize(aToken.RawValue); - } - - private static XSRegisters.RegisterSize GetSize(string value) { - switch (value) { - case "byte": - return XSRegisters.RegisterSize.Byte8; - case "word": - return XSRegisters.RegisterSize.Short16; - case "dword": - return XSRegisters.RegisterSize.Int32; - default: - throw new Exception($"Invalid size '{value}'"); - } - } - - private static string GetSizeString(XSRegisters.RegisterSize size) { - switch (size) { - case XSRegisters.RegisterSize.Byte8: - return "byte"; - case XSRegisters.RegisterSize.Short16: - return "word"; - case XSRegisters.RegisterSize.Int32: - return "dword"; - default: - throw new ArgumentOutOfRangeException(nameof(size), size, null); - } - } - - protected string GetRef(List aTokens, ref int rIdx, bool onlySingleTokenRefs = false) { - var xToken1 = aTokens[rIdx]; - Token xToken2 = null; - if (rIdx + 1 < aTokens.Count - && !onlySingleTokenRefs) { - xToken2 = aTokens[rIdx + 1]; - } - if (xToken1.Type == TokenType.Register) { - if (xToken2 != null - && xToken2.RawValue == "[") { - if (aTokens[rIdx + 2].RawValue == "-") { - rIdx += 5; - return "[" + xToken1 + " - " + aTokens[rIdx - 2] + "]"; - } - rIdx += 4; - return "[" + xToken1 + " + " + aTokens[rIdx - 2] + "]"; - } - rIdx += 1; - return xToken1.RawValue; - } else if (xToken1.Type == TokenType.AlphaNum) { - rIdx += 1; - return "[" + GetLabel(xToken1) + "]"; - } else if (xToken1.Type == TokenType.ValueInt) { - rIdx += 1; - return xToken1.RawValue; - } else if (xToken1.Type == TokenType.Call) { - rIdx += 1; - return "@ret_on_stack@"; - } else if (xToken1.RawValue == "#") { - rIdx += 2; - return ConstLabel(xToken2); - } else { - throw new Exception("Cannot determine reference"); - } - } - - protected ConditionalTestEnum GetJump(string aComparison, bool aInvert = false) { - if (aInvert) { - if (aComparison == "<") { - aComparison = ">="; - } else if (aComparison == ">") { - aComparison = "<="; - } else if (aComparison == "=") { - aComparison = "!="; - } else if (aComparison == "0") { - // Same as JE, but implies intent in .asm better - aComparison = "!0"; - } else if (aComparison == "!0") { - // Same as JE, but implies intent in .asm better - aComparison = "0"; - } else if (aComparison == "!=") { - aComparison = "="; - } else if (aComparison == "<=") { - aComparison = ">"; - } else if (aComparison == ">=") { - aComparison = "<"; - } else { - throw new Exception("Unrecognized symbol in conditional: " + aComparison); - } - } - - if (aComparison == "<") { - return ConditionalTestEnum.Below; // unsigned - } else if (aComparison == ">") { - return ConditionalTestEnum.Above; // unsigned - } else if (aComparison == "=") { - return ConditionalTestEnum.Equal; - } else if (aComparison == "0") { - // Same as JE, but implies intent in .asm better - return ConditionalTestEnum.Zero; - } else if (aComparison == "!=") { - return ConditionalTestEnum.NotEqual; - } else if (aComparison == "!0") { - // Same as JNE, but implies intent in .asm better - return ConditionalTestEnum.NotZero; - } else if (aComparison == "<=") { - return ConditionalTestEnum.BelowOrEqual; // unsigned - } else if (aComparison == ">=") { - return ConditionalTestEnum.AboveOrEqual; // unsigned - } else { - throw new Exception("Unrecognized symbol in conditional: " + aComparison); - } - } - - protected void HandleIf(TokenList aTokens, string xComparison) { - string xLabel; - var xLast = aTokens.Last(); - if (xLast.RawValue == "{") { - mBlocks.Start(aTokens, false); - XS.Jump(GetJump(xComparison, true), BlockLabel("End")); - } else { - if (xLast.Matches("return")) { - xLabel = FuncLabel("Exit"); - } else { - xLabel = GetLabel(xLast); - } - - XS.Jump(GetJump(xComparison), xLabel); - } - } - - protected void AddPatterns() { - AddPattern("! Mov EAX, 0", delegate (TokenList aTokens) { - XS.LiteralCode(aTokens[0].RawValue); - }); - - AddPattern("// Comment", delegate (TokenList aTokens) { - if (EmitUserComments) { - string xValue = aTokens[0].RawValue; - xValue = xValue.Replace("\"", "\\\""); - XS.Comment(xValue); - } - }); - - // The value function returns a token containing the comparison - var xCompares = new Dictionary>(); - var xSizes = new[] - { - "", "byte", "word", "dword" - }; - #region Handle all comparisons - foreach (var xSize in xSizes) { - foreach (var xComparison in mCompareOps) { - var xComparisonToken = new Token(); - xComparisonToken.RawValue = xComparison; - // Skip 0 and !0 - if (!xComparison.Contains("0")) { - xCompares.Add(xSize + " _REG " + xComparison + " 123", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].IntValue, size: xTypedSize); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REG " + xComparison + " _REG", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REG " + xComparison + " _REGADDR[1]", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, sourceDisplacement: (int)tokenList[xOffset + 3].IntValue); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REG " + xComparison + " _REGADDR[-1]", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, sourceDisplacement: -(int)tokenList[xOffset + 3].IntValue); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REG " + xComparison + " _ABC", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, GetLabel(tokenList[xOffset + 2]), sourceIsIndirect: true); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REG " + xComparison + " #_ABC", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, ConstLabel(tokenList[xOffset + 3])); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REGADDR[1] " + xComparison + " 123", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 5].IntValue, destinationDisplacement: (int)tokenList[xOffset + 2].IntValue, size: xTypedSize); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REGADDR[-1] " + xComparison + " 123", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].IntValue, destinationDisplacement: -(int)tokenList[xOffset + 1].IntValue, size: xTypedSize); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REGADDR[1] " + xComparison + " _REG", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, destinationDisplacement: (int)tokenList[xOffset + 1].IntValue); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REGADDR[-1] " + xComparison + " _REG", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, destinationDisplacement: -(int)tokenList[xOffset + 1].IntValue); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REGADDR[1] " + xComparison + " #_ABC", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, ConstLabel(tokenList[xOffset + 2]), destinationDisplacement: (int)tokenList[xOffset + 1].IntValue, sourceIsIndirect: true, size: xTypedSize); - return xComparisonToken; - }); - xCompares.Add(xSize + " _REGADDR[-1] " + xComparison + " #_ABC", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(tokenList[xOffset + 0].Register, ConstLabel(tokenList[xOffset + 2]), destinationDisplacement: (int)tokenList[xOffset + 1].IntValue, size: xTypedSize); - return xComparisonToken; - }); - xCompares.Add(xSize + " _ABC " + xComparison + " 123", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(GetLabel(tokenList[xOffset + 0]), tokenList[xOffset + 2].IntValue, destinationIsIndirect: true, size: xTypedSize.GetValueOrDefault(XSRegisters.RegisterSize.Int32)); - return xComparisonToken; - }); - xCompares.Add(xSize + " _ABC " + xComparison + " _REG", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - if (tokenList[xOffset + 2].Type != TokenType.Register) { - xOffset += 1; - } - XS.Compare(GetSimpleRef(tokenList[xOffset + 0]), tokenList[xOffset + 2].Register, destinationIsIndirect: true); - return xComparisonToken; - }); - xCompares.Add(xSize + " _ABC " + xComparison + " #_ABC", - (tokenOffset, tokenList) => { - var xOffset = tokenOffset; - XSRegisters.RegisterSize? xTypedSize = null; - if (tokenList[xOffset].Type != TokenType.Register) { - xTypedSize = GetSize(tokenList[xOffset]); - xOffset += 1; - } - XS.Compare(GetSimpleRef(tokenList[xOffset + 0]), ConstLabel(tokenList[xOffset + 3]), destinationIsIndirect: true, size: xTypedSize.GetValueOrDefault(XSRegisters.RegisterSize.Int32)); - return xComparisonToken; - }); - } - } - } - #endregion Handle all comparisons - // Labels - // Local and proc level are used most, so designed to make their syntax shortest. - // Think of the dots like a directory, . is current group, .. is above that. - // ..Name: - Global level. Emitted exactly as is. - // .Name: - Group level. Group_Name - // Name: - Function level. Group_ProcName_Name - - // The Exit label is a special one that is used as a target for the return instruction. - // It deserve special handling. - AddPattern("Exit:", delegate (TokenList aTokens) { - XS.Label(GetLabel(aTokens[0])); - mFuncExitFound = true; - }); - - // Regular label recognition. - AddPattern("_ABC:", delegate (TokenList aTokens) { - XS.Label(GetLabel(aTokens[0])); - }); - - AddPattern("Call _ABC", delegate (TokenList aTokens) { - XS.Call(GetLabel(aTokens[1])); - }); - AddPattern("_PCALL", delegate (TokenList aTokens) { - if (aTokens.Count != 1 - || aTokens[0].Type != TokenType.Call) { - throw new Exception("Error occured in parametrized call parsing"); - } else { - List mparts = aTokens[0].RawValue.Remove(aTokens[0].RawValue.Length - 1).Split('(').ToList(); - if (mparts.Count < 2) { - throw new Exception("Error occured in parametrized call parsing"); - } - string fname = mparts[0]; - mparts.RemoveAt(0); - aTokens[0].RawValue = String.Join("(", mparts).Trim(); - string val = ""; - int idx; - - var xParams = new List(); - int level = 0; - foreach (char c in aTokens[0].RawValue) { - switch (c) { - case ',': - if (level == 0) { - xParams.Add(val.Trim()); - val = ""; - } - break; - case '(': - level++; - val += c; - break; - case ')': - level--; - val += c; - break; - default: - val += c; - break; - } - } - if (!String.IsNullOrEmpty(val.Trim())) { - xParams.Add(val); - } - if (level != 0) { - throw new Exception("'(' occured without closing equivalent ')' in parametrized function call"); - } - - Parser xParser; - xParams.Reverse(); - foreach (string p in xParams) { - xParser = new Parser(p, false, false); - idx = 0; - val = GetRef(xParser.Tokens, ref idx); - if (val != "@ret_on_stack@") { - //XS.PushLiteral(val); - throw new Exception(); - } else { - //aAsm += GetPatternCode(xParser.Tokens).GetCode(false); - throw new NotImplementedException("Didn't get converted yet!"); - } - } - XS.Call(GroupLabel(fname)); - } - }); - - AddPattern("Goto _ABC", delegate (TokenList aTokens) { - XS.Jump(GetLabel(aTokens[1])); - }); - - // Defines a constant having the given name and initial value. - AddPattern("const _ABC = 123", delegate (TokenList aTokens) { - XS.Const(ConstLabel(aTokens[1]), aTokens[3].IntValue.ToString()); - }); - - // Declare a double word variable having the given name and initialized to 0. The - // variable is declared at namespace level. - AddPattern("var _ABC", delegate (TokenList aTokens) { - XS.DataMember(GetLabel(aTokens[1])); - }); - - // Declare a doubleword variable having the given name and an explicit initial value. The - // variable is declared at namespace level. - AddPattern("var _ABC = 123", delegate (TokenList aTokens) { - XS.DataMember(GetLabel(aTokens[1]), aTokens[3].IntValue); - }); - - // Declare a textual variable having the given name and value. The variable is defined at - // namespace level and a null terminating byte is automatically added after the textual - // value. - AddPattern("var _ABC = 'Text'", delegate (TokenList aTokens) { - // Fix issue #15660 by using backquotes for string surrounding and escaping embedded - // back quotes. - XS.DataMember(GetLabel(aTokens[1]), EscapeBackQuotes(aTokens[3].RawValue)); - }); - - // Declare a one-dimension array of bytes, words or doublewords. All members are initialized to 0. - // _ABC is array name. 123 is the total number of items in the array. - AddPattern(new string[] - { - "var _ABC byte[123]", "var _ABC word[123]", "var _ABC dword[123]" - }, delegate (TokenList aTokens) { - string xSize; - if (aTokens[2].Matches("byte")) { - xSize = "db"; - } else if (aTokens[2].Matches("word")) { - xSize = "dw"; - } else if (aTokens[2].Matches("dword")) { - xSize = "dd"; - } else { - throw new Exception("Unknown size specified"); - } - XS.DataMember(GetLabel(aTokens[1]), aTokens[4].IntValue, xSize, "0"); - }); - - foreach (var xCompare in xCompares) { - // 0 1 2 3 4 - AddPattern("while " + xCompare.Key + " {", delegate (TokenList aTokens) { - mBlocks.Start(aTokens, false); - XS.Label(BlockLabel("Begin")); - - Token xComparison = xCompare.Value(1, aTokens); - - XS.Jump(GetJump(xComparison.RawValue, true), BlockLabel("End")); - }); - } - - foreach (var xTail in "goto _ABC|return|{".Split('|')) { - // if 0 exit, etc - foreach (var xComparison in mCompareOps) { - AddPattern("if " + xComparison + " " + xTail, delegate (TokenList aTokens) { - string xOp = aTokens[1].RawValue; - - // !0 is 2 tokens - if (aTokens[1].RawValue + aTokens[2].RawValue == "!0") { - xOp = "!0"; - } - - HandleIf(aTokens, xOp); - }); - } - - // if reg = x exit, etc - foreach (var xCompare in xCompares) { - // 0 1 2 3 4 - AddPattern("if " + xCompare.Key + " " + xTail, - delegate (TokenList aTokens) { - Token xComparison = xCompare.Value(1, aTokens); - - HandleIf(aTokens, xComparison.RawValue); - }); - } - } - - AddPattern("_REG ?= 123", delegate (TokenList aTokens) { - XS.Compare(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern("_REG ?= _ABC", delegate (TokenList aTokens) { - XS.Compare(aTokens[0].Register, GetSimpleRef(aTokens[2]), sourceIsIndirect: true); - }); - AddPattern("_REG ?= #_ABC", delegate (TokenList aTokens) { - XS.Compare(aTokens[0].Register, ConstLabel(aTokens[2])); - }); - - AddPattern("_REG ?& 123", delegate (TokenList aTokens) { - XS.Test(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern("_REG ?& _ABC", delegate (TokenList aTokens) { - XS.Test(aTokens[0].Register, GetLabel(aTokens[2]), sourceIsIndirect: true); - }); - AddPattern("_REG ?& #_ABC", delegate (TokenList aTokens) { - XS.Test(aTokens[0].Register, GetLabel(aTokens[2]), sourceIsIndirect: true); - }); - - AddPattern("_REG ~> 123", delegate (TokenList aTokens) { - XS.RotateRight(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern("_REG <~ 123", delegate (TokenList aTokens) { - XS.RotateLeft(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern("_REG >> 123", delegate (TokenList aTokens) { - if (aTokens[2].IntValue > 255) { - throw new IndexOutOfRangeException("Value is too large to be used as bitcount!"); - } - XS.ShiftRight(aTokens[0].Register, (byte)aTokens[2].IntValue); - }); - AddPattern("_REG << 123", delegate (TokenList aTokens) { - if (aTokens[2].IntValue > 255) { - throw new IndexOutOfRangeException("Value is too large to be used as bitcount!"); - } - XS.ShiftLeft(aTokens[0].Register, (byte)aTokens[2].IntValue); - }); - - AddPattern("_REG = 123", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern("_REGADDR[1] = 123", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[5].IntValue, destinationDisplacement: (int)aTokens[2].IntValue, size: XSRegisters.RegisterSize.Int32); - }); - AddPattern("_REGADDR[-1] = 123", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[5].IntValue, destinationDisplacement: -(int)aTokens[2].IntValue, size: XSRegisters.RegisterSize.Int32); - }); - - AddPattern("_REG = #_ABC", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, ConstLabel(aTokens[3])); - }); - AddPattern("_REGADDR[1] = #_ABC", delegate (TokenList aTokens) { - //XS.Set(RegisterSize.Int32, aTokens[0].IntValue, aTokens[2].IntValue, ConstLabel(aTokens[5])); - throw new NotImplementedException(""); - }); - AddPattern("_REGADDR[-1] = #_ABC", delegate (TokenList aTokens) { - var xFirst = GetSimpleRef(aTokens[0]); - var xSecond = GetSimpleRef(aTokens[2]); - - //XS.SetLiteral("dword [" + xFirst + " - " + xSecond + "]", ConstLabel(aTokens[5])); - throw new NotImplementedException(""); - }); - - AddPattern("_REG = _REG", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[2].Register); - }); - AddPattern("_REGADDR[1] = _REG", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[5].Register, destinationDisplacement: (int)aTokens[2].IntValue); - }); - AddPattern("_REGADDR[-1] = _REG", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[5].Register, destinationDisplacement: -(int)aTokens[2].IntValue); - }); - AddPattern("_REG = _REGADDR[1]", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[2].Register, sourceDisplacement: (int)aTokens[4].IntValue); - }); - AddPattern("_REG = _REGADDR[-1]", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[2].Register, sourceDisplacement: -(int)aTokens[4].IntValue); - }); - - AddPattern("_REG = [_REG]", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[3].Register, sourceIsIndirect: true); - }); - AddPattern("_REG = [_REG + 1]", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[3].Register, sourceDisplacement: (int?)aTokens[5].IntValue); - }); - AddPattern("_REG = [_REG - 1]", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[3].Register, sourceDisplacement: -(int)aTokens[5].IntValue); - }); - AddPattern("[_REG] = _REG", delegate (TokenList aTokens) { - XS.Set(aTokens[1].Register, aTokens[4].Register, destinationIsIndirect: true); - }); - AddPattern("[_REG + 1] = _REG", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[3].Register, destinationDisplacement: (int)aTokens[5].IntValue); - }); - AddPattern("[_REG - 1] = _REG", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, aTokens[3].Register, destinationDisplacement: -(int)aTokens[5].IntValue); - }); - - AddPattern("_REG = _ABC", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, GetLabel(aTokens[2]), sourceIsIndirect: true); - }); - - // why not [var] like registers? Because its less frequent to access the ptr - // and it is like a reg.. without [] to get the value... - AddPattern("_REG = @_ABC", delegate (TokenList aTokens) { - XS.Set(aTokens[0].Register, GetLabel(aTokens[3])); - }); - - AddPattern(new string[] - { - "Port[DX] = AL", "Port[DX] = AX", "Port[DX] = EAX" - }, delegate (TokenList aTokens) { - XS.WriteToPortDX(aTokens[5].Register); - }); - AddPattern(new string[] - { - "AL = Port[DX]", "AX = Port[DX]", "EAX = Port[DX]" - }, delegate (TokenList aTokens) { - XS.ReadFromPortDX(aTokens[0].Register); - }); - - AddPattern("+123", delegate (TokenList aTokens) { - XS.Push(aTokens[0].IntValue, size: XSRegisters.RegisterSize.Int32); - }); - AddPattern(new string[] - { - "+123 as byte", "+123 as word", "+123 as dword" - }, delegate (TokenList aTokens) { - var xSize = GetSize(aTokens[1]); - XS.Push(aTokens[1].IntValue, size: xSize); - }); - AddPattern("+_REG", delegate (TokenList aTokens) { - XS.Push(aTokens[1].Register); - }); - AddPattern(new string[] - { - //0 1 2 3 - "+#_ABC", "+#_ABC as byte", "+#_ABC as word", "+#_ABC as dword" - }, delegate (TokenList aTokens) { - XSRegisters.RegisterSize xSize = XSRegisters.RegisterSize.Int32; - if (aTokens.Count > 2) { - xSize = GetSize(aTokens[3]); - } - XS.Push(ConstLabel(aTokens[1]), size: xSize); - }); - AddPattern("+All", delegate (TokenList aTokens) { - XS.PushAllRegisters(); - }); - AddPattern("-All", delegate (TokenList aTokens) { - XS.PopAllRegisters(); - }); - AddPattern("-_REG", delegate (TokenList aTokens) { - XS.Pop(aTokens[1].Register); - }); - - AddPattern("_ABC = _REG", delegate (TokenList aTokens) { - XS.Set(GetLabel(aTokens[0]), aTokens[2].Register, destinationIsIndirect: true); - }); - AddPattern("_ABC = #_ABC", delegate (TokenList aTokens) { - XS.Set(GetLabel(aTokens[0]), ConstLabel(aTokens[3]), destinationIsIndirect: true, size: XSRegisters.RegisterSize.Int32); - }); - AddPattern("_ABC = 123", delegate (TokenList aTokens) { - XS.Set(GetLabel(aTokens[0]), aTokens[2].IntValue, destinationIsIndirect: true); - }); - AddPattern(new string[] - { - "_ABC = 123 as byte", "_ABC = 123 as word", "_ABC = 123 as dword" - }, delegate (TokenList aTokens) { - XS.Set(GetLabel(aTokens[0]), aTokens[2].IntValue, size: GetSize(aTokens[4])); - }); - - AddPattern(new string[] - { - "_REG + 1", - }, delegate (TokenList aTokens) { - XS.Add(aTokens[0].Register, aTokens[2].IntValue); - }); - - AddPattern(new string[] - { - "_REG + _REG" - }, delegate (TokenList aTokens) { - XS.Add(aTokens[0].Register, aTokens[2].Register); - }); - AddPattern(new string[] - { - "_REG - 1", - }, delegate (TokenList aTokens) { - XS.Sub(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern(new string[] - { - "_REG - _REG" - }, delegate (TokenList aTokens) { - XS.Sub(aTokens[0].Register, aTokens[2].Register); - }); - AddPattern(new string[] - { - "_REG * 1", - }, delegate (TokenList aTokens) { - XS.IntegerMultiply(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern(new string[] - { - "_REG * _REG" - }, delegate (TokenList aTokens) { - XS.IntegerMultiply(aTokens[0].Register, aTokens[2].Register); - }); - AddPattern("_REG++", delegate (TokenList aTokens) { - XS.Increment(aTokens[0].Register); - }); - AddPattern("_REG--", delegate (TokenList aTokens) { - XS.Decrement(aTokens[0].Register); - }); - - AddPattern(new string[] - { - "_REG & 1", - }, delegate (TokenList aTokens) { - XS.And(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern(new string[] - { - "_REG & _REG" - }, delegate (TokenList aTokens) { - XS.And(aTokens[0].Register, aTokens[2].Register); - }); - AddPattern(new string[] - { - "_REG | 1", - }, delegate (TokenList aTokens) { - XS.Or(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern(new string[] - { - "_REG | _REG" - }, delegate (TokenList aTokens) { - XS.Or(aTokens[0].Register, aTokens[2].Register); - }); - AddPattern(new string[] - { - "_REG ^ 1", - }, delegate (TokenList aTokens) { - XS.Xor(aTokens[0].Register, aTokens[2].IntValue); - }); - AddPattern(new string[] - { - "_REG ^ _REG" - }, delegate (TokenList aTokens) { - XS.Xor(aTokens[0].Register, aTokens[2].Register); - }); - - // End block. This handle both terminating a standard block as well as a function or an - // interrupt handler. - AddPattern("}", delegate (TokenList aTokens) { - if (mBlocks.Count == 0) { - EndFunc(); - } else { - var xBlock = mBlocks.Current(); - var xToken1 = xBlock.StartTokens[0]; - if (xToken1.Matches("repeat")) { - var xCount = xBlock.StartTokens[1].IntValue; - for (var i = 1; i <= xCount; i++) { - xBlock.AddContentsToParentAssembler(); - } - } else if (xToken1.Matches("while")) { - XS.Jump(BlockLabel("Begin")); - XS.Label(BlockLabel("End")); - xBlock.AddContentsToParentAssembler(); - } else if (xToken1.Matches("if")) { - XS.Label(BlockLabel("End")); - xBlock.AddContentsToParentAssembler(); - } else { - throw new Exception("Unknown block starter."); - } - mBlocks.End(); - } - }); - - AddPattern("namespace _ABC", delegate (TokenList aTokens) { - mNamespace = aTokens[1].RawValue; - }); - - AddPattern("Return", delegate { - XS.Jump(FuncLabel("Exit")); - }); - - AddPattern("Repeat 4 times {", delegate (TokenList aTokens) { - mBlocks.Start(aTokens, true); - }); - - AddPattern("Interrupt _ABC {", delegate (TokenList aTokens) { - StartFunc(aTokens[1].RawValue); - mInIntHandler = true; - XS.Label(GetNamespace() + "_" + aTokens[1].RawValue); - }); - - // This needs to be different from return. - // return jumps to exit, ret does raw x86 ret - AddPattern("Ret", delegate (TokenList aTokens) { - XS.Return(); - }); - AddPattern("IRet", delegate (TokenList aTokens) { - XS.InterruptReturn(); - }); - - AddPattern("Function _ABC {", delegate (TokenList aTokens) { - StartFunc(aTokens[1].RawValue); - mInIntHandler = false; - XS.Label(GetNamespace() + "_" + aTokens[1].RawValue); - }); - - AddPattern("Checkpoint 'Text'", delegate (TokenList aTokens) { - // This method emits a lot of ASM, but thats what we want becuase - // at this point we need ASM as simple as possible and completely transparent. - // No stack changes, no register mods, no calls, no jumps, etc. - - // TODO: Add an option on the debug project properties to turn this off. - // Also see WriteDebugVideo in CosmosAssembler.cs - var xPreBootLogging = true; - if (xPreBootLogging) { - UInt32 xVideo = 0xB8000; - for (UInt32 i = xVideo; i < xVideo + 80 * 2; i = i + 2) { - XS.SetByte(i, 0); - XS.SetByte(i + 1, 2); - } - - foreach (var xChar in aTokens[1].RawValue) { - XS.SetByte(xVideo, (byte)xChar); - xVideo = xVideo + 2; - } - } - }); - } - - /// Fix issue #15660. This method escapes double quotes in the candidate string. - /// The string to be sanitized. - /// The original string with escaped double quotes. - private static string EscapeBackQuotes(string from) { - StringBuilder builder = new StringBuilder(); - bool sanitized = false; - bool escaped = false; - foreach (char scannedCharacter in from) { - switch (scannedCharacter) { - case '\\': - escaped = !escaped; - break; - case '`': - if (!escaped) { - sanitized = true; - builder.Append('\\'); - } - escaped = false; - break; - default: - escaped = false; - break; - } - builder.Append(scannedCharacter); - } - return (sanitized) ? builder.ToString() : from; - } - - protected Pattern FindMatch(TokenList aTokens) { - int xHash = aTokens.GetPatternHashCode(); - - // Get a list of matching hashes, but then we have to - // search for exact pattern match because it is possible - // to have duplicate hashes. Hashes just provide us a quick way - // to reduce the search. - foreach (var xPattern in mPatterns.Where(q => q.Hash == xHash)) { - if (xPattern.Tokens.PatternMatches(aTokens)) { - return xPattern; - } - } - return null; - } - - public bool GetPatternCode(TokenList aTokens) { - var xPattern = FindMatch(aTokens); - if (xPattern == null) { - return false; - } - - xPattern.Code(aTokens); - - //// Apply {0} etc into string - //// This happens twice for block code, but its ok because the first pass - //// strips out all tags. - //for (int i = 0; i < xResult.Code.Count; i++) { - // xResult.Code[i] = string.Format(xResult.Code[i], aTokens.ToArray()); - //} - return true; - } - - public void Assemble(string aLine) { - var xParser = new Parser(aLine, false, false); - var xTokens = xParser.Tokens; - - if (GetPatternCode(xTokens) == false) { - if (xTokens.Count == 0) { - throw new Exception("Parsing error: " + aLine); - } - - var xFirst = xTokens[0]; - var xLast = xTokens[xTokens.Count - 1]; - - // Find match and emit X# - if (xTokens.Count == 2 - && xFirst.Type == TokenType.AlphaNum - && xLast.Matches("()")) { - // () could be handled by pattern, but best to keep in one place for future - //xResult += "Call " + GroupLabel(aTokens[0].Value); - XS.Call(GroupLabel(xTokens[0].RawValue)); - } - } - } - - /// Register a single pattern with its associated transformation handler. - /// A single line of X# code that define the pattern optionally using - /// pattern reserved syntax. - /// The associated code transformation handler. - protected void AddPattern(string aPattern, CodeFunc aCode) { - Parser xParser = null; - try { - xParser = new Parser(aPattern, false, true); - } catch (Exception e) { - throw new Exception(string.Format("Invalid pattern '{0}'", aPattern ?? "NULL"), e); - } - var xPattern = new Pattern(xParser.Tokens, aCode, aPattern); - mPatterns.Add(xPattern); - } - - /// Register a collection of patterns that share a single transformation handler. - /// - /// A collection of X# lines of code. Each line of code define a - /// pattern optionally using the pattern reserved syntax. - /// The code transformation handler that is common abmongst all the - /// patterns from the collection. - protected void AddPattern(string[] aPatterns, CodeFunc aCode) { - foreach (var xPattern in aPatterns) { - AddPattern(xPattern, aCode); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using XSharp.Assembler.x86; + +namespace XSharp +{ + /// This class is able to translate a single X# source code line into one or more + /// target assembler source code and data lines. The class is a group of pattern each of + /// which defines a transformation function from the X# syntax to the target assembler + /// syntax. + public class TokenPatterns { + /// Describe a single pattern with its list of tokens that might include pattern + /// reserved syntax token and a transformation function. For ease of search and performance + /// an hashcode value is computed on the tokens list content and later used for searching + /// a pattern matching an actual line of X# code source. + protected class Pattern { + public readonly TokenList Tokens; + public readonly int Hash; + public readonly CodeFunc Code; + public readonly string PatternString; + + public Pattern(TokenList aTokens, CodeFunc aCode, string patternString) { + Tokens = aTokens; + Hash = aTokens.GetHashCode(); + Code = aCode; + PatternString = patternString; + } + } + + /// The set of blocks for the currently assembled function. Each time we begin + /// assembling a new function this blocks collection is reset to an empty state. + protected Blocks mBlocks = new Blocks(); + + protected class Blocks : List { + protected int mCurrentLabelID = 0; + + public void Reset() { + mCurrentLabelID = 0; + } + + public Block Current() { + return base[Count - 1]; + } + + public void Start(TokenList aTokens, bool aIsCollector) { + var xBlock = new Block(); + mCurrentLabelID++; + xBlock.LabelID = mCurrentLabelID; + xBlock.StartTokens = aTokens; + + // Last because we use Current() above + Add(xBlock); + xBlock.ParentAssembler = Assembler.Assembler.CurrentInstance; + new Assembler.Assembler(); + } + + public void End() { + Assembler.Assembler.ClearCurrentInstance(); + RemoveAt(Count - 1); + } + } + protected class Block { + public TokenList StartTokens; + public int LabelID; + + public Assembler.Assembler ParentAssembler; + + public void AddContentsToParentAssembler() { + ParentAssembler.Instructions.AddRange(Assembler.Assembler.CurrentInstance.Instructions); + } + } + + protected string mFuncName = null; + protected bool mFuncExitFound = false; + + public bool EmitUserComments = true; + public delegate void CodeFunc(TokenList aTokens); + protected List mPatterns = new List(); + protected bool mInIntHandler; + protected string[] mCompareOps; + protected List mCompares = new List(); + + protected string mNamespace = null; + protected string GetNamespace() { + if (mNamespace == null) { + throw new Exception("A namespace has not been defined."); + } + return mNamespace; + } + + public TokenPatterns() { + mCompareOps = "< > = != <= >= 0 !0".Split(' '); + var xSizes = "byte , word , dword ".Split(',').ToList(); + // We must add this empty size so that we allow constructs where the size is not + // explicitly defined in source code. For example : while eax < 0 + // otherwise we would have to write : while dword eax < 0 + xSizes.Add(""); + foreach (var xSize in xSizes) { + foreach (var xComparison in mCompareOps) { + // Skip 0 and !0 + if (!xComparison.Contains("0")) { + mCompares.Add(xSize + "_REG " + xComparison + " 123"); + mCompares.Add(xSize + "_REG " + xComparison + " _REG"); + mCompares.Add(xSize + "_REG " + xComparison + " _REGADDR[1]"); + mCompares.Add(xSize + "_REG " + xComparison + " _REGADDR[-1]"); + mCompares.Add(xSize + "_REG " + xComparison + " _ABC"); + mCompares.Add(xSize + "_REG " + xComparison + " #_ABC"); + // + mCompares.Add(xSize + "_REGADDR[1] " + xComparison + " 123"); + mCompares.Add(xSize + "_REGADDR[-1] " + xComparison + " 123"); + mCompares.Add(xSize + "_REGADDR[1] " + xComparison + " _REG"); + mCompares.Add(xSize + "_REGADDR[-1] " + xComparison + " _REG"); + mCompares.Add(xSize + "_REGADDR[1] " + xComparison + " #_ABC"); + mCompares.Add(xSize + "_REGADDR[-1] " + xComparison + " #_ABC"); + // + mCompares.Add(xSize + "_ABC " + xComparison + " 123"); + mCompares.Add(xSize + "_ABC " + xComparison + " _REG"); + mCompares.Add(xSize + "_ABC " + xComparison + " #_ABC"); + } + } + } + + AddPatterns(); + } + + /// Builds a label that is suitable to denote a constant which name is given by the + /// token. + /// + /// + protected string ConstLabel(Token aToken) { + return GroupLabel("Const_" + aToken); + } + + /// Builds a label at namespace level having the given name. + /// Local label name at namespace level. + /// The label name + protected string GroupLabel(string aLabel) { + return GetNamespace() + "_" + aLabel; + } + + /// Builds a label at function level having the given name. + /// Local label name at function level. + /// The label name + protected string FuncLabel(string aLabel) { + return GetNamespace() + "_" + mFuncName + "_" + aLabel; + } + + /// Builds a label having the given name at current function block level. + /// Local label name at function block level. + /// The label name. + protected string BlockLabel(string aLabel) { + return FuncLabel("Block" + mBlocks.Current().LabelID + "_" + aLabel); + } + + /// Build a label name for the given token. This method enforce the rule for . + /// and .. prefixes and build the label at appropriate level. + /// + /// + protected string GetLabel(Token aToken) { + if ((aToken.Type != TokenType.AlphaNum) && !aToken.Matches("exit")) { + throw new Exception("Label must be AlphaNum."); + } + + string xValue = aToken.RawValue; + if (!InFunctionBody) { + if (xValue.StartsWith(".")) { + return xValue.Substring(1); + } + return GroupLabel(xValue); + } else { + if (xValue.StartsWith("..")) { + return xValue.Substring(2); + } else if (xValue.StartsWith(".")) { + return GroupLabel(xValue.Substring(1)); + } + return FuncLabel(xValue); + } + } + + /// Get a flag that tell if we are in a function body or not. This is used by the + /// assembler generator when end of source file is reached to make sure the last function + /// or interrupt handler is properly closed (see issue #15666) + internal bool InFunctionBody { + get { return !string.IsNullOrEmpty(mFuncName); } + } + + /// Start a new function having the given name. The current blocks collection is + /// reset to an empty state and the function name is saved for later reuse in local to function + /// labels' name construction. + /// Function name. + protected void StartFunc(string aName) { + if (InFunctionBody) { + throw new Exception( + "Found a function/interrupt handler definition embedded inside another function/interrupt handler."); + } + mFuncName = aName; + mFuncExitFound = false; + mBlocks.Reset(); + } + + /// Terminate assembling current function. If a local to function exit label has not + /// been explicitly defined a new one is automatically created. This is because some "return" + /// keyword might have been used in function X# code. This keyword requires an exit label to + /// be defined at function level. This method also automatically insert an IRET or RET instruction + /// depending on whether the function is an interrupt handler or a standard function. + protected void EndFunc() { + if (null == mFuncName) { + throw new Exception("Found a closing curly brace that doesn't match an opening curly brace."); + } + if (!mFuncExitFound) { + XS.Label(GetNamespace() + "_" + mFuncName + "_Exit"); + } + if (mInIntHandler) { + XS.InterruptReturn(); + } else { + // TODO: this shouldn't be here + XS.Set("INTs_LastKnownAddress", GetNamespace() + "_" + mFuncName + "_Exit", destinationIsIndirect: true, size: XSRegisters.RegisterSize.Long64); + XS.Return(); + } + mFuncName = null; + } + + protected string GetSimpleRef(Token aToken) { + return GetLabel(aToken); + } + + private static XSRegisters.RegisterSize GetSize(Token aToken) { + return GetSize(aToken.RawValue); + } + + private static XSRegisters.RegisterSize GetSize(string value) { + switch (value) { + case "byte": + return XSRegisters.RegisterSize.Byte8; + case "word": + return XSRegisters.RegisterSize.Short16; + case "dword": + return XSRegisters.RegisterSize.Int32; + default: + throw new Exception($"Invalid size '{value}'"); + } + } + + private static string GetSizeString(XSRegisters.RegisterSize size) { + switch (size) { + case XSRegisters.RegisterSize.Byte8: + return "byte"; + case XSRegisters.RegisterSize.Short16: + return "word"; + case XSRegisters.RegisterSize.Int32: + return "dword"; + default: + throw new ArgumentOutOfRangeException(nameof(size), size, null); + } + } + + protected string GetRef(List aTokens, ref int rIdx, bool onlySingleTokenRefs = false) { + var xToken1 = aTokens[rIdx]; + Token xToken2 = null; + if (rIdx + 1 < aTokens.Count + && !onlySingleTokenRefs) { + xToken2 = aTokens[rIdx + 1]; + } + if (xToken1.Type == TokenType.Register) { + if (xToken2 != null + && xToken2.RawValue == "[") { + if (aTokens[rIdx + 2].RawValue == "-") { + rIdx += 5; + return "[" + xToken1 + " - " + aTokens[rIdx - 2] + "]"; + } + rIdx += 4; + return "[" + xToken1 + " + " + aTokens[rIdx - 2] + "]"; + } + rIdx += 1; + return xToken1.RawValue; + } else if (xToken1.Type == TokenType.AlphaNum) { + rIdx += 1; + return "[" + GetLabel(xToken1) + "]"; + } else if (xToken1.Type == TokenType.ValueInt) { + rIdx += 1; + return xToken1.RawValue; + } else if (xToken1.Type == TokenType.Call) { + rIdx += 1; + return "@ret_on_stack@"; + } else if (xToken1.RawValue == "#") { + rIdx += 2; + return ConstLabel(xToken2); + } else { + throw new Exception("Cannot determine reference"); + } + } + + protected ConditionalTestEnum GetJump(string aComparison, bool aInvert = false) { + if (aInvert) { + if (aComparison == "<") { + aComparison = ">="; + } else if (aComparison == ">") { + aComparison = "<="; + } else if (aComparison == "=") { + aComparison = "!="; + } else if (aComparison == "0") { + // Same as JE, but implies intent in .asm better + aComparison = "!0"; + } else if (aComparison == "!0") { + // Same as JE, but implies intent in .asm better + aComparison = "0"; + } else if (aComparison == "!=") { + aComparison = "="; + } else if (aComparison == "<=") { + aComparison = ">"; + } else if (aComparison == ">=") { + aComparison = "<"; + } else { + throw new Exception("Unrecognized symbol in conditional: " + aComparison); + } + } + + if (aComparison == "<") { + return ConditionalTestEnum.Below; // unsigned + } else if (aComparison == ">") { + return ConditionalTestEnum.Above; // unsigned + } else if (aComparison == "=") { + return ConditionalTestEnum.Equal; + } else if (aComparison == "0") { + // Same as JE, but implies intent in .asm better + return ConditionalTestEnum.Zero; + } else if (aComparison == "!=") { + return ConditionalTestEnum.NotEqual; + } else if (aComparison == "!0") { + // Same as JNE, but implies intent in .asm better + return ConditionalTestEnum.NotZero; + } else if (aComparison == "<=") { + return ConditionalTestEnum.BelowOrEqual; // unsigned + } else if (aComparison == ">=") { + return ConditionalTestEnum.AboveOrEqual; // unsigned + } else { + throw new Exception("Unrecognized symbol in conditional: " + aComparison); + } + } + + protected void HandleIf(TokenList aTokens, string xComparison) { + string xLabel; + var xLast = aTokens.Last(); + if (xLast.RawValue == "{") { + mBlocks.Start(aTokens, false); + XS.Jump(GetJump(xComparison, true), BlockLabel("End")); + } else { + if (xLast.Matches("return")) { + xLabel = FuncLabel("Exit"); + } else { + xLabel = GetLabel(xLast); + } + + XS.Jump(GetJump(xComparison), xLabel); + } + } + + protected void AddPatterns() { + AddPattern("! Mov EAX, 0", delegate (TokenList aTokens) { + XS.LiteralCode(aTokens[0].RawValue); + }); + + AddPattern("// Comment", delegate (TokenList aTokens) { + if (EmitUserComments) { + string xValue = aTokens[0].RawValue; + xValue = xValue.Replace("\"", "\\\""); + XS.Comment(xValue); + } + }); + + // The value function returns a token containing the comparison + var xCompares = new Dictionary>(); + var xSizes = new[] + { + "", "byte", "word", "dword" + }; + #region Handle all comparisons + foreach (var xSize in xSizes) { + foreach (var xComparison in mCompareOps) { + var xComparisonToken = new Token(); + xComparisonToken.RawValue = xComparison; + // Skip 0 and !0 + if (!xComparison.Contains("0")) { + xCompares.Add(xSize + " _REG " + xComparison + " 123", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].IntValue, size: xTypedSize); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REG " + xComparison + " _REG", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REG " + xComparison + " _REGADDR[1]", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, sourceDisplacement: (int)tokenList[xOffset + 3].IntValue); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REG " + xComparison + " _REGADDR[-1]", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, sourceDisplacement: -(int)tokenList[xOffset + 3].IntValue); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REG " + xComparison + " _ABC", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, GetLabel(tokenList[xOffset + 2]), sourceIsIndirect: true); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REG " + xComparison + " #_ABC", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, ConstLabel(tokenList[xOffset + 3])); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REGADDR[1] " + xComparison + " 123", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 5].IntValue, destinationDisplacement: (int)tokenList[xOffset + 2].IntValue, size: xTypedSize); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REGADDR[-1] " + xComparison + " 123", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].IntValue, destinationDisplacement: -(int)tokenList[xOffset + 1].IntValue, size: xTypedSize); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REGADDR[1] " + xComparison + " _REG", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, destinationDisplacement: (int)tokenList[xOffset + 1].IntValue); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REGADDR[-1] " + xComparison + " _REG", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, tokenList[xOffset + 2].Register, destinationDisplacement: -(int)tokenList[xOffset + 1].IntValue); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REGADDR[1] " + xComparison + " #_ABC", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, ConstLabel(tokenList[xOffset + 2]), destinationDisplacement: (int)tokenList[xOffset + 1].IntValue, sourceIsIndirect: true, size: xTypedSize); + return xComparisonToken; + }); + xCompares.Add(xSize + " _REGADDR[-1] " + xComparison + " #_ABC", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(tokenList[xOffset + 0].Register, ConstLabel(tokenList[xOffset + 2]), destinationDisplacement: (int)tokenList[xOffset + 1].IntValue, size: xTypedSize); + return xComparisonToken; + }); + xCompares.Add(xSize + " _ABC " + xComparison + " 123", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(GetLabel(tokenList[xOffset + 0]), tokenList[xOffset + 2].IntValue, destinationIsIndirect: true, size: xTypedSize.GetValueOrDefault(XSRegisters.RegisterSize.Int32)); + return xComparisonToken; + }); + xCompares.Add(xSize + " _ABC " + xComparison + " _REG", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + if (tokenList[xOffset + 2].Type != TokenType.Register) { + xOffset += 1; + } + XS.Compare(GetSimpleRef(tokenList[xOffset + 0]), tokenList[xOffset + 2].Register, destinationIsIndirect: true); + return xComparisonToken; + }); + xCompares.Add(xSize + " _ABC " + xComparison + " #_ABC", + (tokenOffset, tokenList) => { + var xOffset = tokenOffset; + XSRegisters.RegisterSize? xTypedSize = null; + if (tokenList[xOffset].Type != TokenType.Register) { + xTypedSize = GetSize(tokenList[xOffset]); + xOffset += 1; + } + XS.Compare(GetSimpleRef(tokenList[xOffset + 0]), ConstLabel(tokenList[xOffset + 3]), destinationIsIndirect: true, size: xTypedSize.GetValueOrDefault(XSRegisters.RegisterSize.Int32)); + return xComparisonToken; + }); + } + } + } + #endregion Handle all comparisons + // Labels + // Local and proc level are used most, so designed to make their syntax shortest. + // Think of the dots like a directory, . is current group, .. is above that. + // ..Name: - Global level. Emitted exactly as is. + // .Name: - Group level. Group_Name + // Name: - Function level. Group_ProcName_Name + + // The Exit label is a special one that is used as a target for the return instruction. + // It deserve special handling. + AddPattern("Exit:", delegate (TokenList aTokens) { + XS.Label(GetLabel(aTokens[0])); + mFuncExitFound = true; + }); + + // Regular label recognition. + AddPattern("_ABC:", delegate (TokenList aTokens) { + XS.Label(GetLabel(aTokens[0])); + }); + + AddPattern("Call _ABC", delegate (TokenList aTokens) { + XS.Call(GetLabel(aTokens[1])); + }); + AddPattern("_PCALL", delegate (TokenList aTokens) { + if (aTokens.Count != 1 + || aTokens[0].Type != TokenType.Call) { + throw new Exception("Error occured in parametrized call parsing"); + } else { + List mparts = aTokens[0].RawValue.Remove(aTokens[0].RawValue.Length - 1).Split('(').ToList(); + if (mparts.Count < 2) { + throw new Exception("Error occured in parametrized call parsing"); + } + string fname = mparts[0]; + mparts.RemoveAt(0); + aTokens[0].RawValue = String.Join("(", mparts).Trim(); + string val = ""; + int idx; + + var xParams = new List(); + int level = 0; + foreach (char c in aTokens[0].RawValue) { + switch (c) { + case ',': + if (level == 0) { + xParams.Add(val.Trim()); + val = ""; + } + break; + case '(': + level++; + val += c; + break; + case ')': + level--; + val += c; + break; + default: + val += c; + break; + } + } + if (!String.IsNullOrEmpty(val.Trim())) { + xParams.Add(val); + } + if (level != 0) { + throw new Exception("'(' occured without closing equivalent ')' in parametrized function call"); + } + + Parser xParser; + xParams.Reverse(); + foreach (string p in xParams) { + xParser = new Parser(p, false, false); + idx = 0; + val = GetRef(xParser.Tokens, ref idx); + if (val != "@ret_on_stack@") { + //XS.PushLiteral(val); + throw new Exception(); + } else { + //aAsm += GetPatternCode(xParser.Tokens).GetCode(false); + throw new NotImplementedException("Didn't get converted yet!"); + } + } + XS.Call(GroupLabel(fname)); + } + }); + + AddPattern("Goto _ABC", delegate (TokenList aTokens) { + XS.Jump(GetLabel(aTokens[1])); + }); + + // Defines a constant having the given name and initial value. + AddPattern("const _ABC = 123", delegate (TokenList aTokens) { + XS.Const(ConstLabel(aTokens[1]), aTokens[3].IntValue.ToString()); + }); + + // Declare a double word variable having the given name and initialized to 0. The + // variable is declared at namespace level. + AddPattern("var _ABC", delegate (TokenList aTokens) { + XS.DataMember(GetLabel(aTokens[1])); + }); + + // Declare a doubleword variable having the given name and an explicit initial value. The + // variable is declared at namespace level. + AddPattern("var _ABC = 123", delegate (TokenList aTokens) { + XS.DataMember(GetLabel(aTokens[1]), aTokens[3].IntValue); + }); + + // Declare a textual variable having the given name and value. The variable is defined at + // namespace level and a null terminating byte is automatically added after the textual + // value. + AddPattern("var _ABC = 'Text'", delegate (TokenList aTokens) { + // Fix issue #15660 by using backquotes for string surrounding and escaping embedded + // back quotes. + XS.DataMember(GetLabel(aTokens[1]), EscapeBackQuotes(aTokens[3].RawValue)); + }); + + // Declare a one-dimension array of bytes, words or doublewords. All members are initialized to 0. + // _ABC is array name. 123 is the total number of items in the array. + AddPattern(new string[] + { + "var _ABC byte[123]", "var _ABC word[123]", "var _ABC dword[123]" + }, delegate (TokenList aTokens) { + string xSize; + if (aTokens[2].Matches("byte")) { + xSize = "db"; + } else if (aTokens[2].Matches("word")) { + xSize = "dw"; + } else if (aTokens[2].Matches("dword")) { + xSize = "dd"; + } else { + throw new Exception("Unknown size specified"); + } + XS.DataMember(GetLabel(aTokens[1]), aTokens[4].IntValue, xSize, "0"); + }); + + foreach (var xCompare in xCompares) { + // 0 1 2 3 4 + AddPattern("while " + xCompare.Key + " {", delegate (TokenList aTokens) { + mBlocks.Start(aTokens, false); + XS.Label(BlockLabel("Begin")); + + Token xComparison = xCompare.Value(1, aTokens); + + XS.Jump(GetJump(xComparison.RawValue, true), BlockLabel("End")); + }); + } + + foreach (var xTail in "goto _ABC|return|{".Split('|')) { + // if 0 exit, etc + foreach (var xComparison in mCompareOps) { + AddPattern("if " + xComparison + " " + xTail, delegate (TokenList aTokens) { + string xOp = aTokens[1].RawValue; + + // !0 is 2 tokens + if (aTokens[1].RawValue + aTokens[2].RawValue == "!0") { + xOp = "!0"; + } + + HandleIf(aTokens, xOp); + }); + } + + // if reg = x exit, etc + foreach (var xCompare in xCompares) { + // 0 1 2 3 4 + AddPattern("if " + xCompare.Key + " " + xTail, + delegate (TokenList aTokens) { + Token xComparison = xCompare.Value(1, aTokens); + + HandleIf(aTokens, xComparison.RawValue); + }); + } + } + + AddPattern("_REG ?= 123", delegate (TokenList aTokens) { + XS.Compare(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern("_REG ?= _ABC", delegate (TokenList aTokens) { + XS.Compare(aTokens[0].Register, GetSimpleRef(aTokens[2]), sourceIsIndirect: true); + }); + AddPattern("_REG ?= #_ABC", delegate (TokenList aTokens) { + XS.Compare(aTokens[0].Register, ConstLabel(aTokens[2])); + }); + + AddPattern("_REG ?& 123", delegate (TokenList aTokens) { + XS.Test(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern("_REG ?& _ABC", delegate (TokenList aTokens) { + XS.Test(aTokens[0].Register, GetLabel(aTokens[2]), sourceIsIndirect: true); + }); + AddPattern("_REG ?& #_ABC", delegate (TokenList aTokens) { + XS.Test(aTokens[0].Register, GetLabel(aTokens[2]), sourceIsIndirect: true); + }); + + AddPattern("_REG ~> 123", delegate (TokenList aTokens) { + XS.RotateRight(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern("_REG <~ 123", delegate (TokenList aTokens) { + XS.RotateLeft(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern("_REG >> 123", delegate (TokenList aTokens) { + if (aTokens[2].IntValue > 255) { + throw new IndexOutOfRangeException("Value is too large to be used as bitcount!"); + } + XS.ShiftRight(aTokens[0].Register, (byte)aTokens[2].IntValue); + }); + AddPattern("_REG << 123", delegate (TokenList aTokens) { + if (aTokens[2].IntValue > 255) { + throw new IndexOutOfRangeException("Value is too large to be used as bitcount!"); + } + XS.ShiftLeft(aTokens[0].Register, (byte)aTokens[2].IntValue); + }); + + AddPattern("_REG = 123", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern("_REGADDR[1] = 123", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[5].IntValue, destinationDisplacement: (int)aTokens[2].IntValue, size: XSRegisters.RegisterSize.Int32); + }); + AddPattern("_REGADDR[-1] = 123", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[5].IntValue, destinationDisplacement: -(int)aTokens[2].IntValue, size: XSRegisters.RegisterSize.Int32); + }); + + AddPattern("_REG = #_ABC", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, ConstLabel(aTokens[3])); + }); + AddPattern("_REGADDR[1] = #_ABC", delegate (TokenList aTokens) { + //XS.Set(RegisterSize.Int32, aTokens[0].IntValue, aTokens[2].IntValue, ConstLabel(aTokens[5])); + throw new NotImplementedException(""); + }); + AddPattern("_REGADDR[-1] = #_ABC", delegate (TokenList aTokens) { + var xFirst = GetSimpleRef(aTokens[0]); + var xSecond = GetSimpleRef(aTokens[2]); + + //XS.SetLiteral("dword [" + xFirst + " - " + xSecond + "]", ConstLabel(aTokens[5])); + throw new NotImplementedException(""); + }); + + AddPattern("_REG = _REG", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[2].Register); + }); + AddPattern("_REGADDR[1] = _REG", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[5].Register, destinationDisplacement: (int)aTokens[2].IntValue); + }); + AddPattern("_REGADDR[-1] = _REG", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[5].Register, destinationDisplacement: -(int)aTokens[2].IntValue); + }); + AddPattern("_REG = _REGADDR[1]", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[2].Register, sourceDisplacement: (int)aTokens[4].IntValue); + }); + AddPattern("_REG = _REGADDR[-1]", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[2].Register, sourceDisplacement: -(int)aTokens[4].IntValue); + }); + + AddPattern("_REG = [_REG]", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[3].Register, sourceIsIndirect: true); + }); + AddPattern("_REG = [_REG + 1]", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[3].Register, sourceDisplacement: (int?)aTokens[5].IntValue); + }); + AddPattern("_REG = [_REG - 1]", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[3].Register, sourceDisplacement: -(int)aTokens[5].IntValue); + }); + AddPattern("[_REG] = _REG", delegate (TokenList aTokens) { + XS.Set(aTokens[1].Register, aTokens[4].Register, destinationIsIndirect: true); + }); + AddPattern("[_REG + 1] = _REG", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[3].Register, destinationDisplacement: (int)aTokens[5].IntValue); + }); + AddPattern("[_REG - 1] = _REG", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, aTokens[3].Register, destinationDisplacement: -(int)aTokens[5].IntValue); + }); + + AddPattern("_REG = _ABC", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, GetLabel(aTokens[2]), sourceIsIndirect: true); + }); + + // why not [var] like registers? Because its less frequent to access the ptr + // and it is like a reg.. without [] to get the value... + AddPattern("_REG = @_ABC", delegate (TokenList aTokens) { + XS.Set(aTokens[0].Register, GetLabel(aTokens[3])); + }); + + AddPattern(new string[] + { + "Port[DX] = AL", "Port[DX] = AX", "Port[DX] = EAX" + }, delegate (TokenList aTokens) { + XS.WriteToPortDX(aTokens[5].Register); + }); + AddPattern(new string[] + { + "AL = Port[DX]", "AX = Port[DX]", "EAX = Port[DX]" + }, delegate (TokenList aTokens) { + XS.ReadFromPortDX(aTokens[0].Register); + }); + + AddPattern("+123", delegate (TokenList aTokens) { + XS.Push(aTokens[0].IntValue, size: XSRegisters.RegisterSize.Int32); + }); + AddPattern(new string[] + { + "+123 as byte", "+123 as word", "+123 as dword" + }, delegate (TokenList aTokens) { + var xSize = GetSize(aTokens[1]); + XS.Push(aTokens[1].IntValue, size: xSize); + }); + AddPattern("+_REG", delegate (TokenList aTokens) { + XS.Push(aTokens[1].Register); + }); + AddPattern(new string[] + { + //0 1 2 3 + "+#_ABC", "+#_ABC as byte", "+#_ABC as word", "+#_ABC as dword" + }, delegate (TokenList aTokens) { + XSRegisters.RegisterSize xSize = XSRegisters.RegisterSize.Int32; + if (aTokens.Count > 2) { + xSize = GetSize(aTokens[3]); + } + XS.Push(ConstLabel(aTokens[1]), size: xSize); + }); + AddPattern("+All", delegate (TokenList aTokens) { + XS.PushAllRegisters(); + }); + AddPattern("-All", delegate (TokenList aTokens) { + XS.PopAllRegisters(); + }); + AddPattern("-_REG", delegate (TokenList aTokens) { + XS.Pop(aTokens[1].Register); + }); + + AddPattern("_ABC = _REG", delegate (TokenList aTokens) { + XS.Set(GetLabel(aTokens[0]), aTokens[2].Register, destinationIsIndirect: true); + }); + AddPattern("_ABC = #_ABC", delegate (TokenList aTokens) { + XS.Set(GetLabel(aTokens[0]), ConstLabel(aTokens[3]), destinationIsIndirect: true, size: XSRegisters.RegisterSize.Int32); + }); + AddPattern("_ABC = 123", delegate (TokenList aTokens) { + XS.Set(GetLabel(aTokens[0]), aTokens[2].IntValue, destinationIsIndirect: true); + }); + AddPattern(new string[] + { + "_ABC = 123 as byte", "_ABC = 123 as word", "_ABC = 123 as dword" + }, delegate (TokenList aTokens) { + XS.Set(GetLabel(aTokens[0]), aTokens[2].IntValue, size: GetSize(aTokens[4])); + }); + + AddPattern(new string[] + { + "_REG + 1", + }, delegate (TokenList aTokens) { + XS.Add(aTokens[0].Register, aTokens[2].IntValue); + }); + + AddPattern(new string[] + { + "_REG + _REG" + }, delegate (TokenList aTokens) { + XS.Add(aTokens[0].Register, aTokens[2].Register); + }); + AddPattern(new string[] + { + "_REG - 1", + }, delegate (TokenList aTokens) { + XS.Sub(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern(new string[] + { + "_REG - _REG" + }, delegate (TokenList aTokens) { + XS.Sub(aTokens[0].Register, aTokens[2].Register); + }); + AddPattern(new string[] + { + "_REG * 1", + }, delegate (TokenList aTokens) { + XS.IntegerMultiply(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern(new string[] + { + "_REG * _REG" + }, delegate (TokenList aTokens) { + XS.IntegerMultiply(aTokens[0].Register, aTokens[2].Register); + }); + AddPattern("_REG++", delegate (TokenList aTokens) { + XS.Increment(aTokens[0].Register); + }); + AddPattern("_REG--", delegate (TokenList aTokens) { + XS.Decrement(aTokens[0].Register); + }); + + AddPattern(new string[] + { + "_REG & 1", + }, delegate (TokenList aTokens) { + XS.And(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern(new string[] + { + "_REG & _REG" + }, delegate (TokenList aTokens) { + XS.And(aTokens[0].Register, aTokens[2].Register); + }); + AddPattern(new string[] + { + "_REG | 1", + }, delegate (TokenList aTokens) { + XS.Or(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern(new string[] + { + "_REG | _REG" + }, delegate (TokenList aTokens) { + XS.Or(aTokens[0].Register, aTokens[2].Register); + }); + AddPattern(new string[] + { + "_REG ^ 1", + }, delegate (TokenList aTokens) { + XS.Xor(aTokens[0].Register, aTokens[2].IntValue); + }); + AddPattern(new string[] + { + "_REG ^ _REG" + }, delegate (TokenList aTokens) { + XS.Xor(aTokens[0].Register, aTokens[2].Register); + }); + + // End block. This handle both terminating a standard block as well as a function or an + // interrupt handler. + AddPattern("}", delegate (TokenList aTokens) { + if (mBlocks.Count == 0) { + EndFunc(); + } else { + var xBlock = mBlocks.Current(); + var xToken1 = xBlock.StartTokens[0]; + if (xToken1.Matches("repeat")) { + var xCount = xBlock.StartTokens[1].IntValue; + for (var i = 1; i <= xCount; i++) { + xBlock.AddContentsToParentAssembler(); + } + } else if (xToken1.Matches("while")) { + XS.Jump(BlockLabel("Begin")); + XS.Label(BlockLabel("End")); + xBlock.AddContentsToParentAssembler(); + } else if (xToken1.Matches("if")) { + XS.Label(BlockLabel("End")); + xBlock.AddContentsToParentAssembler(); + } else { + throw new Exception("Unknown block starter."); + } + mBlocks.End(); + } + }); + + AddPattern("namespace _ABC", delegate (TokenList aTokens) { + mNamespace = aTokens[1].RawValue; + }); + + AddPattern("Return", delegate { + XS.Jump(FuncLabel("Exit")); + }); + + AddPattern("Repeat 4 times {", delegate (TokenList aTokens) { + mBlocks.Start(aTokens, true); + }); + + AddPattern("Interrupt _ABC {", delegate (TokenList aTokens) { + StartFunc(aTokens[1].RawValue); + mInIntHandler = true; + XS.Label(GetNamespace() + "_" + aTokens[1].RawValue); + }); + + // This needs to be different from return. + // return jumps to exit, ret does raw x86 ret + AddPattern("Ret", delegate (TokenList aTokens) { + XS.Return(); + }); + AddPattern("IRet", delegate (TokenList aTokens) { + XS.InterruptReturn(); + }); + + AddPattern("Function _ABC {", delegate (TokenList aTokens) { + StartFunc(aTokens[1].RawValue); + mInIntHandler = false; + XS.Label(GetNamespace() + "_" + aTokens[1].RawValue); + }); + + AddPattern("Checkpoint 'Text'", delegate (TokenList aTokens) { + // This method emits a lot of ASM, but thats what we want becuase + // at this point we need ASM as simple as possible and completely transparent. + // No stack changes, no register mods, no calls, no jumps, etc. + + // TODO: Add an option on the debug project properties to turn this off. + // Also see WriteDebugVideo in CosmosAssembler.cs + var xPreBootLogging = true; + if (xPreBootLogging) { + UInt32 xVideo = 0xB8000; + for (UInt32 i = xVideo; i < xVideo + 80 * 2; i = i + 2) { + XS.SetByte(i, 0); + XS.SetByte(i + 1, 2); + } + + foreach (var xChar in aTokens[1].RawValue) { + XS.SetByte(xVideo, (byte)xChar); + xVideo = xVideo + 2; + } + } + }); + } + + /// Fix issue #15660. This method escapes double quotes in the candidate string. + /// The string to be sanitized. + /// The original string with escaped double quotes. + private static string EscapeBackQuotes(string from) { + StringBuilder builder = new StringBuilder(); + bool sanitized = false; + bool escaped = false; + foreach (char scannedCharacter in from) { + switch (scannedCharacter) { + case '\\': + escaped = !escaped; + break; + case '`': + if (!escaped) { + sanitized = true; + builder.Append('\\'); + } + escaped = false; + break; + default: + escaped = false; + break; + } + builder.Append(scannedCharacter); + } + return (sanitized) ? builder.ToString() : from; + } + + protected Pattern FindMatch(TokenList aTokens) { + int xHash = aTokens.GetPatternHashCode(); + + // Get a list of matching hashes, but then we have to + // search for exact pattern match because it is possible + // to have duplicate hashes. Hashes just provide us a quick way + // to reduce the search. + foreach (var xPattern in mPatterns.Where(q => q.Hash == xHash)) { + if (xPattern.Tokens.PatternMatches(aTokens)) { + return xPattern; + } + } + return null; + } + + public bool GetPatternCode(TokenList aTokens) { + var xPattern = FindMatch(aTokens); + if (xPattern == null) { + return false; + } + + xPattern.Code(aTokens); + + //// Apply {0} etc into string + //// This happens twice for block code, but its ok because the first pass + //// strips out all tags. + //for (int i = 0; i < xResult.Code.Count; i++) { + // xResult.Code[i] = string.Format(xResult.Code[i], aTokens.ToArray()); + //} + return true; + } + + public void Assemble(string aLine) { + var xParser = new Parser(aLine, false, false); + var xTokens = xParser.Tokens; + + if (GetPatternCode(xTokens) == false) { + if (xTokens.Count == 0) { + throw new Exception("Parsing error: " + aLine); + } + + var xFirst = xTokens[0]; + var xLast = xTokens[xTokens.Count - 1]; + + // Find match and emit X# + if (xTokens.Count == 2 + && xFirst.Type == TokenType.AlphaNum + && xLast.Matches("()")) { + // () could be handled by pattern, but best to keep in one place for future + //xResult += "Call " + GroupLabel(aTokens[0].Value); + XS.Call(GroupLabel(xTokens[0].RawValue)); + } + } + } + + /// Register a single pattern with its associated transformation handler. + /// A single line of X# code that define the pattern optionally using + /// pattern reserved syntax. + /// The associated code transformation handler. + protected void AddPattern(string aPattern, CodeFunc aCode) { + Parser xParser = null; + try { + xParser = new Parser(aPattern, false, true); + } catch (Exception e) { + throw new Exception(string.Format("Invalid pattern '{0}'", aPattern ?? "NULL"), e); + } + var xPattern = new Pattern(xParser.Tokens, aCode, aPattern); + mPatterns.Add(xPattern); + } + + /// Register a collection of patterns that share a single transformation handler. + /// + /// A collection of X# lines of code. Each line of code define a + /// pattern optionally using the pattern reserved syntax. + /// The code transformation handler that is common abmongst all the + /// patterns from the collection. + protected void AddPattern(string[] aPatterns, CodeFunc aCode) { + foreach (var xPattern in aPatterns) { + AddPattern(xPattern, aCode); + } + } + } +} diff --git a/source/XSharp/XSharp/Gen1/XS.FPU.cs b/source/XSharp/XSharp/Gen1/XS.FPU.cs index b00c3f2a..74a64ce4 100644 --- a/source/XSharp/XSharp/Gen1/XS.FPU.cs +++ b/source/XSharp/XSharp/Gen1/XS.FPU.cs @@ -1,163 +1,163 @@ -using System; -using XSharp.Assembler.x86.x87; - -namespace XSharp -{ - public partial class XS - { - public static class FPU - { - public static void FloatCompareAndSet(XSRegisters.RegisterFPU register) - { - new FloatCompareAndSet - { - DestinationReg = register.RegEnum - }; - } - - public static void FloatStoreAndPop(XSRegisters.Register32 register, bool isIndirect = false, int? displacement = null, XSRegisters.RegisterSize? size = null) - { - if (displacement != null) - { - isIndirect = true; - if (displacement == 0) - { - displacement = null; - } - } - - if (size == null) - { - if (isIndirect) - { - throw new InvalidOperationException("No size specified!"); - } - size = register.Size; - } - - new FloatStoreAndPop - { - DestinationReg = register.RegEnum, - DestinationIsIndirect = isIndirect, - DestinationDisplacement = displacement, - Size = (byte)size - }; - } - - public static void FloatStoreAndPop(XSRegisters.RegisterFPU register) - { - new FloatStoreAndPop - { - DestinationReg = register.RegEnum - }; - } - - public static void FloatLoad(XSRegisters.Register32 register, bool destinationIsIndirect = false, int? displacement = null, XSRegisters.RegisterSize? size = null) - { - Do(register, isIndirect: destinationIsIndirect, displacement: displacement, size: size); - } - - public static void FloatAbs() - { - new FloatABS(); - } - - public static void FloatInit() - { - new FloatInit(); - } - - public static void FloatNegate() - { - new FloatNegate(); - } - - public static void FloatRound() - { - new FloatRound(); - } - - public static void FloatCosine() - { - new FloatCosine(); - } - - public static void FloatSine() - { - new FloatSine(); - } - - public static void FloatTan() - { - new FloatTan(); - } - - public static void FloatPop() - { - new FloatPop(); - } - - public static void FloatAdd(XSRegisters.Register32 destination, bool isIndirect = false, XSRegisters.RegisterSize? size = null) - { - if (size == null) - { - if (isIndirect) - { - throw new InvalidOperationException("No size specified!"); - } - size = destination.Size; - } - - new FloatAdd - { - DestinationReg = destination, - DestinationIsIndirect = isIndirect, - Size = (byte)size.Value - }; - } - - public static void IntLoad(XSRegisters.Register32 destination, bool isIndirect = false, int? displacement = null, XSRegisters.RegisterSize? size = null) - { - if (size == null) - { - if (isIndirect) - { - throw new InvalidOperationException("No size specified!"); - } - size = destination.Size; - } - - if (displacement != null) - { - isIndirect = true; - } - - new IntLoad - { - DestinationReg = destination, - DestinationIsIndirect = isIndirect, - Size = (byte)size.Value - }; - } - - public static void IntStoreWithTruncate(XSRegisters.Register32 destination, bool isIndirect = false, XSRegisters.RegisterSize? size = null) - { - if (size == null) - { - if (isIndirect) - { - throw new InvalidOperationException("No size specified!"); - } - size = destination.Size; - } - - new IntStoreWithTrunc - { - DestinationReg = destination, - DestinationIsIndirect = isIndirect, - Size = (byte)size.Value - }; - } - } - } -} +using System; +using XSharp.Assembler.x86.x87; + +namespace XSharp +{ + public partial class XS + { + public static class FPU + { + public static void FloatCompareAndSet(XSRegisters.RegisterFPU register) + { + new FloatCompareAndSet + { + DestinationReg = register.RegEnum + }; + } + + public static void FloatStoreAndPop(XSRegisters.Register64 register, bool isIndirect = false, int? displacement = null, XSRegisters.RegisterSize? size = null) + { + if (displacement != null) + { + isIndirect = true; + if (displacement == 0) + { + displacement = null; + } + } + + if (size == null) + { + if (isIndirect) + { + throw new InvalidOperationException("No size specified!"); + } + size = register.Size; + } + + new FloatStoreAndPop + { + DestinationReg = register.RegEnum, + DestinationIsIndirect = isIndirect, + DestinationDisplacement = displacement, + Size = (byte)size + }; + } + + public static void FloatStoreAndPop(XSRegisters.RegisterFPU register) + { + new FloatStoreAndPop + { + DestinationReg = register.RegEnum + }; + } + + public static void FloatLoad(XSRegisters.Register64 register, bool destinationIsIndirect = false, int? displacement = null, XSRegisters.RegisterSize? size = null) + { + Do(register, isIndirect: destinationIsIndirect, displacement: displacement, size: size); + } + + public static void FloatAbs() + { + new FloatABS(); + } + + public static void FloatInit() + { + new FloatInit(); + } + + public static void FloatNegate() + { + new FloatNegate(); + } + + public static void FloatRound() + { + new FloatRound(); + } + + public static void FloatCosine() + { + new FloatCosine(); + } + + public static void FloatSine() + { + new FloatSine(); + } + + public static void FloatTan() + { + new FloatTan(); + } + + public static void FloatPop() + { + new FloatPop(); + } + + public static void FloatAdd(XSRegisters.Register64 destination, bool isIndirect = false, XSRegisters.RegisterSize? size = null) + { + if (size == null) + { + if (isIndirect) + { + throw new InvalidOperationException("No size specified!"); + } + size = destination.Size; + } + + new FloatAdd + { + DestinationReg = destination, + DestinationIsIndirect = isIndirect, + Size = (byte)size.Value + }; + } + + public static void IntLoad(XSRegisters.Register64 destination, bool isIndirect = false, int? displacement = null, XSRegisters.RegisterSize? size = null) + { + if (size == null) + { + if (isIndirect) + { + throw new InvalidOperationException("No size specified!"); + } + size = destination.Size; + } + + if (displacement != null) + { + isIndirect = true; + } + + new IntLoad + { + DestinationReg = destination, + DestinationIsIndirect = isIndirect, + Size = (byte)size.Value + }; + } + + public static void IntStoreWithTruncate(XSRegisters.Register64 destination, bool isIndirect = false, XSRegisters.RegisterSize? size = null) + { + if (size == null) + { + if (isIndirect) + { + throw new InvalidOperationException("No size specified!"); + } + size = destination.Size; + } + + new IntStoreWithTrunc + { + DestinationReg = destination, + DestinationIsIndirect = isIndirect, + Size = (byte)size.Value + }; + } + } + } +} diff --git a/source/XSharp/XSharp/Gen1/XS.SSE.cs b/source/XSharp/XSharp/Gen1/XS.SSE.cs index 7a7e7bd3..99082bc8 100644 --- a/source/XSharp/XSharp/Gen1/XS.SSE.cs +++ b/source/XSharp/XSharp/Gen1/XS.SSE.cs @@ -1,197 +1,197 @@ -using System; - -using XSharp.Assembler.x86.SSE; -using XSharp.Assembler.x86.x87; - -namespace XSharp -{ - using static XSRegisters; - - partial class XS - { - public static class SSE - { - public static void SSEInit() - { - XS.Comment("BEGIN - SSE Init"); - - // CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 - - XS.Set(EAX, CR4); - XS.Or(EAX, 0x100); - XS.Set(CR4, EAX); - XS.Set(EAX, CR4); - XS.Or(EAX, 0x200); - XS.Set(CR4, EAX); - XS.Set(EAX, CR0); - XS.And(EAX, 0xfffffffd); - XS.Set(CR0, EAX); - XS.Set(EAX, CR0); - - XS.And(EAX, 1); - XS.Set(CR0, EAX); - XS.Comment("END - SSE Init"); - } - - public static void AddSS(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void MulSS(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void SubSS(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void XorPS(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void CompareSS(RegisterXMM destination, RegisterXMM source, ComparePseudoOpcodes comparision) - { - new CompareSS() - { - DestinationReg = destination, - SourceReg = source, - pseudoOpcode = (byte) comparision - }; - } - - public static void ConvertSI2SS(RegisterXMM destination, Register32 source, bool sourceIsIndirect = false) - { - new ConvertSI2SS() - { - DestinationReg = destination, - SourceReg = source, - SourceIsIndirect = sourceIsIndirect - }; - } - - public static void MoveSS(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void MoveSS(RegisterXMM destination, Register32 source, bool sourceIsIndirect = false) - { - new MoveSS() - { - DestinationReg = destination, - SourceReg = source, - SourceIsIndirect = sourceIsIndirect - }; - } - - public static void MoveSS(Register32 destination, RegisterXMM source, bool destinationIsIndirect = false) - { - new MoveSS() - { - DestinationReg = destination, - DestinationIsIndirect = destinationIsIndirect, - SourceReg = source - }; - } - - public static void MoveSS(RegisterXMM destination, String sourceLabel, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, sourceLabel, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveUPS(Register32 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveDQA(RegisterXMM destination, Register32 source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveDQA(Register32 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveDQU(RegisterXMM destination, Register32 source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveDQU(Register32 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveAPS(Register32 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void MoveAPS(RegisterXMM destination, Register32 source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void ConvertSS2SIAndTruncate(Register32 destination, RegisterXMM source) - { - new ConvertSS2SIAndTruncate - { - DestinationReg = destination, - SourceReg = source - }; - } - - public static void DivPS(RegisterXMM destination, RegisterXMM source) - { - new DivPS - { - DestinationReg = destination, - SourceReg = source - }; - } - - public static void DivSS(RegisterXMM destination, RegisterXMM source) - { - new DivSS - { - DestinationReg = destination, - SourceReg = source - }; - } - - public static void FXSave(Register32 destination, bool isIndirect) - { - new FXSave - { - DestinationReg = destination, - DestinationIsIndirect = isIndirect - }; - } - - public static void FXRestore(Register32 destination, bool isIndirect) - { - new FXStore() - { - DestinationReg = destination, - DestinationIsIndirect = isIndirect - }; - } - - public static void Shufps(RegisterXMM destination, RegisterXMM source, int bitmask) - { - new Shufps() - { - DestinationReg = destination, - SourceReg = source, - pseudoOpcode = (byte)bitmask - }; - } - } - } -} +using System; + +using XSharp.Assembler.x86.SSE; +using XSharp.Assembler.x86.x87; + +namespace XSharp +{ + using static XSRegisters; + + partial class XS + { + public static class SSE + { + public static void SSEInit() + { + XS.Comment("BEGIN - SSE Init"); + + // CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 + + XS.Set(RAX, CR4); + XS.Or(RAX, 0x100); + XS.Set(CR4, RAX); + XS.Set(RAX, CR4); + XS.Or(RAX, 0x200); + XS.Set(CR4, RAX); + XS.Set(RAX, CR0); + XS.And(RAX, 0xfffffffd); + XS.Set(CR0, RAX); + XS.Set(RAX, CR0); + + XS.And(RAX, 1); + XS.Set(CR0, RAX); + XS.Comment("END - SSE Init"); + } + + public static void AddSS(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void MulSS(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void SubSS(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void XorPS(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void CompareSS(RegisterXMM destination, RegisterXMM source, ComparePseudoOpcodes comparision) + { + new CompareSS() + { + DestinationReg = destination, + SourceReg = source, + pseudoOpcode = (byte) comparision + }; + } + + public static void ConvertSI2SS(RegisterXMM destination, Register64 source, bool sourceIsIndirect = false) + { + new ConvertSI2SS() + { + DestinationReg = destination, + SourceReg = source, + SourceIsIndirect = sourceIsIndirect + }; + } + + public static void MoveSS(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void MoveSS(RegisterXMM destination, Register64 source, bool sourceIsIndirect = false) + { + new MoveSS() + { + DestinationReg = destination, + SourceReg = source, + SourceIsIndirect = sourceIsIndirect + }; + } + + public static void MoveSS(Register64 destination, RegisterXMM source, bool destinationIsIndirect = false) + { + new MoveSS() + { + DestinationReg = destination, + DestinationIsIndirect = destinationIsIndirect, + SourceReg = source + }; + } + + public static void MoveSS(RegisterXMM destination, String sourceLabel, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, sourceLabel, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveUPS(Register64 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveDQA(RegisterXMM destination, Register64 source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveDQA(Register64 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveDQU(RegisterXMM destination, Register64 source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveDQU(Register64 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveAPS(Register64 destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void MoveAPS(RegisterXMM destination, Register64 source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void ConvertSS2SIAndTruncate(Register64 destination, RegisterXMM source) + { + new ConvertSS2SIAndTruncate + { + DestinationReg = destination, + SourceReg = source + }; + } + + public static void DivPS(RegisterXMM destination, RegisterXMM source) + { + new DivPS + { + DestinationReg = destination, + SourceReg = source + }; + } + + public static void DivSS(RegisterXMM destination, RegisterXMM source) + { + new DivSS + { + DestinationReg = destination, + SourceReg = source + }; + } + + public static void FXSave(Register64 destination, bool isIndirect) + { + new FXSave + { + DestinationReg = destination, + DestinationIsIndirect = isIndirect + }; + } + + public static void FXRestore(Register64 destination, bool isIndirect) + { + new FXStore() + { + DestinationReg = destination, + DestinationIsIndirect = isIndirect + }; + } + + public static void Shufps(RegisterXMM destination, RegisterXMM source, int bitmask) + { + new Shufps() + { + DestinationReg = destination, + SourceReg = source, + pseudoOpcode = (byte)bitmask + }; + } + } + } +} diff --git a/source/XSharp/XSharp/Gen1/XS.SSE2.cs b/source/XSharp/XSharp/Gen1/XS.SSE2.cs index 464e1f56..62877f5a 100644 --- a/source/XSharp/XSharp/Gen1/XS.SSE2.cs +++ b/source/XSharp/XSharp/Gen1/XS.SSE2.cs @@ -1,124 +1,124 @@ -using System; - -using XSharp.Assembler.x86.SSE; -using static XSharp.XSRegisters; - -namespace XSharp -{ - partial class XS - { - public static class SSE2 - { - public static void AddSD(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void DivSD(RegisterXMM destination, RegisterXMM source) - { - new DivSD - { - DestinationReg = destination, - SourceReg = source - }; - } - - public static void MulSD(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void SubSD(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void CompareSD(RegisterXMM destination, RegisterXMM source, ComparePseudoOpcodes comparision) - { - new CompareSD() - { - DestinationReg = destination, - SourceReg = source, - pseudoOpcode = (byte)comparision - }; - } - - public static void ConvertSD2SIAndTruncate(Register32 destination, RegisterXMM source) - { - new ConvertSD2SIAndTruncate - { - DestinationReg = destination, - SourceReg = source - }; - } - - public static void ConvertSS2SD(RegisterXMM destination, Register32 source, bool sourceIsIndirect = false) - { - new ConvertSS2SD() - { - DestinationReg = destination, - SourceReg = source, - SourceIsIndirect = sourceIsIndirect - }; - } - - public static void ConvertSD2SS(RegisterXMM destination, Register32 source, bool sourceIsIndirect = false) - { - new ConvertSD2SS() - { - DestinationReg = destination, - SourceReg = source, - SourceIsIndirect = sourceIsIndirect - }; - } - - public static void ConvertSI2SD(RegisterXMM destination, Register32 source, bool sourceIsIndirect = false, int? sourceDisplacement = null, bool destinationIsIndirect = false, int? destinationDisplacement = null) - { - new ConvertSI2SD() - { - DestinationReg = destination, - DestinationIsIndirect = destinationIsIndirect, - DestinationDisplacement = destinationDisplacement, - SourceReg = source, - SourceIsIndirect = sourceIsIndirect, - SourceDisplacement = sourceDisplacement - }; - } - - public static void MoveSD(RegisterXMM destination, RegisterXMM source) - { - DoDestinationSource(destination, source); - } - - public static void MoveSD(RegisterXMM destination, Register32 source, bool sourceIsIndirect = false) - { - new MoveSD() - { - DestinationReg = destination, - SourceReg = source, - SourceIsIndirect = sourceIsIndirect - }; - } - - public static void MoveSD(Register32 destination, RegisterXMM source, bool destinationIsIndirect = false) - { - new MoveSD() - { - DestinationReg = destination, - DestinationIsIndirect = destinationIsIndirect, - SourceReg = source - }; - } - - public static void XorPD(RegisterXMM destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - - public static void XorPD(RegisterXMM destination, String sourceLabel, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) - { - DoDestinationSource(destination, sourceLabel, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); - } - } - } -} +using System; + +using XSharp.Assembler.x86.SSE; +using static XSharp.XSRegisters; + +namespace XSharp +{ + partial class XS + { + public static class SSE2 + { + public static void AddSD(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void DivSD(RegisterXMM destination, RegisterXMM source) + { + new DivSD + { + DestinationReg = destination, + SourceReg = source + }; + } + + public static void MulSD(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void SubSD(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void CompareSD(RegisterXMM destination, RegisterXMM source, ComparePseudoOpcodes comparision) + { + new CompareSD() + { + DestinationReg = destination, + SourceReg = source, + pseudoOpcode = (byte)comparision + }; + } + + public static void ConvertSD2SIAndTruncate(Register64 destination, RegisterXMM source) + { + new ConvertSD2SIAndTruncate + { + DestinationReg = destination, + SourceReg = source + }; + } + + public static void ConvertSS2SD(RegisterXMM destination, Register64 source, bool sourceIsIndirect = false) + { + new ConvertSS2SD() + { + DestinationReg = destination, + SourceReg = source, + SourceIsIndirect = sourceIsIndirect + }; + } + + public static void ConvertSD2SS(RegisterXMM destination, Register64 source, bool sourceIsIndirect = false) + { + new ConvertSD2SS() + { + DestinationReg = destination, + SourceReg = source, + SourceIsIndirect = sourceIsIndirect + }; + } + + public static void ConvertSI2SD(RegisterXMM destination, Register64 source, bool sourceIsIndirect = false, int? sourceDisplacement = null, bool destinationIsIndirect = false, int? destinationDisplacement = null) + { + new ConvertSI2SD() + { + DestinationReg = destination, + DestinationIsIndirect = false, //must be indirect in long mode + DestinationDisplacement = destinationDisplacement, + SourceReg = source, + SourceIsIndirect = true, + SourceDisplacement = sourceDisplacement + }; + } + + public static void MoveSD(RegisterXMM destination, RegisterXMM source) + { + DoDestinationSource(destination, source); + } + + public static void MoveSD(RegisterXMM destination, Register64 source, bool sourceIsIndirect = false) + { + new MoveSD() + { + DestinationReg = destination, + SourceReg = source, + SourceIsIndirect = sourceIsIndirect + }; + } + + public static void MoveSD(Register64 destination, RegisterXMM source, bool destinationIsIndirect = false) + { + new MoveSD() + { + DestinationReg = destination, + DestinationIsIndirect = destinationIsIndirect, + SourceReg = source + }; + } + + public static void XorPD(RegisterXMM destination, RegisterXMM source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + + public static void XorPD(RegisterXMM destination, String sourceLabel, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null) + { + DoDestinationSource(destination, sourceLabel, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement); + } + } + } +} diff --git a/source/XSharp/XSharp/Gen1/XS.cs b/source/XSharp/XSharp/Gen1/XS.cs index 4df8ab7f..af0970b3 100644 --- a/source/XSharp/XSharp/Gen1/XS.cs +++ b/source/XSharp/XSharp/Gen1/XS.cs @@ -74,7 +74,7 @@ private static void Do(string destination, Register source, bool destinationI }; } - private static void Do(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + private static void Do(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) where T : InstructionWithDestinationAndSourceAndSize, new() { if (destinationDisplacement != null) @@ -110,7 +110,7 @@ private static void Do(string destination, UInt32 value, bool destinationIsIn }; } - private static void Do(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + private static void Do(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) where T : InstructionWithDestinationAndSourceAndSize, new() { if (destinationDisplacement != null) @@ -212,7 +212,7 @@ private static void Do(Register destination, uint value, bool destinationIsIn { if (destinationIsIndirect) { - size = RegisterSize.Int32; + size = RegisterSize.Long64; } else { @@ -287,7 +287,7 @@ private static void Do(Register destination, Register source, bool destinatio #region InstructionWithDestinationAndSize - private static void Do(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + private static void Do(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) where T : InstructionWithDestinationAndSize, new() { if (displacement != null) @@ -336,7 +336,7 @@ private static void Do(Register register, bool isIndirect = false, int? displ }; } - private static void Do(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + private static void Do(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) where T : InstructionWithDestinationAndSize, new() { if (displacement != null) @@ -578,12 +578,12 @@ public static void Set(string destination, Register source, bool destinationIsIn Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Set(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Set(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Set(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Set(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } @@ -617,12 +617,12 @@ public static void Lea(string destination, Register source, bool destinationIsIn Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Lea(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Lea(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Lea(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Lea(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } @@ -667,7 +667,7 @@ public static void Call(string target) new Call { DestinationLabel = target }; } - public static void Call(Register32 register) + public static void Call(Register64 register) { new Call { DestinationReg = register.RegEnum }; } @@ -741,7 +741,7 @@ public static void ShiftLeft(Register destination, byte bitCount) Do(destination, bitCount); } - public static void ShiftLeft(Register destination, Register8 bitCount, bool destinationIsIndirect = false, RegisterSize size = RegisterSize.Int32) + public static void ShiftLeft(Register destination, Register8 bitCount, bool destinationIsIndirect = false, RegisterSize size = RegisterSize.Long64) { if (bitCount != CL) { @@ -771,7 +771,7 @@ public static void ShiftLeftArithmetic(Register destination, byte bitCount) Do(destination, bitCount); } - public static void ShiftLeftArithmetic(Register destination, Register8 bitCount, bool destinationIsIndirect = false, RegisterSize size = RegisterSize.Int32) + public static void ShiftLeftArithmetic(Register destination, Register8 bitCount, bool destinationIsIndirect = false, RegisterSize size = RegisterSize.Long64) { if (bitCount != CL) { @@ -796,19 +796,19 @@ public static void ReadFromPortDX(Register value) }; } - public static void Push(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Push(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(destinationValue, isIndirect, displacement, size); } - public static void Push(Register register, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Push(Register register, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(register, isIndirect, displacement, size); } - public static void Push(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Push(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { - Do(label, isIndirect, displacement, size); + Do(label, true, displacement, size); } public static void Pushfd() @@ -871,7 +871,7 @@ public static void SubWithCarry(Register register, Register valueToAdd, bool des Do(register, valueToAdd, destinationDisplacement: destinationDisplacement, destinationIsIndirect: destinationIsIndirect); } - public static void And(Register register, uint value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void And(Register register, uint value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(register, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size: size); } @@ -886,12 +886,12 @@ public static void Xor(string destination, Register source, bool destinationIsIn Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Xor(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Xor(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Xor(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Xor(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } @@ -928,12 +928,12 @@ public static void Compare(string destination, Register source, bool destination Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Compare(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Compare(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Compare(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Compare(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } @@ -996,7 +996,7 @@ public static void Test(Register destination, Register sourceReg, bool sourceIsI }; } - public static void Divide(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Divide(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(destinationValue, isIndirect, displacement, size); } @@ -1006,12 +1006,12 @@ public static void Divide(Register register, bool isIndirect = false, int? displ Do(register, isIndirect, displacement, size); } - public static void Divide(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Divide(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(label, isIndirect, displacement, size); } - public static void IntegerDivide(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void IntegerDivide(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(destinationValue, isIndirect, displacement, size); } @@ -1021,27 +1021,27 @@ public static void IntegerDivide(Register register, bool isIndirect = false, int Do(register, isIndirect, displacement, size); } - public static void IntegerDivide(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void IntegerDivide(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(label, isIndirect, displacement, size); } - public static void Multiply(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Multiply(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(destinationValue, isIndirect, displacement, size); } - public static void Multiply(Register register, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Multiply(Register register, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(register, isIndirect, displacement, size); } - public static void Multiply(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Multiply(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(label, isIndirect, displacement, size); } - public static void Negate(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Negate(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(destinationValue, isIndirect, displacement, size); } @@ -1051,12 +1051,12 @@ public static void Negate(Register register, bool isIndirect = false, int? displ Do(register, isIndirect, displacement, size); } - public static void Negate(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Negate(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(label, isIndirect, displacement, size); } - public static void Not(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Not(uint destinationValue, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(destinationValue, isIndirect, displacement, size); } @@ -1066,7 +1066,7 @@ public static void Not(Register register, bool isIndirect = false, int? displace Do(register, isIndirect, displacement, size); } - public static void Not(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Int32) + public static void Not(string label, bool isIndirect = false, int? displacement = null, RegisterSize size = RegisterSize.Long64) { Do(label, isIndirect, displacement, size); } @@ -1076,12 +1076,12 @@ public static void AddWithCarry(string destination, Register source, bool destin Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void AddWithCarry(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void AddWithCarry(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void AddWithCarry(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void AddWithCarry(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } @@ -1106,12 +1106,12 @@ public static void Or(string destination, Register source, bool destinationIsInd Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Or(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Or(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void Or(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void Or(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } @@ -1246,7 +1246,7 @@ public static void StoreDwordInString() }; } - public static void LoadGdt(Register32 destination, bool isIndirect = false) + public static void LoadGdt(Register64 destination, bool isIndirect = false) { new Lgdt { @@ -1255,7 +1255,7 @@ public static void LoadGdt(Register32 destination, bool isIndirect = false) }; } - public static void LoadIdt(Register32 destination, bool isIndirect = false) + public static void LoadIdt(Register64 destination, bool isIndirect = false) { new Lidt { @@ -1269,12 +1269,12 @@ public static void RotateThroughCarryRight(string destination, Register source, Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void RotateThroughCarryRight(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void RotateThroughCarryRight(string destination, UInt32 value, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, value, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } - public static void RotateThroughCarryRight(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Int32) + public static void RotateThroughCarryRight(string destination, string source, bool destinationIsIndirect = false, int? destinationDisplacement = null, bool sourceIsIndirect = false, int? sourceDisplacement = null, RegisterSize size = RegisterSize.Long64) { Do(destination, source, destinationIsIndirect, destinationDisplacement, sourceIsIndirect, sourceDisplacement, size); } diff --git a/source/XSharp/XSharp/Gen1/XSRegisters.cs b/source/XSharp/XSharp/Gen1/XSRegisters.cs index dbe66069..7d6c700f 100644 --- a/source/XSharp/XSharp/Gen1/XSRegisters.cs +++ b/source/XSharp/XSharp/Gen1/XSRegisters.cs @@ -73,7 +73,7 @@ public Register16(string name, RegistersEnum regEnum) : base(name, regEnum, Regi public class Register32 : Register { - public Register32(string name, RegistersEnum regEnum) : base(name, regEnum, RegisterSize.Int32) + public Register32(string name, RegistersEnum regEnum) : base(name, regEnum, RegisterSize.FPU) { } } @@ -110,35 +110,35 @@ public RegisterSegment(string name, RegistersEnum regEnum) : base(name, regEnum, public static readonly Register8 AH = new Register8(nameof(AH), RegistersEnum.AH); public static readonly Register16 AX = new Register16(nameof(AX), RegistersEnum.AX); public static readonly Register32 EAX = new Register32(nameof(EAX), RegistersEnum.EAX); + public static readonly Register64 RAX = new Register64(nameof(RAX), RegistersEnum.RAX); public static readonly Register8 BL = new Register8(nameof(BL), RegistersEnum.BL); public static readonly Register8 BH = new Register8(nameof(BH), RegistersEnum.BH); public static readonly Register16 BX = new Register16(nameof(BX), RegistersEnum.BX); - public static readonly Register32 EBX = new Register32(nameof(EBX), RegistersEnum.EBX); + public static readonly Register64 RBX = new Register64(nameof(RBX), RegistersEnum.RBX); public static readonly Register8 CL = new Register8(nameof(CL), RegistersEnum.CL); public static readonly Register8 CH = new Register8(nameof(CH), RegistersEnum.CH); public static readonly Register16 CX = new Register16(nameof(CX), RegistersEnum.CX); - public static readonly Register32 ECX = new Register32(nameof(ECX), RegistersEnum.ECX); + public static readonly Register64 RCX = new Register64(nameof(RCX), RegistersEnum.RCX); public static readonly Register8 DL = new Register8(nameof(DL), RegistersEnum.DL); public static readonly Register8 DH = new Register8(nameof(DH), RegistersEnum.DH); public static readonly Register16 DX = new Register16(nameof(DX), RegistersEnum.DX); - public static readonly Register32 EDX = new Register32(nameof(EDX), RegistersEnum.EDX); - - public static readonly Register32 EBP = new Register32(nameof(EBP), RegistersEnum.EBP); - public static readonly Register32 ESP = new Register32(nameof(ESP), RegistersEnum.ESP); - public static readonly Register32 ESI = new Register32(nameof(ESI), RegistersEnum.ESI); - public static readonly Register32 EDI = new Register32(nameof(EDI), RegistersEnum.EDI); - - public static readonly Register64 RAX = new Register64(nameof(RAX), RegistersEnum.RAX); - public static readonly Register64 RBX = new Register64(nameof(RBX), RegistersEnum.RBX); - public static readonly Register64 RCX = new Register64(nameof(RCX), RegistersEnum.RCX); public static readonly Register64 RDX = new Register64(nameof(RDX), RegistersEnum.RDX); + + public static readonly Register64 RBP = new Register64(nameof(RBP), RegistersEnum.RBP); + public static readonly Register64 RSP = new Register64(nameof(RSP), RegistersEnum.RSP); public static readonly Register64 RSI = new Register64(nameof(RSI), RegistersEnum.RSI); public static readonly Register64 RDI = new Register64(nameof(RDI), RegistersEnum.RDI); - public static readonly Register64 RSP = new Register64(nameof(RSP), RegistersEnum.RSP); - public static readonly Register64 RBP = new Register64(nameof(RBP), RegistersEnum.RBP); + + // + + + + + + public static readonly Register64 R8 = new Register64(nameof(R8), RegistersEnum.R8); public static readonly Register64 R9 = new Register64(nameof(R9), RegistersEnum.R9); public static readonly Register64 R10 = new Register64(nameof(R10), RegistersEnum.R10); @@ -176,10 +176,10 @@ public RegisterSegment(string name, RegistersEnum regEnum) : base(name, regEnum, public static readonly RegisterXMM XMM7 = new RegisterXMM(nameof(XMM7), RegistersEnum.XMM7); // Control Registers - public static readonly Register32 CR0 = new Register32(nameof(CR0), RegistersEnum.CR0); - public static readonly Register32 CR1 = new Register32(nameof(CR1), RegistersEnum.CR1); - public static readonly Register32 CR2 = new Register32(nameof(CR2), RegistersEnum.CR2); - public static readonly Register32 CR3 = new Register32(nameof(CR3), RegistersEnum.CR3); - public static readonly Register32 CR4 = new Register32(nameof(CR4), RegistersEnum.CR4); + public static readonly Register64 CR0 = new Register64(nameof(CR0), RegistersEnum.CR0); + public static readonly Register64 CR1 = new Register64(nameof(CR1), RegistersEnum.CR1); + public static readonly Register64 CR2 = new Register64(nameof(CR2), RegistersEnum.CR2); + public static readonly Register64 CR3 = new Register64(nameof(CR3), RegistersEnum.CR3); + public static readonly Register64 CR4 = new Register64(nameof(CR4), RegistersEnum.CR4); } } diff --git a/source/XSharp/XSharp/XSharp.csproj b/source/XSharp/XSharp/XSharp.csproj index dec1613c..64f45047 100644 --- a/source/XSharp/XSharp/XSharp.csproj +++ b/source/XSharp/XSharp/XSharp.csproj @@ -5,6 +5,7 @@ True CA1716;CA1801;CA1822;$(NoWarn) AnyCPU;x86 + 10.0.0