Ejemplo n.º 1
0
        private IEnumerable <AssemblyLine> LoadArgument(int index)
        {
            var parameter = MethodDefinition.Parameters[index];

            yield return(LDA(LabelGenerator.GetFromParameter(parameter)));

            yield return(PHA());
        }
Ejemplo n.º 2
0
        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)));
        }
Ejemplo n.º 3
0
        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);
                }
            }
        }
Ejemplo n.º 4
0
        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)));
        }