public static RomInfo CreateRom(CompiledProgram program, string assemblerPath) { var memoryManager = new MemoryManager(program); var lines = new List <AssemblyLine>(); lines.AddRange(CreateHeader()); lines.AddRange(CreateStaticVariables(program.Types, memoryManager)); lines.AddRange(CreateEntryPoint(program.EntryPoint)); lines.AddRange(CreateMethods(program)); lines.AddRange(CreateInterruptVectors()); File.WriteAllLines(AssemblyFileName, lines.Select(l => l.ToString())); var assembled = AssembleOutput(assemblerPath); return(new RomInfo(assembled, Path.GetFullPath(BinaryFileName), Path.GetFullPath(AssemblyFileName), Path.GetFullPath(SymbolsFileName), Path.GetFullPath(ListFileName))); }
private static IEnumerable <AssemblyLine> CreateMethods(CompiledProgram program) { var nodes = program.CallGraph.AllNodes; var methods = program.Types.SelectMany(t => t.Subroutines) .Where(s => s != program.EntryPoint) .Where(s => s.Body.Any()) // Don't emit empty methods. .Where(s => nodes.Any(n => n.Value == s.MethodDefinition)); // Don't emit methods that are never called. yield return(Comment("Begin subroutine emit.", 0)); yield return(BlankLine()); foreach (var method in methods) { // Do not emit subroutines that will never be JSR'd. if (method.TryGetFrameworkAttribute <AlwaysInlineAttribute>(out _)) { continue; } foreach (var line in CreateMethod(method)) { yield return(line); } } yield return(Comment("End subroutine emit.", 0)); yield return(BlankLine()); IEnumerable <AssemblyLine> CreateMethod(CompiledSubroutine subroutine) { yield return(Comment(subroutine.MethodDefinition.ToString(), 0)); yield return(Label(LabelGenerator.GetFromMethod(subroutine.MethodDefinition))); foreach (var line in subroutine.Body) { yield return(line); } yield return(BlankLine()); } }
public static Task <RomInfo> CompileFromFiles(IEnumerable <string> filePaths, string frameworkPath, string dasmPath) { if (filePaths == null) { throw new ArgumentNullException(nameof(filePaths)); } else if (!filePaths.Any()) { throw new ArgumentException("No source files specified.", nameof(filePaths)); } if (frameworkPath == null) { throw new ArgumentNullException(nameof(frameworkPath)); } else if (string.IsNullOrWhiteSpace(frameworkPath)) { throw new ArgumentException("VCS framework DLL path must be specified.", nameof(frameworkPath)); } // TODO - No DASM path should mean the caller just wants the assembly output, not a compiled binary. var compilation = CompilationCreator.CreateFromFilePaths(filePaths); var assemblyDefinition = GetAssemblyDefinition(compilation, out var assemblyStream); var frameworkAssembly = System.Reflection.Assembly.Load(new AssemblyName(Path.GetFileNameWithoutExtension(frameworkPath))); var frameworkAttributes = frameworkAssembly.ExportedTypes.Where(t => t.GetTypeInfo().BaseType == typeof(Attribute)); var compiler = new Compiler(frameworkAssembly, assemblyDefinition, frameworkAttributes.ToArray()); compiler.AddPredefinedTypes(); var frameworkCompiledAssembly = CompileAssembly(compiler, AssemblyDefinition.ReadAssembly(frameworkPath, new ReaderParameters { ReadSymbols = true })); var userCompiledAssembly = CompileAssembly(compiler, assemblyDefinition); var callGraph = CallGraph.CreateFromEntryMethod(userCompiledAssembly.EntryPoint); var program = new CompiledProgram(new[] { frameworkCompiledAssembly, userCompiledAssembly }, callGraph); var romInfo = RomCreator.CreateRom(program, dasmPath); return(Task.FromResult(romInfo)); }
public MemoryManager(CompiledProgram program) { Program = program; AllSymbols = AddPredefinedGlobals().Concat(LayoutGlobals()).Concat(AllocateLocalAddresses(program.CallGraph)); }