private IEnumerable <AssemblyLine> LoadArgument(int index) { var parameter = MethodDefinition.Parameters[index]; yield return(LDA(LabelGenerator.GetFromParameter(parameter))); yield return(PHA()); }
private IEnumerable <AssemblyLine> StoreArgument(Instruction instruction) { // Either Starg or Starg_S. var parameter = (ParameterDefinition)instruction.Operand; yield return(PLA()); yield return(STA(LabelGenerator.GetFromParameter(parameter))); }
private IEnumerable <Symbol> AllocateLocalAddresses(CallGraph callGraph) { foreach (var node in callGraph.AllNodes) { foreach (var parameter in node.Value.Parameters) { yield return(DefineSymbol(LabelGenerator.GetFromParameter(parameter), NextGlobal)); AdvanceNextGlobal(1); } foreach (var local in node.Value.Body.Variables) { yield return(DefineSymbol(LabelGenerator.GetFromVariable(node.Value, local), NextGlobal)); AdvanceNextGlobal(1); } } }
private IEnumerable <AssemblyLine> Call(Instruction instruction) { // Could be either a MethodDefinition or MethodReference. MethodReference method = (MethodReference)instruction.Operand; var methodDeclaringType = method.DeclaringType.FullName; var processedSubroutine = Types[methodDeclaringType].Subroutines.Single(s => s.FullName == method.FullName); // Check if this method should be replaced with a direct store to a symbol (generally a TIA register). // Don't directly compare types since we may have received a different Framework assembly than what this library was built against. if (processedSubroutine.TryGetFrameworkAttribute <OverrideWithStoreToSymbolAttribute>(out var overrideStore)) { if (!overrideStore.Strobe) { //TODO - We assume this is a 1-arg void method. Actually enforce this at the processing stage. if (method.Parameters.Count != 1) { throw new NotImplementedException($"{method.Name}, marked with {nameof(OverrideWithStoreToSymbolAttribute)}, must take 1 parameter for now."); } yield return(PLA()); } yield return(STA(overrideStore.Symbol)); yield break; } if (processedSubroutine.TryGetFrameworkAttribute <OverrideWithLoadToRegisterAttribute>(out var overrideRegisterLoad)) { //TODO - We assume this is a 1-arg void method. Actually enforce this at the processing stage. if (method.Parameters.Count != 1) { throw new NotImplementedException($"{method.Name}, marked with {nameof(OverrideWithLoadToRegisterAttribute)} must take 1 parameter."); } yield return(PLA()); switch (overrideRegisterLoad.Register) { case "A": break; case "X": yield return(TAX()); break; case "Y": yield return(TAY()); break; default: throw new FatalCompilationException($"Attempted load to unknown register: {overrideRegisterLoad.Register}"); } yield break; } if (processedSubroutine.TryGetFrameworkAttribute <OverrideWithLoadFromSymbolAttribute>(out var overrideLoad)) { if (method.Parameters.Count != 0) { throw new NotImplementedException($"{method.Name}, marked with {nameof(OverrideWithLoadFromSymbolAttribute)}, must take 0 parameters."); } yield return(LDA(overrideLoad.Symbol)); yield return(PHA()); yield break; } var parameters = ((MethodReference)method).Parameters.ToImmutableArray(); if (parameters.Any()) { // PLA arguments in reverse off stack and assign to parameters. foreach (var parameter in parameters.Reverse()) { yield return(PLA()); yield return(STA(LabelGenerator.GetFromParameter(parameter))); } } if (processedSubroutine.TryGetFrameworkAttribute <AlwaysInlineAttribute>(out _)) { var compiledSubroutine = Types[method.DeclaringType.FullName].Subroutines.Single(s => s.FullName == method.FullName) as CompiledSubroutine; if (compiledSubroutine == null) { throw new FatalCompilationException($"Attempted to inline method '{processedSubroutine.Name}' that hasn't been compiled yet. This suggests a bug in determining method compilation order."); } foreach (var assemblyLine in compiledSubroutine.Body) { //TODO - If the subroutine contains labels you can end up emitting duplicates if the inline subroutine is called more than once. Make them unique. //TODO - Once we have branching and multiple return statements this will explode. // In reality we probably want to replace RTS with JMP to a label inserted after this method body. if (!assemblyLine.Text.Contains("RTS")) { yield return(assemblyLine); } } yield break; } yield return(JSR(LabelGenerator.GetFromMethod(method))); }