diff --git a/source/Indy.IL2CPU/Assembler/Assembler.cs b/source/Indy.IL2CPU/Assembler/Assembler.cs index 7209a473d..c3c6ff838 100644 --- a/source/Indy.IL2CPU/Assembler/Assembler.cs +++ b/source/Indy.IL2CPU/Assembler/Assembler.cs @@ -92,8 +92,6 @@ namespace Indy.IL2CPU.Assembler { } } - private Func mGetFileNameForGroup; - private uint mDataMemberCounter = 0; public string GetIdentifier(string aPrefix) { @@ -101,29 +99,11 @@ namespace Indy.IL2CPU.Assembler { return aPrefix + mDataMemberCounter.ToString("X8").ToUpper(); } - public Assembler(Func aGetFileNameForGroup) { - mGetFileNameForGroup = aGetFileNameForGroup; + public Assembler() { CurrentInstance.Push(this); //mInstructions.AddComplexIndexDefinition( } - public List> GetInstructions() { -//using (mInstructionsLocker.AcquireReaderLock()) { -// if(mInstructions.ContainsKey(Thread.CurrentThread.ManagedThreadId)) { -// return mInstructions[Thread.CurrentThread.ManagedThreadId]; -// } -//} -// using(mInstructionsLocker.AcquireWriterLock()) { -// // do this check again, between the two locks, the situation might have changed. -// if (mInstructions.ContainsKey(Thread.CurrentThread.ManagedThreadId)) -// { -// return mInstructions[Thread.CurrentThread.ManagedThreadId]; -// } -// var xResult = new -// } - throw new NotImplementedException("After multi-threaded refactorings, this hasn't been implemented again, yet"); - } - public List DataMembers { get { return mDataMembers; } } @@ -294,7 +274,9 @@ namespace Indy.IL2CPU.Assembler { } if (mInstructions.Count > 0) { string xMainLabel=""; - foreach (Instruction x in mInstructions) { + for(int i = 0; i < mInstructions.Count;i++){ + //foreach (Instruction x in mInstructions) { + var x = mInstructions[i]; string prefix = "\t\t\t"; Label xLabel = x as Label; if (xLabel != null) { diff --git a/source/Indy.IL2CPU/Assembler/ElementReference.cs b/source/Indy.IL2CPU/Assembler/ElementReference.cs index f47f19f9e..1566d817e 100644 --- a/source/Indy.IL2CPU/Assembler/ElementReference.cs +++ b/source/Indy.IL2CPU/Assembler/ElementReference.cs @@ -19,6 +19,35 @@ namespace Indy.IL2CPU.Assembler { } } + private ulong? mActualAddress; + + public bool Resolve(Assembler aAssembler, out ulong aAddress) { + if (mActualAddress != null) { + aAddress = mActualAddress.Value; + return true; + } + BaseAssemblerElement xElement = (from item in aAssembler.Instructions + let xLabel = item as Label + where xLabel != null && xLabel.QualifiedName.Equals(Name, StringComparison.InvariantCultureIgnoreCase) + select item).SingleOrDefault(); + if (xElement == null) { + xElement = (from item in aAssembler.DataMembers + where item.Name.Equals(Name, StringComparison.InvariantCultureIgnoreCase) + select item).SingleOrDefault(); + } + + if (xElement != null) { + if (xElement.ActualAddress.HasValue) { + mActualAddress = xElement.ActualAddress.Value + (uint)Offset; + aAddress = mActualAddress.Value; + return true; + } + } + + aAddress = 0; + return false; + } + public int Offset { get; set; diff --git a/source/Indy.IL2CPU/Assembler/RawAssembler.cs b/source/Indy.IL2CPU/Assembler/RawAssembler.cs index 87af17ad5..7836a9e23 100644 --- a/source/Indy.IL2CPU/Assembler/RawAssembler.cs +++ b/source/Indy.IL2CPU/Assembler/RawAssembler.cs @@ -6,6 +6,6 @@ using System.IO; namespace Indy.IL2CPU.Assembler { public class RawAssembler : Assembler { - public RawAssembler() : base(null) { } + public RawAssembler() : base() { } } } diff --git a/source/Indy.IL2CPU/Assembler/x86/Assembler.cs b/source/Indy.IL2CPU/Assembler/x86/Assembler.cs index 0c5196ed9..30dfad477 100644 --- a/source/Indy.IL2CPU/Assembler/x86/Assembler.cs +++ b/source/Indy.IL2CPU/Assembler/x86/Assembler.cs @@ -6,155 +6,9 @@ using System.Text; namespace Indy.IL2CPU.Assembler.X86 { public class Assembler : Indy.IL2CPU.Assembler.Assembler { - //TODO: COM Port info - should be in assembler? Assembler should not know about comports... - protected byte mComNumber = 0; - protected UInt16[] mComPortAddresses = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 }; - - public Assembler(Func aGetStreamForGroup, byte aComNumber) - : base(aGetStreamForGroup) { - mComNumber = aComNumber; - } - - public Assembler(Func aGetStreamForGroup) : base(aGetStreamForGroup) { - } - - private static string GetValidGroupName(string aGroup) { - return aGroup.Replace('-','_').Replace('.', '_'); - } - - public override void Initialize() { - base.Initialize(); - if (mComNumber > 0) { - new Define("DEBUGSTUB"); - } - new Label("Kernel_Start"); - new Comment("MultiBoot-compliant loader (e.g. GRUB or X.exe) provides info in registers: "); - new Comment("EBX=multiboot_info "); - new Comment("EAX=0x2BADB002 - check if it's really Multiboot loader "); - new Comment(" ;- copy mb info - some stuff for you "); - new Add { DestinationReg = Registers.EBX, SourceValue = 4 }; - new Move { - DestinationReg = Registers.EAX, - SourceReg = Registers.EBX, - SourceIsIndirect = true - }; - new Move { DestinationRef = new ElementReference("MultiBootInfo_Memory_Low"), DestinationIsIndirect = true, SourceReg = Registers.EAX }; - new Add { DestinationReg = Registers.EBX, SourceValue = 4 }; - new Move { - DestinationReg = Registers.EAX, - SourceReg = Registers.EBX, - SourceIsIndirect = true - }; - new Move { DestinationRef = new ElementReference("MultiBootInfo_Memory_High"), DestinationIsIndirect = true, SourceReg = Registers.EAX }; - new Move { - DestinationReg = Registers.ESP, - SourceRef = new ElementReference("Kernel_Stack") - }; - new Comment("some more startups todo"); - new ClrInterruptFlag(); - if (mComNumber > 0) { - UInt16 xComAddr = mComPortAddresses[mComNumber - 1]; - // 9600 baud, 8 databits, no parity, 1 stopbit - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 1 }; - new Move { DestinationReg = Registers.AL, SourceValue = 0 }; - new Out { Size = 8 }; // disable interrupts for serial stuff - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 3 }; - new Move { DestinationReg = Registers.AL, SourceValue = 0x80 }; - new Out { Size = 8 }; // Enable DLAB (set baud rate divisor) - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr }; - new Move { DestinationReg = Registers.AL, SourceValue = 0xC }; - new Out { Size = 8 }; // Set divisor (lo byte) - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 1 }; - new Move { DestinationReg = Registers.AL, SourceValue = 0x0 }; - new Out { Size = 8 }; // (hi byte) - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 3 }; - new Move { DestinationReg = Registers.AL, SourceValue = 0x3 }; - new Out { Size = 8 }; // 8 bits, no parity, one stop bit - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 2 }; - new Move { DestinationReg = Registers.AL, SourceValue = 0xC7 }; - new Out { Size = 8 }; // Enable FIFO, clear them, with 14-byte threshold - new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 4 }; - new Move { DestinationReg = Registers.AL, SourceValue = 0x3 }; - new Out { Size = 8 }; // IRQ-s enabled, RTS/DSR set - } - - // SSE init - // CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 - new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR4 }; - new Or { DestinationReg = Registers.EAX, SourceValue = 0x100 }; - new Move { DestinationReg = Registers.CR4, SourceReg = Registers.EAX }; - new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR4 }; - new Or { DestinationReg = Registers.EAX, SourceValue = 0x200 }; - new Move { DestinationReg = Registers.CR4, SourceReg = Registers.EAX }; - new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR0 }; - - new And { DestinationReg = Registers.EAX, SourceValue = 0xfffffffd }; - new Move { DestinationReg = Registers.CR0, SourceReg = Registers.EAX }; - new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR0 }; - - new And { DestinationReg = Registers.EAX, SourceValue = 1 }; - new Move { DestinationReg = Registers.CR0, SourceReg = Registers.EAX }; - - // END SSE INIT - - new Call { DestinationLabel = EntryPointName }; - new Label(".loop"); - new ClrInterruptFlag(); - new Halt(); - new Jump { DestinationLabel = ".loop" }; - new Label("DEBUG_STUB_"); - new Return(); - if (mComNumber > 0) { - var xStub = new DebugStub(); - xStub.Main(mComPortAddresses[mComNumber - 1]); - } - //aOutputWriter.WriteLine("section .data"); - DataMembers.Add(new DataIfNotDefined("NASM_COMPILATION")); - uint xFlags = 0x10003; - DataMembers.Add(new DataMember("MultibootSignature", - new uint[] { 0x1BADB002 })); - DataMembers.Add(new DataMember("MultibootFlags", - xFlags)); - DataMembers.Add(new DataMember("MultibootChecksum", - (int)(0 - (xFlags + 0x1BADB002)))); - DataMembers.Add(new DataMember("MultibootHeaderAddr", new ElementReference("MultibootSignature"))); - DataMembers.Add(new DataMember("MultibootLoadAddr", new ElementReference("MultibootSignature"))); - DataMembers.Add(new DataMember("MultibootLoadEndAddr", 0)); - DataMembers.Add(new DataMember("MultibootBSSEndAddr", 0)); - DataMembers.Add(new DataMember("MultibootEntryAddr", new ElementReference("Kernel_Start"))); - DataMembers.Add(new DataEndIfDefined()); - DataMembers.Add(new DataIfDefined("NASM_COMPILATION")); - xFlags = 0x00003; - DataMembers.Add(new DataMember("MultibootSignature", - new uint[] { 0x1BADB002 })); - DataMembers.Add(new DataMember("MultibootFlags", - xFlags)); - DataMembers.Add(new DataMember("MultibootChecksum", - (int)(0 - (xFlags + 0x1BADB002)))); - DataMembers.Add(new DataEndIfDefined()); - DataMembers.Add(new DataMember("MultiBootInfo_Memory_High", 0)); - DataMembers.Add(new DataMember("MultiBootInfo_Memory_Low", 0)); - DataMembers.Add(new DataMember("Before_Kernel_Stack", - new byte[0x50000])); - DataMembers.Add(new DataMember("Kernel_Stack", - new byte[0])); - DebugStub.EmitDataSection(); - } - - protected override void OnBeforeFlush() { - base.OnBeforeFlush(); - DataMembers.AddRange(new DataMember[]{ - new DataMember("_end_data", - new byte[0])}); - new Label("_end_code"); - } - public override void FlushText(TextWriter aOutput) { aOutput.WriteLine("use32"); - //aOutput.WriteLine("%define NASM_COMPILATION 1"); - //aOutput.WriteLine("global Kernel_Start"); - aOutput.WriteLine("[map all main.map]"); - //aOutput.WriteLine("org 0x500000"); + aOutput.WriteLine("org 0x200000"); base.FlushText(aOutput); } } diff --git a/source/Indy.IL2CPU/Assembler/x86/CosmosAssembler.cs b/source/Indy.IL2CPU/Assembler/x86/CosmosAssembler.cs new file mode 100644 index 000000000..b952cbd31 --- /dev/null +++ b/source/Indy.IL2CPU/Assembler/x86/CosmosAssembler.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace Indy.IL2CPU.Assembler.X86 { + public class CosmosAssembler: Assembler { + //TODO: COM Port info - should be in assembler? Assembler should not know about comports... + protected byte mComNumber = 0; + protected UInt16[] mComPortAddresses = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 }; + + public CosmosAssembler(byte aComNumber) { + mComNumber = aComNumber; + } + + private static string GetValidGroupName(string aGroup) { + return aGroup.Replace('-','_').Replace('.', '_'); + } + + public override void Initialize() { + base.Initialize(); + if (mComNumber > 0) { + new Define("DEBUGSTUB"); + } + new Label("Kernel_Start"); + new Comment("MultiBoot-compliant loader (e.g. GRUB or X.exe) provides info in registers: "); + new Comment("EBX=multiboot_info "); + new Comment("EAX=0x2BADB002 - check if it's really Multiboot loader "); + new Comment(" ;- copy mb info - some stuff for you "); + new Add { DestinationReg = Registers.EBX, SourceValue = 4 }; + new Move { + DestinationReg = Registers.EAX, + SourceReg = Registers.EBX, + SourceIsIndirect = true + }; + new Move { DestinationRef = new ElementReference("MultiBootInfo_Memory_Low"), DestinationIsIndirect = true, SourceReg = Registers.EAX }; + new Add { DestinationReg = Registers.EBX, SourceValue = 4 }; + new Move { + DestinationReg = Registers.EAX, + SourceReg = Registers.EBX, + SourceIsIndirect = true + }; + new Move { DestinationRef = new ElementReference("MultiBootInfo_Memory_High"), DestinationIsIndirect = true, SourceReg = Registers.EAX }; + new Move { + DestinationReg = Registers.ESP, + SourceRef = new ElementReference("Kernel_Stack") + }; + new Comment("some more startups todo"); + new ClrInterruptFlag(); + if (mComNumber > 0) { + UInt16 xComAddr = mComPortAddresses[mComNumber - 1]; + // 9600 baud, 8 databits, no parity, 1 stopbit + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 1 }; + new Move { DestinationReg = Registers.AL, SourceValue = 0 }; + new Out { Size = 8 }; // disable interrupts for serial stuff + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 3 }; + new Move { DestinationReg = Registers.AL, SourceValue = 0x80 }; + new Out { Size = 8 }; // Enable DLAB (set baud rate divisor) + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr }; + new Move { DestinationReg = Registers.AL, SourceValue = 0xC }; + new Out { Size = 8 }; // Set divisor (lo byte) + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 1 }; + new Move { DestinationReg = Registers.AL, SourceValue = 0x0 }; + new Out { Size = 8 }; // (hi byte) + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 3 }; + new Move { DestinationReg = Registers.AL, SourceValue = 0x3 }; + new Out { Size = 8 }; // 8 bits, no parity, one stop bit + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 2 }; + new Move { DestinationReg = Registers.AL, SourceValue = 0xC7 }; + new Out { Size = 8 }; // Enable FIFO, clear them, with 14-byte threshold + new Move { DestinationReg = Registers.DX, SourceValue = (uint)xComAddr + 4 }; + new Move { DestinationReg = Registers.AL, SourceValue = 0x3 }; + new Out { Size = 8 }; // IRQ-s enabled, RTS/DSR set + } + + // SSE init + // CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 + new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR4 }; + new Or { DestinationReg = Registers.EAX, SourceValue = 0x100 }; + new Move { DestinationReg = Registers.CR4, SourceReg = Registers.EAX }; + new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR4 }; + new Or { DestinationReg = Registers.EAX, SourceValue = 0x200 }; + new Move { DestinationReg = Registers.CR4, SourceReg = Registers.EAX }; + new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR0 }; + + new And { DestinationReg = Registers.EAX, SourceValue = 0xfffffffd }; + new Move { DestinationReg = Registers.CR0, SourceReg = Registers.EAX }; + new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR0 }; + + new And { DestinationReg = Registers.EAX, SourceValue = 1 }; + new Move { DestinationReg = Registers.CR0, SourceReg = Registers.EAX }; + + // END SSE INIT + + new Call { DestinationLabel = EntryPointName }; + new Label(".loop"); + new ClrInterruptFlag(); + new Halt(); + new Jump { DestinationLabel = ".loop" }; + new Label("DEBUG_STUB_"); + new Return(); + if (mComNumber > 0) { + var xStub = new DebugStub(); + xStub.Main(mComPortAddresses[mComNumber - 1]); + } + //aOutputWriter.WriteLine("section .data"); + DataMembers.Add(new DataIfNotDefined("NASM_COMPILATION")); + uint xFlags = 0x10003; + DataMembers.Add(new DataMember("MultibootSignature", + new uint[] { 0x1BADB002 })); + DataMembers.Add(new DataMember("MultibootFlags", + xFlags)); + DataMembers.Add(new DataMember("MultibootChecksum", + (int)(0 - (xFlags + 0x1BADB002)))); + DataMembers.Add(new DataMember("MultibootHeaderAddr", new ElementReference("MultibootSignature"))); + DataMembers.Add(new DataMember("MultibootLoadAddr", new ElementReference("MultibootSignature"))); + DataMembers.Add(new DataMember("MultibootLoadEndAddr", 0)); + DataMembers.Add(new DataMember("MultibootBSSEndAddr", 0)); + DataMembers.Add(new DataMember("MultibootEntryAddr", new ElementReference("Kernel_Start"))); + DataMembers.Add(new DataEndIfDefined()); + DataMembers.Add(new DataIfDefined("NASM_COMPILATION")); + xFlags = 0x00003; + DataMembers.Add(new DataMember("MultibootSignature", + new uint[] { 0x1BADB002 })); + DataMembers.Add(new DataMember("MultibootFlags", + xFlags)); + DataMembers.Add(new DataMember("MultibootChecksum", + (int)(0 - (xFlags + 0x1BADB002)))); + DataMembers.Add(new DataEndIfDefined()); + DataMembers.Add(new DataMember("MultiBootInfo_Memory_High", 0)); + DataMembers.Add(new DataMember("MultiBootInfo_Memory_Low", 0)); + DataMembers.Add(new DataMember("Before_Kernel_Stack", + new byte[0x50000])); + DataMembers.Add(new DataMember("Kernel_Stack", + new byte[0])); + DebugStub.EmitDataSection(); + } + + protected override void OnBeforeFlush() { + base.OnBeforeFlush(); + DataMembers.AddRange(new DataMember[]{ + new DataMember("_end_data", + new byte[0])}); + new Label("_end_code"); + } + + public override void FlushText(TextWriter aOutput) { + //aOutput.WriteLine("use32"); + //aOutput.WriteLine("%define NASM_COMPILATION 1"); + //aOutput.WriteLine("global Kernel_Start"); + aOutput.WriteLine("[map all main.map]"); + //aOutput.WriteLine("org 0x500000"); + base.FlushText(aOutput); + } + } +} \ No newline at end of file diff --git a/source/Indy.IL2CPU/Assembler/x86/Halt.cs b/source/Indy.IL2CPU/Assembler/x86/Halt.cs index 1d89d69fc..8dcda7e6c 100644 --- a/source/Indy.IL2CPU/Assembler/x86/Halt.cs +++ b/source/Indy.IL2CPU/Assembler/x86/Halt.cs @@ -8,7 +8,7 @@ namespace Indy.IL2CPU.Assembler.X86 { public static void InitializeEncodingData(Instruction.InstructionData aData) { aData.EncodingOptions.Add(new InstructionData.InstructionEncodingOption { - OpCode= new byte[0xF4] + OpCode= new byte[]{0xF4} }); } } diff --git a/source/Indy.IL2CPU/Assembler/x86/JumpBase.cs b/source/Indy.IL2CPU/Assembler/x86/JumpBase.cs index 00d86faab..17fefbe8c 100644 --- a/source/Indy.IL2CPU/Assembler/x86/JumpBase.cs +++ b/source/Indy.IL2CPU/Assembler/x86/JumpBase.cs @@ -16,5 +16,15 @@ namespace Indy.IL2CPU.Assembler.X86 { DestinationRef = new ElementReference(value); } } + + public override string ToString() { + var xResult = base.ToString(); + if (!xResult.StartsWith(Mnemonic + " near", StringComparison.InvariantCultureIgnoreCase)) { + if (xResult.StartsWith(Mnemonic)) { + return Mnemonic + " near " + xResult.Substring(Mnemonic.Length + 1); + } + } + return xResult; + } } } \ No newline at end of file diff --git a/source/Indy.IL2CPU/Assembler/x86/Move.cs b/source/Indy.IL2CPU/Assembler/x86/Move.cs index dc3284277..de5c739b1 100644 --- a/source/Indy.IL2CPU/Assembler/x86/Move.cs +++ b/source/Indy.IL2CPU/Assembler/x86/Move.cs @@ -7,14 +7,23 @@ namespace Indy.IL2CPU.Assembler.X86 { [OpCode("mov")] public class Move: InstructionWithDestinationAndSourceAndSize { public static void InitializeEncodingData(Instruction.InstructionData aData){ + aData.DefaultSize = false; + aData.EncodingOptions.Add(new InstructionData.InstructionEncodingOption { + OpCode = new byte[] { 0xB0 }, + //NeedsModRMByte=true, + OperandSizeByte=0, + OperandSizeBitShiftLeft = 3, + DestinationReg=Guid.Empty, + DestinationRegByte=0, + SourceImmediate=true + }); // immediate to register aData.EncodingOptions.Add(new InstructionData.InstructionEncodingOption { OpCode = new byte[] { 0xC6 }, - NeedsModRMByte=true, - OperandSizeByte=0, - DestinationReg=Guid.Empty, - DestinationRegByte=1, - SourceImmediate=true - }); + //NeedsModRMByte=true, + OperandSizeByte = 0, + OperandSizeBitShiftLeft = 0, + SourceImmediate = true + }); // immediate to memory } } } diff --git a/source/Indy.IL2CPU/Assembler/x86/Push.cs b/source/Indy.IL2CPU/Assembler/x86/Push.cs index 10b970cd7..0caf5e2c0 100644 --- a/source/Indy.IL2CPU/Assembler/x86/Push.cs +++ b/source/Indy.IL2CPU/Assembler/x86/Push.cs @@ -6,5 +6,8 @@ using System.Text; namespace Indy.IL2CPU.Assembler.X86 { [OpCode("push")] public class Push : InstructionWithDestinationAndSize { + public Push() { + Size = 32; + } } } \ No newline at end of file diff --git a/source/Indy.IL2CPU/Assembler/x86/X/RegisterEBX.cs b/source/Indy.IL2CPU/Assembler/x86/X/RegisterEBX.cs new file mode 100644 index 000000000..b1b80154b --- /dev/null +++ b/source/Indy.IL2CPU/Assembler/x86/X/RegisterEBX.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Indy.IL2CPU.Assembler.X86.X { + public class RegisterEBX : Register32 { + public const string Name = "EBX"; + public static readonly RegisterEBX Instance = new RegisterEBX(); + + public override string ToString() { + return Name; + } + + public static implicit operator RegisterEBX(ElementReference aReference) { + Instance.Move(aReference); + return Instance; + } + + public static implicit operator RegisterEBX(MemoryAction aAction) { + Instance.Move(aAction); + return Instance; + } + + public static implicit operator RegisterEBX(UInt32 aValue) { + Instance.Move(aValue); + return Instance; + } + + public static implicit operator RegisterEBX(RegisterECX aValue) { + Instance.Move(aValue.GetId()); + return Instance; + } + } +} diff --git a/source/Indy.IL2CPU/Assembler/x86/X/Y86.cs b/source/Indy.IL2CPU/Assembler/x86/X/Y86.cs index 8724f0f9e..756df9908 100644 --- a/source/Indy.IL2CPU/Assembler/x86/X/Y86.cs +++ b/source/Indy.IL2CPU/Assembler/x86/X/Y86.cs @@ -13,7 +13,8 @@ namespace Indy.IL2CPU.Assembler.X86.X { //TODO: Add registers as needed, not all are here yet public RegisterEAX EAX = RegisterEAX.Instance; public RegisterAL AL = RegisterAL.Instance; - + + public RegisterEBX EBX = RegisterEBX.Instance; public RegisterECX ECX = RegisterECX.Instance; public RegisterEDX EDX = RegisterEDX.Instance; diff --git a/source/Indy.IL2CPU/Assembler/x86/_Infra/Extensions.cs b/source/Indy.IL2CPU/Assembler/x86/_Infra/Extensions.cs index b7d9e17e2..fb59e4312 100644 --- a/source/Indy.IL2CPU/Assembler/x86/_Infra/Extensions.cs +++ b/source/Indy.IL2CPU/Assembler/x86/_Infra/Extensions.cs @@ -13,7 +13,7 @@ namespace Indy.IL2CPU.Assembler.X86 { if (aThis.DestinationReg != Guid.Empty) { xDest = Registers.GetRegisterName(aThis.DestinationReg); } else { - xDest = "0x" + aThis.DestinationValue.ToString("X").ToUpperInvariant(); + xDest = "0x" + aThis.DestinationValue.GetValueOrDefault().ToString("X").ToUpperInvariant(); } } if (aThis.DestinationDisplacement != 0) { diff --git a/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithDestination.cs b/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithDestination.cs index 9ddbfb8a3..9245a6a4a 100644 --- a/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithDestination.cs +++ b/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithDestination.cs @@ -15,7 +15,7 @@ namespace Indy.IL2CPU.Assembler.X86 { set; } - uint DestinationValue { + uint? DestinationValue { get; set; } diff --git a/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithSource.cs b/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithSource.cs index c67af7f80..633bdfd14 100644 --- a/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithSource.cs +++ b/source/Indy.IL2CPU/Assembler/x86/_Infra/IInstructionWithSource.cs @@ -15,7 +15,7 @@ namespace Indy.IL2CPU.Assembler.X86 { set; } - uint SourceValue { + uint? SourceValue { get; set; } diff --git a/source/Indy.IL2CPU/Assembler/x86/_Infra/Instruction.cs b/source/Indy.IL2CPU/Assembler/x86/_Infra/Instruction.cs index 5811acf93..450bd471d 100644 --- a/source/Indy.IL2CPU/Assembler/x86/_Infra/Instruction.cs +++ b/source/Indy.IL2CPU/Assembler/x86/_Infra/Instruction.cs @@ -73,6 +73,10 @@ namespace Indy.IL2CPU.Assembler.X86 { public bool HasDestinationOperand; public bool HasSourceOperand; + /// + /// True if by default large (32bit), false if small (16bit) + /// + public bool? DefaultSize; public List EncodingOptions = new List(); } @@ -131,8 +135,261 @@ namespace Indy.IL2CPU.Assembler.X86 { case 64: return "qword"; default: + return "non-existing size!!"; throw new Exception("Invalid size: " + aSize); } - } + } + + public override bool DetermineSize(Indy.IL2CPU.Assembler.Assembler aAssembler, out ulong aSize) { + InstructionData xInstructionData = null; + using (mInstructionDatasLocker.AcquireReaderLock()) { + mInstructionDatas.TryGetValue(this.GetType(), out xInstructionData); + } + if (xInstructionData == null) { + return base.DetermineSize(aAssembler, out aSize); + } + var xWithDestAndSourceAndSize = this as InstructionWithDestinationAndSourceAndSize; + if (xWithDestAndSourceAndSize != null) { + return DetermineSize(xWithDestAndSourceAndSize, xInstructionData, out aSize); + } + var xWithDestAndSource = this as InstructionWithDestinationAndSource; + if (xWithDestAndSource != null) { + return base.DetermineSize(aAssembler, out aSize); + } + var xWithDestAndSize = this as InstructionWithDestinationAndSize; + if (xWithDestAndSize != null) { + return base.DetermineSize(aAssembler, out aSize); + } + var xWithDest = this as InstructionWithDestination; + if (xWithDest != null) { + return base.DetermineSize(aAssembler, out aSize); + } + if (xInstructionData.EncodingOptions.Count > 0) { + // todo: improve + aSize = (ulong)xInstructionData.EncodingOptions[0].OpCode.Length; + return true; + } + aSize = 0; + return false; + } + + private static bool DetermineSize(InstructionWithDestinationAndSourceAndSize aInstruction, InstructionData aInstructionData, out ulong aSize) { + var xTheEncodingOption = GetInstructionEncodingOption(aInstruction, aInstructionData); + aSize = (ulong)xTheEncodingOption.OpCode.Length; + if (xTheEncodingOption.NeedsModRMByte) { + aSize += 1; + } + if (aInstruction.DestinationValue.HasValue || aInstruction.DestinationRef != null) { + aSize += 4; + } + if (aInstruction.SourceValue.HasValue || aInstruction.SourceRef != null) { + aSize += 4; + } + if (aInstructionData.DefaultSize.HasValue && aInstructionData.DefaultSize.Value) { + if (aInstruction.Size < 16) { + aSize += 1; + } + } + + return true; + } + + private static InstructionData.InstructionEncodingOption GetInstructionEncodingOption(InstructionWithDestinationAndSourceAndSize aInstruction, InstructionData aInstructionData) { + InstructionData.InstructionEncodingOption xTheEncodingOption = null; + for (int i = 0; i < aInstructionData.EncodingOptions.Count; i++) { + var xEncodingOption = aInstructionData.EncodingOptions[i]; + if (!((xEncodingOption.DestinationReg.HasValue && aInstruction.DestinationReg != Guid.Empty) || + (!xEncodingOption.DestinationReg.HasValue && aInstruction.DestinationReg == Guid.Empty))) { + // mismatch + continue; + } + if (!((xEncodingOption.DestinationMemory && (aInstruction.DestinationValue != null && aInstruction.DestinationIsIndirect)) || + (!xEncodingOption.DestinationMemory && (aInstruction.DestinationValue == null && !aInstruction.DestinationIsIndirect))) && aInstruction.DestinationIsIndirect) { + continue; + } + if (!((xEncodingOption.DestinationImmediate && aInstruction.DestinationValue != null) || + (!xEncodingOption.DestinationImmediate && aInstruction.DestinationValue == null))) { + continue; + } + if (!((xEncodingOption.SourceReg.HasValue && aInstruction.SourceReg != Guid.Empty) || + (!xEncodingOption.SourceReg.HasValue && aInstruction.SourceReg == Guid.Empty))) { + // mismatch + continue; + } + if (!((xEncodingOption.SourceMemory && (aInstruction.SourceValue != null && aInstruction.SourceIsIndirect)) || + (!xEncodingOption.SourceMemory && (aInstruction.SourceValue == null && !aInstruction.SourceIsIndirect))) && aInstruction.SourceIsIndirect) { + continue; + } + if (!((xEncodingOption.SourceImmediate && aInstruction.SourceValue != null) || + (!xEncodingOption.SourceImmediate && aInstruction.SourceValue == null))) { + continue; + } + xTheEncodingOption = xEncodingOption; + break; + } + if (xTheEncodingOption == null) { + throw new Exception("No valid EncodingOption found!"); + } + return xTheEncodingOption; + } + + public override byte[] GetData(Indy.IL2CPU.Assembler.Assembler aAssembler) { + InstructionData xInstructionData = null; + using (mInstructionDatasLocker.AcquireReaderLock()) { + mInstructionDatas.TryGetValue(this.GetType(), out xInstructionData); + } + if (xInstructionData == null) { + return base.GetData(aAssembler); + } + var xWithDestAndSourceAndSize = this as InstructionWithDestinationAndSourceAndSize; + if (xWithDestAndSourceAndSize != null) { + return GetData(aAssembler, xWithDestAndSourceAndSize, xInstructionData); + } + var xWithDestAndSource = this as InstructionWithDestinationAndSource; + if (xWithDestAndSource != null) { + return base.GetData(aAssembler); + } + var xWithDestAndSize = this as InstructionWithDestinationAndSize; + if (xWithDestAndSize != null) { + return base.GetData(aAssembler); + } + var xWithDest = this as InstructionWithDestination; + if (xWithDest != null) { + return base.GetData(aAssembler); + } + if (xInstructionData.EncodingOptions.Count > 0) { + // todo: improve + return xInstructionData.EncodingOptions[0].OpCode; + } + return null; + } + + private static byte[] GetData(Indy.IL2CPU.Assembler.Assembler aAssembler, InstructionWithDestinationAndSourceAndSize aInstruction, InstructionData aInstructionData) { + var xEncodingOption = GetInstructionEncodingOption(aInstruction, aInstructionData); + var xSize = xEncodingOption.OpCode.Length; + if (xEncodingOption.NeedsModRMByte) { + xSize += 1; + } + if (aInstruction.DestinationValue.HasValue || aInstruction.DestinationRef != null) { + xSize += 4; + } + if (aInstruction.SourceValue.HasValue || aInstruction.SourceRef != null) { + xSize += 4; + } + int xExtraOffset = 0; + if (aInstructionData.DefaultSize.HasValue && aInstructionData.DefaultSize.Value) { + if (aInstruction.Size < 16) { + xSize += 1; + xExtraOffset = 1; + } + } + var xBuffer = new byte[xSize]; + Array.Copy(xEncodingOption.OpCode, 0, xBuffer, xExtraOffset, xEncodingOption.OpCode.Length); + if (xExtraOffset == 1) { + throw new Exception("OperandSize prefix needed!"); + } + if (xEncodingOption.NeedsModRMByte) { + if(aInstruction.DestinationReg != Guid.Empty && !aInstruction.DestinationIsIndirect) { + xBuffer[xEncodingOption.OpCode.Length] |= 0xC0; + } + if(aInstruction.DestinationReg != Guid.Empty && aInstruction.DestinationIsIndirect) { + // + } + // todo: add more ModRM stuff + } + if (aInstruction.DestinationReg != Guid.Empty) { + xBuffer[xEncodingOption.DestinationRegByte] |= (byte)(EncodeRegister(aInstruction.DestinationReg) << xEncodingOption.DestinationRegBitShiftLeft); + } + // todo: add more options + if (aInstruction.SourceValue.HasValue) { + int xOffset = xEncodingOption.OpCode.Length + xExtraOffset; + if(xEncodingOption.NeedsModRMByte) { + xOffset++; + } + Array.Copy(BitConverter.GetBytes(aInstruction.SourceValue.Value), 0, xBuffer, xOffset, 4); + } + if(aInstructionData.DefaultSize.HasValue) { + if(!aInstructionData.DefaultSize.Value && aInstruction.Size > 16) { + xBuffer[xEncodingOption.OperandSizeByte] |= (byte)(1 << xEncodingOption.OperandSizeBitShiftLeft); + } + } + + + // + return xBuffer; + } + + private static byte EncodeRegister(Guid aRegister) { + // todo: implement support for other registers + if (!Registers.Is32Bit(aRegister)) { + throw new Exception("Register not supported!"); + } + if (aRegister == Registers.EAX) return 0x0; + if (aRegister == Registers.ECX) return 0x1; + if (aRegister == Registers.EDX) return 0x2; + if (aRegister == Registers.EBX) return 0x3; + if (aRegister == Registers.ESP) return 0x4; + if (aRegister == Registers.EBP) return 0x5; + if (aRegister == Registers.ESI) return 0x6; + if (aRegister == Registers.EDI) return 0x7; + throw new Exception("Register not supported!"); + } + + private ulong? mDataSize; + + public override bool IsComplete(Indy.IL2CPU.Assembler.Assembler aAssembler) { + var xWithDestAndSourceAndSize = this as InstructionWithDestinationAndSourceAndSize; + if (xWithDestAndSourceAndSize != null) { + ulong xAddress; + if (xWithDestAndSourceAndSize.DestinationRef != null && !xWithDestAndSourceAndSize.DestinationRef.Resolve(aAssembler, out xAddress)) { + return false; + } + if (xWithDestAndSourceAndSize.DestinationRef != null && !xWithDestAndSourceAndSize.SourceRef.Resolve(aAssembler, out xAddress)) { + return false; + } + } + var xWithDestAndSource = this as InstructionWithDestinationAndSource; + if (xWithDestAndSource != null) { + ulong xAddress; + if (xWithDestAndSource.DestinationRef != null && !xWithDestAndSource.DestinationRef.Resolve(aAssembler, out xAddress)) { + return false; + } + if (xWithDestAndSource.DestinationRef != null && !xWithDestAndSource.SourceRef.Resolve(aAssembler, out xAddress)) { + return false; + } + } + var xWithDestAndSize = this as InstructionWithDestinationAndSize; + if (xWithDestAndSize != null) { + ulong xAddress; + if (xWithDestAndSize.DestinationRef != null && !xWithDestAndSize.DestinationRef.Resolve(aAssembler, out xAddress)) { + return false; + } + } + var xWithDest = this as InstructionWithDestination; + if (xWithDest != null) { + ulong xAddress; + if (xWithDest.DestinationRef!=null && !xWithDest.DestinationRef.Resolve(aAssembler, out xAddress)) { + return false; + } + } + + return true; + } + + public override ulong? ActualAddress { + get { + if (!StartAddress.HasValue) { + return null; + } + if(!mDataSize.HasValue){ + return null; + } + return StartAddress.Value + mDataSize.Value; + } + } + + private static bool IsLargeRegister(Guid aRegister) { + return Registers.Is32Bit(aRegister); + } } } diff --git a/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestination.cs b/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestination.cs index 80e6a49b7..2f4ca01ca 100644 --- a/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestination.cs +++ b/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestination.cs @@ -15,7 +15,7 @@ namespace Indy.IL2CPU.Assembler.X86 { set; } - public uint DestinationValue { + public uint? DestinationValue { get; set; } diff --git a/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestinationAndSource.cs b/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestinationAndSource.cs index e4932dc48..960a1b6b1 100644 --- a/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestinationAndSource.cs +++ b/source/Indy.IL2CPU/Assembler/x86/_Infra/InstructionWithDestinationAndSource.cs @@ -15,7 +15,7 @@ namespace Indy.IL2CPU.Assembler.X86 { set; } - public uint SourceValue { + public uint? SourceValue { get; set; } @@ -38,7 +38,7 @@ namespace Indy.IL2CPU.Assembler.X86 { if (SourceReg != Guid.Empty) { xDest = Registers.GetRegisterName(SourceReg); } else { - xDest = "0x" + SourceValue.ToString("X").ToUpperInvariant(); + xDest = "0x" + SourceValue.GetValueOrDefault().ToString("X").ToUpperInvariant(); } } if (SourceDisplacement != 0) { diff --git a/source/Indy.IL2CPU/Engine.cs b/source/Indy.IL2CPU/Engine.cs index e2424227f..f46921c7d 100644 --- a/source/Indy.IL2CPU/Engine.cs +++ b/source/Indy.IL2CPU/Engine.cs @@ -167,10 +167,9 @@ namespace Indy.IL2CPU { switch (aTargetPlatform) { case TargetPlatformEnum.X86: { mMap = new Indy.IL2CPU.IL.X86.X86OpCodeMap(); - mAssembler = new Assembler.X86.Assembler(aGetFileNameForGroup, - ((aDebugMode != DebugMode.None) && (aDebugMode != DebugMode.MLUsingGDB)) - ? aDebugComNumber - : (byte)0); + mAssembler = new Assembler.X86.CosmosAssembler(((aDebugMode != DebugMode.None) && (aDebugMode != DebugMode.MLUsingGDB)) + ? aDebugComNumber + : (byte)0); break; } default: diff --git a/source/Indy.IL2CPU/IL/x86/Newarr.cs b/source/Indy.IL2CPU/IL/x86/Newarr.cs index 0d03db713..b799f7a60 100644 --- a/source/Indy.IL2CPU/IL/x86/Newarr.cs +++ b/source/Indy.IL2CPU/IL/x86/Newarr.cs @@ -54,11 +54,11 @@ namespace Indy.IL2CPU.IL.X86 { new CPUx86.Pop { DestinationReg = CPUx86.Registers.ESI}; new CPUx86.Push { DestinationReg = CPUx86.Registers.ESI }; //Assembler.StackSizes.Push(xElementCountSize); - new CPUx86.Push { DestinationValue = mElementSize }; + new CPUx86.Push { Size=32,DestinationValue = mElementSize }; Assembler.StackContents.Push(new StackContent(4, typeof(uint))); Multiply(Assembler); // the total items size is now on the stack - new CPUx86.Push { DestinationValue = (ObjectImpl.FieldDataOffset + 4) }; + new CPUx86.Push { Size=32,DestinationValue = (ObjectImpl.FieldDataOffset + 4) }; Assembler.StackContents.Push(new StackContent(4, typeof(uint))); Add(Assembler); // the total array size is now on the stack. diff --git a/source/Indy.IL2CPU/IL/x86/Op.cs b/source/Indy.IL2CPU/IL/x86/Op.cs index e250c30c7..003e386fa 100644 --- a/source/Indy.IL2CPU/IL/x86/Op.cs +++ b/source/Indy.IL2CPU/IL/x86/Op.cs @@ -233,7 +233,7 @@ namespace Indy.IL2CPU.IL.X86 { throw new Exception("Remainder size " + (aField.Size) + " not supported!"); } if (aAddGCCode && aField.NeedsGC) { - new CPUx86.Push { DestinationReg = Registers.ESP, DestinationIsIndirect = true }; + new CPUx86.Push {Size=32, DestinationReg = Registers.ESP, DestinationIsIndirect = true }; Engine.QueueMethod(GCImplementationRefs.IncRefCountRef); new CPUx86.Call { DestinationLabel = Label.GenerateLabelName(GCImplementationRefs.IncRefCountRef) }; } diff --git a/source/Indy.IL2CPU/IL/x86/X86MainEntryPointOp.cs b/source/Indy.IL2CPU/IL/x86/X86MainEntryPointOp.cs index b43b6dc40..0e8e17e96 100644 --- a/source/Indy.IL2CPU/IL/x86/X86MainEntryPointOp.cs +++ b/source/Indy.IL2CPU/IL/x86/X86MainEntryPointOp.cs @@ -16,7 +16,7 @@ namespace Indy.IL2CPU.IL.X86 { } public override void Push(uint aValue) { - new CPUx86.Push { DestinationValue = aValue }; + new CPUx86.Push {Size=32, DestinationValue = aValue }; } private int xLabelId = 0; diff --git a/source/Indy.IL2CPU/IL/x86/X86MethodHeaderOp.cs b/source/Indy.IL2CPU/IL/x86/X86MethodHeaderOp.cs index ef2512bc1..14cd02606 100644 --- a/source/Indy.IL2CPU/IL/x86/X86MethodHeaderOp.cs +++ b/source/Indy.IL2CPU/IL/x86/X86MethodHeaderOp.cs @@ -44,7 +44,7 @@ namespace Indy.IL2CPU.IL.X86 { foreach (var xLocal in aLocals) { aAssembler.StackContents.Push(new StackContent(xLocal.Size, xLocal.VariableType)); for (int i = 0; i < (xLocal.Size / 4); i++) { - new CPUx86.Push{DestinationValue=0}; + new CPUx86.Push{Size=32,DestinationValue=0}; } } if(aDebugMode&& aIsNonDebuggable) { diff --git a/source/Indy.IL2CPU/Indy.IL2CPU.csproj b/source/Indy.IL2CPU/Indy.IL2CPU.csproj index 7f71a4571..b3bb43c90 100644 --- a/source/Indy.IL2CPU/Indy.IL2CPU.csproj +++ b/source/Indy.IL2CPU/Indy.IL2CPU.csproj @@ -90,11 +90,13 @@ + + diff --git a/source/Playgrounds/Matthijs/TestApp/Program.cs b/source/Playgrounds/Matthijs/TestApp/Program.cs index 9262fb58e..effb09350 100644 --- a/source/Playgrounds/Matthijs/TestApp/Program.cs +++ b/source/Playgrounds/Matthijs/TestApp/Program.cs @@ -12,7 +12,8 @@ namespace TestApp { class Renderer : Y86 { public void DoRender() { Label = "Kernel_Start"; - EAX = 0xB8000; + EBX = 0xB8000; + Memory[EBX, 8] = 65; //IfDefined("DefinedSymbol"); //Memory[0xB8002, 8] = 66; //Memory[0xB8003, 8] = 15; @@ -26,11 +27,7 @@ namespace TestApp { } static void Main(string[] args) { try { - var xAsm = new Assembler(delegate(string aGroup) { - return Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), - "Output"), - aGroup + ".out"); - }); + var xAsm = new Assembler(); xAsm.Initialize(); xAsm.DataMembers.Add(new Indy.IL2CPU.Assembler.DataMember("TestData", new byte[]{65, 66, 67, 68,69,70, 71, 72, 73, 74})); xAsm.Instructions.Clear(); @@ -42,17 +39,17 @@ namespace TestApp { Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Output")); } - //using (Stream xOutput = new FileStream(Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), - // "Output"), - // "TheOutput.out"), FileMode.Create)) { - // xAsm.FlushBinary(xOutput, 0x500000); - //} - - using (StreamWriter xOutput = new StreamWriter(Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), + using (Stream xOutput = new FileStream(Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Output"), - "TheOutput.out"))) { - xAsm.FlushText(xOutput); - } + "TheOutput.bin"), FileMode.Create)) { + xAsm.FlushBinary(xOutput, 0x500000); + } + + //using (StreamWriter xOutput = new StreamWriter(Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), + // "Output"), + // "TheOutput.asm"))) { + // xAsm.FlushText(xOutput); + //} // now the file should have been written } catch (Exception E) { Console.WriteLine(E.ToString()); }