diff --git a/SuperVM.Assembler/Assembler.cs b/SuperVM.Assembler/Assembler.cs index 04db48e..dd38663 100644 --- a/SuperVM.Assembler/Assembler.cs +++ b/SuperVM.Assembler/Assembler.cs @@ -181,17 +181,7 @@ namespace SuperVM.Assembler } } - ulong encoded = 0; - - encoded |= ((uint)(instruction.ExecutionZ) << 0); - encoded |= ((uint)(instruction.ExecutionN) << 2); - encoded |= ((uint)(instruction.Input0) << 4); - encoded |= ((uint)(instruction.Input1) << 6); - encoded |= ((uint)(instruction.Command) << 7); - encoded |= ((uint)(instruction.CommandInfo) << 13); - encoded |= ((uint)(instruction.ModifyFlags ? 1 : 0) << 29); - encoded |= ((uint)(instruction.Output) << 30); - encoded |= ((ulong)argument << 32); + ulong encoded = instruction.Encode(); code.Add(encoded); instructions.Add(instruction); diff --git a/SuperVM.Assembler/SuperVM.Assembler.csproj b/SuperVM.Assembler/SuperVM.Assembler.csproj index a69f90f..fcf4b2f 100644 --- a/SuperVM.Assembler/SuperVM.Assembler.csproj +++ b/SuperVM.Assembler/SuperVM.Assembler.csproj @@ -33,6 +33,10 @@ 4 + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + @@ -51,6 +55,7 @@ + diff --git a/SuperVM.Assembler/packages.config b/SuperVM.Assembler/packages.config new file mode 100644 index 0000000..273ff53 --- /dev/null +++ b/SuperVM.Assembler/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/SuperVM.ExperimentalHost/App.config b/SuperVM.ExperimentalHost/App.config new file mode 100644 index 0000000..2d2a12d --- /dev/null +++ b/SuperVM.ExperimentalHost/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/SuperVM.ExperimentalHost/Program.cs b/SuperVM.ExperimentalHost/Program.cs new file mode 100644 index 0000000..9c9cb3a --- /dev/null +++ b/SuperVM.ExperimentalHost/Program.cs @@ -0,0 +1,215 @@ +using ICSharpCode.SharpZipLib.Core; +using ICSharpCode.SharpZipLib.Zip; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SuperVM.ExperimentalHost +{ + class Program + { + private static bool running; + + static void Main(string[] args) + { + var zf = new ZipFile("executable.zip"); + + NameValueCollection meta; + var metaConfFile = zf.GetEntry("meta.conf"); + using (var stream = zf.GetInputStream(metaConfFile)) + { + meta = ReadConfiguration(stream); + } + + // Default memory size to + int memsize = int.Parse(meta["memsize"] ?? "16384"); + + var codeName = meta["code"] ?? "code.bin"; + var dataName = meta["data"]; + + if (codeName == null) + throw new InvalidDataException(); + + Module module; + { // Load code + var codeFile = zf.GetEntry(codeName); + var bits = new byte[codeFile.Size]; + using (var stream = zf.GetInputStream(codeFile)) + { + for (int i = 0; i < bits.Length; i += stream.Read(bits, i, bits.Length - i)) ; + } + var instr = new ulong[bits.Length / sizeof(ulong)]; + Buffer.BlockCopy(bits, 0, instr, 0, instr.Length * sizeof(ulong)); + + module = new Module(instr.Select(Instruction.Decode).ToArray()); + } + + byte[] initialMemory = null; + if (dataName != null) + { + var dataFile = zf.GetEntry(dataName); + using (var stream = zf.GetInputStream(dataFile)) + { + using (var ms = new MemoryStream()) + { + stream.CopyTo(ms); + initialMemory = ms.ToArray(); + } + } + } + + Memory memory = new Memory(memsize); + if (initialMemory != null) + { + Array.Copy(initialMemory, memory.Raw, Math.Min(initialMemory.Length, memsize)); + } + + var process = new Process(module, memory); + process.SysCall += Process_SysCall; + + running = true; + var watch = Stopwatch.StartNew(); + long instructions = 0; + while (running) + { + process.Step(); + instructions++; + } + watch.Stop(); + + Console.WriteLine(); + Console.WriteLine("Time: {0}", watch.Elapsed); + Console.WriteLine("Count: {0}", instructions); + Console.WriteLine("IPS: {0}", instructions / watch.Elapsed.TotalSeconds); + + Console.ReadLine(); + } + + private static void Process_SysCall(object sender, Process.CommandExecutionEnvironment e) + { + switch (e.Additional) + { + case 0: running = false; break; + case 1: // putc + Console.Write((char)(e.Input0 & 0xFF)); + break; + case 2: // puti + Console.Write(e.Input0); + break; + default: + throw new InvalidOperationException("Unkown syscall: " + e.Additional); + } + } + + static NameValueCollection ReadConfiguration(Stream stream) + { + var nvc = new NameValueCollection(); + using (var reader = new StreamReader(stream, Encoding.ASCII)) + { + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + if (line.StartsWith("#")) + continue; + var parts = line.Split('='); + if (parts.Length != 2) + throw new InvalidDataException(); + nvc[parts[0].Trim()] = parts[1].Trim(); + } + } + return nvc; + } + + // Calling example: + // WebClient webClient = new WebClient(); + // Stream data = webClient.OpenRead("http://www.example.com/test.zip"); + // This stream cannot be opened with the ZipFile class because CanSeek is false. + // UnzipFromStream(data, @"c:\temp"); + + public void UnzipFromStream(Stream zipStream, string outFolder) + { + ZipInputStream zipInputStream = new ZipInputStream(zipStream); + ZipEntry zipEntry = zipInputStream.GetNextEntry(); + while (zipEntry != null) + { + String entryFileName = zipEntry.Name; + // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName); + // Optionally match entrynames against a selection list here to skip as desired. + // The unpacked length is available in the zipEntry.Size property. + + byte[] buffer = new byte[4096]; // 4K is optimum + + // Manipulate the output filename here as desired. + String fullZipToPath = Path.Combine(outFolder, entryFileName); + string directoryName = Path.GetDirectoryName(fullZipToPath); + if (directoryName.Length > 0) + Directory.CreateDirectory(directoryName); + + // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size + // of the file, but does not waste memory. + // The "using" will close the stream even if an exception occurs. + using (FileStream streamWriter = File.Create(fullZipToPath)) + { + StreamUtils.Copy(zipInputStream, streamWriter, buffer); + } + zipEntry = zipInputStream.GetNextEntry(); + } + } + + + public void ExtractZipFile(string archiveFilenameIn, string password, string outFolder) + { + ZipFile zf = null; + try + { + FileStream fs = File.OpenRead(archiveFilenameIn); + zf = new ZipFile(fs); + if (!String.IsNullOrEmpty(password)) + { + zf.Password = password; // AES encrypted entries are handled automatically + } + foreach (ZipEntry zipEntry in zf) + { + if (!zipEntry.IsFile) + { + continue; // Ignore directories + } + String entryFileName = zipEntry.Name; + // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName); + // Optionally match entrynames against a selection list here to skip as desired. + // The unpacked length is available in the zipEntry.Size property. + + byte[] buffer = new byte[4096]; // 4K is optimum + Stream zipStream = zf.GetInputStream(zipEntry); + + // Manipulate the output filename here as desired. + String fullZipToPath = Path.Combine(outFolder, entryFileName); + string directoryName = Path.GetDirectoryName(fullZipToPath); + if (directoryName.Length > 0) + Directory.CreateDirectory(directoryName); + + // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size + // of the file, but does not waste memory. + // The "using" will close the stream even if an exception occurs. + using (FileStream streamWriter = File.Create(fullZipToPath)) + { + StreamUtils.Copy(zipStream, streamWriter, buffer); + } + } + } + finally + { + if (zf != null) + { + zf.IsStreamOwner = true; // Makes close also shut the underlying stream + zf.Close(); // Ensure we release resources + } + } + } + } +} diff --git a/SuperVM.ExperimentalHost/Properties/AssemblyInfo.cs b/SuperVM.ExperimentalHost/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d3d14c6 --- /dev/null +++ b/SuperVM.ExperimentalHost/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("SuperVM.ExperimentalHost")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SuperVM.ExperimentalHost")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("4fe5c136-c634-4ec5-a373-13b1a18a3a2b")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SuperVM.ExperimentalHost/SuperVM.ExperimentalHost.csproj b/SuperVM.ExperimentalHost/SuperVM.ExperimentalHost.csproj new file mode 100644 index 0000000..dec7d08 --- /dev/null +++ b/SuperVM.ExperimentalHost/SuperVM.ExperimentalHost.csproj @@ -0,0 +1,83 @@ + + + + + Debug + AnyCPU + {4FE5C136-C634-4EC5-A373-13B1A18A3A2B} + Exe + Properties + SuperVM.ExperimentalHost + SuperVM.ExperimentalHost + v4.6 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Always + + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + + + + + + + + + + + + + + + + + + + + + {014295b7-06bd-47c7-b8ca-d046984b0f35} + SuperVM + + + + + + + + $(SolutionDir)SuperVM.Assembler\bin\Debug\SuperVM.Assembler.exe $(ProjectDir)demo.asm +cp $(ProjectDir)demo.bin $(TargetDir)code.bin +$(TargetDir)pack.bat + + + \ No newline at end of file diff --git a/SuperVM.ExperimentalHost/demo.asm b/SuperVM.ExperimentalHost/demo.asm new file mode 100644 index 0000000..86d0fb6 --- /dev/null +++ b/SuperVM.ExperimentalHost/demo.asm @@ -0,0 +1,13 @@ + + + +main: + push 0 ; ptr +loop: + [i0:peek] load [f:yes] + [ex(z)=1] jmp @end + [i0:pop] syscall [ci:1] + [i0:arg] [i1:pop] add 1 + jmp @loop +end: + syscall [ci:0] ; quit \ No newline at end of file diff --git a/SuperVM.ExperimentalHost/demo.bin b/SuperVM.ExperimentalHost/demo.bin new file mode 100644 index 0000000..d8b5d7f Binary files /dev/null and b/SuperVM.ExperimentalHost/demo.bin differ diff --git a/SuperVM.ExperimentalHost/packages.config b/SuperVM.ExperimentalHost/packages.config new file mode 100644 index 0000000..7310888 --- /dev/null +++ b/SuperVM.ExperimentalHost/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/SuperVM.sln b/SuperVM.sln index b348cd0..be29d74 100644 --- a/SuperVM.sln +++ b/SuperVM.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperVM", "SuperVM\SuperVM. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperVM.Assembler", "SuperVM.Assembler\SuperVM.Assembler.csproj", "{A84B2773-0EB8-4F3A-B342-68DDD9BD675E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperVM.ExperimentalHost", "SuperVM.ExperimentalHost\SuperVM.ExperimentalHost.csproj", "{4FE5C136-C634-4EC5-A373-13B1A18A3A2B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {A84B2773-0EB8-4F3A-B342-68DDD9BD675E}.Debug|Any CPU.Build.0 = Debug|Any CPU {A84B2773-0EB8-4F3A-B342-68DDD9BD675E}.Release|Any CPU.ActiveCfg = Release|Any CPU {A84B2773-0EB8-4F3A-B342-68DDD9BD675E}.Release|Any CPU.Build.0 = Release|Any CPU + {4FE5C136-C634-4EC5-A373-13B1A18A3A2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FE5C136-C634-4EC5-A373-13B1A18A3A2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FE5C136-C634-4EC5-A373-13B1A18A3A2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FE5C136-C634-4EC5-A373-13B1A18A3A2B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SuperVM/Instruction.cs b/SuperVM/Instruction.cs index ce6090f..1918db2 100644 --- a/SuperVM/Instruction.cs +++ b/SuperVM/Instruction.cs @@ -17,5 +17,39 @@ namespace SuperVM public bool ModifyFlags; public OutputType Output; public uint Argument; + + public override string ToString() => $"({Input0},{Input1}) {Command} -> {Output}"; + + public ulong Encode() + { + ulong encoded = 0; + encoded |= ((uint)(this.ExecutionZ) << 0); + encoded |= ((uint)(this.ExecutionN) << 2); + encoded |= ((uint)(this.Input0) << 4); + encoded |= ((uint)(this.Input1) << 6); + encoded |= ((uint)(this.Command) << 7); + encoded |= ((uint)(this.CommandInfo) << 13); + encoded |= ((uint)(this.ModifyFlags ? 1 : 0) << 29); + encoded |= ((uint)(this.Output) << 30); + encoded |= ((ulong)this.Argument << 32); + return encoded; + } + + public static Instruction Decode(ulong encoded) + { + var instr = new Instruction(); + + instr.ExecutionZ = (ExecutionMode)((encoded >> 0) & 3); + instr.ExecutionN = (ExecutionMode)((encoded >> 2) & 3); + instr.Input0 = (InputType)((encoded >> 4) & 3); + instr.Input1 = (InputType)((encoded >> 6) & 1); + instr.Command = (Command)((encoded >> 7) & 63); + instr.CommandInfo = (ushort)((encoded >> 13) & 65535); + instr.ModifyFlags = ((encoded >> 29) & 1) != 0; + instr.Output = (OutputType)((encoded >> 30) & 3); + instr.Argument = (uint)(encoded >> 32); + + return instr; + } } } diff --git a/SuperVM/Process.Commands.cs b/SuperVM/Process.Commands.cs index 4487187..81aaffa 100644 --- a/SuperVM/Process.Commands.cs +++ b/SuperVM/Process.Commands.cs @@ -8,6 +8,12 @@ namespace SuperVM { partial class Process { + public Process(Module module, Memory memory) + { + this.Module = module; + this.Memory = memory; + } + private static class Cmd { diff --git a/SuperVM/Process.cs b/SuperVM/Process.cs index 78cfbe6..fb14ee3 100644 --- a/SuperVM/Process.cs +++ b/SuperVM/Process.cs @@ -167,7 +167,7 @@ namespace SuperVM public Module Module { get; set; } - public Memory Memory { get; set; } + public Memory Memory { get; set; } = new Memory(16384); public uint CodePointer { get; set; } public uint StackPointer { get; set; } @@ -189,12 +189,34 @@ namespace SuperVM this.Process = process; } + /// + /// First input value + /// public uint Input0 { get; set; } + + /// + /// Second input value + /// public uint Input1 { get; set; } + + /// + /// The command argument + /// public uint Argument { get; set; } + + /// + /// The command info + /// public uint Additional { get; set; } + + /// + /// The output of the command. + /// public uint Output { get; set; } + /// + /// The executing process. + /// public Process Process { get; private set; } } }