From 28db7072d0c6c07b505d822e2746f36bc783d5bc Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Sun, 15 Apr 2018 13:52:55 -0500 Subject: [PATCH] Resolve merge conflicts --- SpriteCompiler/Problem/CodeSequence.cs | 41 +++- .../SpriteGeneratorSuccessorFunction.cs | 178 +++++++++++++----- 2 files changed, 170 insertions(+), 49 deletions(-) diff --git a/SpriteCompiler/Problem/CodeSequence.cs b/SpriteCompiler/Problem/CodeSequence.cs index 87d359f..62487f3 100644 --- a/SpriteCompiler/Problem/CodeSequence.cs +++ b/SpriteCompiler/Problem/CodeSequence.cs @@ -11,13 +11,18 @@ namespace SpriteCompiler.Problem /// public abstract class CodeSequence { + protected CodeSequence() + : this(0) + { + } + protected CodeSequence(int cycles) { CycleCount = cycles; } // Number of cycles that this code snippets takes to execute - public int CycleCount { get; private set; } + public int CycleCount { get; protected set; } // Function to generate a new state based on the code's operation public abstract SpriteGeneratorState Apply(SpriteGeneratorState state); @@ -200,6 +205,40 @@ namespace SpriteCompiler.Problem } } + public sealed class EIGHT_BIT_STORE : CodeSequence + { + private SpriteByte data; + + public EIGHT_BIT_STORE(SpriteByte data) + { + this.data = data; + } + + public override SpriteGeneratorState Apply(SpriteGeneratorState state) + { + var offset = data.Offset - state.S.Value; + + // If + + + return state.Clone(_ => + { + _.A = Register.UNINITIALIZED; + _.RemoveByte((ushort)(offset + _.S.Value)); + }); + } + + public override string Emit() + { + return String.Join("\n", + FormatLine("", "LDA", offset.ToString("X2") + ",s", "4 cycles"), + FormatLine("", "AND", "#$" + mask.ToString("X2"), "2 cycles"), + FormatLine("", "ORA", "#$" + value.ToString("X2"), "2 cycles"), + FormatLine("", "STA", offset.ToString("X2") + ",s", "4 cycles") + ); + } + } + public sealed class STACK_REL_8_BIT_READ_MODIFY_WRITE : CodeSequence { private readonly byte value; diff --git a/SpriteCompiler/Problem/SpriteGeneratorSuccessorFunction.cs b/SpriteCompiler/Problem/SpriteGeneratorSuccessorFunction.cs index ecb0ce6..33d0503 100644 --- a/SpriteCompiler/Problem/SpriteGeneratorSuccessorFunction.cs +++ b/SpriteCompiler/Problem/SpriteGeneratorSuccessorFunction.cs @@ -6,8 +6,55 @@ using System.Collections.Generic; using System.Linq; + public sealed class SolidRun + { + private readonly SpriteByte first; + private readonly SpriteByte last; + + public SolidRun(SpriteByte first, SpriteByte last) + { + this.first = first; + this.last = last; + } + + public SpriteByte First { get { return first; } } + public SpriteByte Last { get { return last; } } + public int Count { get { return last.Offset - first.Offset + 1; } } + } + public static class StateHelpers { + public static SolidRun FirstSolidRun(IEnumerable open) + { + bool trigger = false; + SpriteByte first = default(SpriteByte); + SpriteByte last = default(SpriteByte); + + foreach (var item in open) + { + if (item.Mask == 0x00 && !trigger) + { + first = item; + trigger = true; + } + + if ((item.Mask != 0x00 || (item.Offset - last.Offset) > 1) && trigger) + { + return new SolidRun(first, last); + } + + last = item; + } + + // If we get to the end and are still solid, great + if (last.Mask == 0x00 && trigger) + { + return new SolidRun(first, last); + } + + return null; + } + public static SpriteByte? TryGetStackByte(this SpriteGeneratorState state, IDictionary data) { SpriteByte top; @@ -74,6 +121,88 @@ } } + /// + /// A collection of successor function that deal with very specific situations. A full successor function can + /// be composed of these functions + /// + public static class SuccessorFunctions + { + /// + /// Proposed actions to move the stack. We can only move the stack if we are in 16-bit accumulator + /// mode. + /// + /// We only consider two movements (add to this list if suboptimal code sequences are found) + /// + /// 1. Jump to first byte more than 256 bytes ahead of the current stack location + /// 2. Jump to the last byte of the nearest run + /// + public sealed class StackMove : ISuccessorFunction + { + public IEnumerable> Successors(SpriteGeneratorState state) + { + if (!state.LongA || !state.S.IsScreenOffset) + { + yield break; + } + + var openList = state.RemainingBytes(); + + // Check for the first byte more than 255 bytes beyound our current location + var nextByte = openList.Where(sb => (sb.Offset - state.S.Value) > 255).Cast().FirstOrDefault(); + if (nextByte != null) + { + yield return state.Apply(new MOVE_STACK(nextByte.Value.Offset - state.S.Value)); + } + + // Check for the next run of solid bytes and move to the end + var run = StateHelpers.FirstSolidRun(openList); + if (run != null) + { + yield return state.Apply(new MOVE_STACK(run.Last.Offset - state.S.Value)); + } + + yield break; + } + } + + /// + /// Write the next 8-bit value that is not a solid byte. Must already be in 8-bit mode + /// + public sealed class EighBitMixed : ISuccessorFunction + { + public IEnumerable> Successors(SpriteGeneratorState state) + { + if (state.LongA || !state.S.IsScreenOffset) + { + yield break; + } + + var openList = state.RemainingBytes(); + + // Get the first byte with a non-zero mask that is within 255 bytes of the current location + var nextByte = openList.Where(sb => (sb.Offset - state.S.Value) <= 255).Cast().FirstOrDefault(); + if (nextByte != null) + { + yield return state.Apply(new MOVE_STACK(nextByte.Value.Offset - state.S.Value)); + } + + // Check for the next run of solid bytes and move to the end + var run = StateHelpers.FirstSolidRun(openList); + if (run != null) + { + yield return state.Apply(new MOVE_STACK(run.Last.Offset - state.S.Value)); + } + + yield break; + } + } + } + + /// + /// This successor function does not try to leverage cached values in the X, Y or D registers + /// + + public sealed class SpriteGeneratorSuccessorFunction : ISuccessorFunction { public IEnumerable> Successors(SpriteGeneratorState state) @@ -94,7 +223,7 @@ var firstByte = open.First(); // Identify the first run of solid bytes - var firstSolid = FirstSolidRun(open); + var firstSolid = StateHelpers.FirstSolidRun(open); // In an initial state, the stack has not been set, but the accumulator contains a screen // offset address. There are three possible options @@ -316,53 +445,6 @@ pair.Item2.Mask == 0x00; } - private class SolidRun - { - private readonly SpriteByte first; - private readonly SpriteByte last; - - public SolidRun(SpriteByte first, SpriteByte last) - { - this.first = first; - this.last = last; - } - - public SpriteByte First { get { return first; } } - public SpriteByte Last { get { return last; } } - public int Count { get { return last.Offset - first.Offset + 1; } } - } - - private SolidRun FirstSolidRun(IEnumerable open) - { - bool trigger = false; - SpriteByte first = default(SpriteByte); - SpriteByte last = default(SpriteByte); - - foreach (var item in open) - { - if (item.Mask == 0x00 && !trigger) - { - first = item; - trigger = true; - } - - if ((item.Mask != 0x00 || (item.Offset - last.Offset) > 1) && trigger) - { - return new SolidRun(first, last); - } - - last = item; - } - - // If we get to the end and are still sold, great - if (last.Mask == 0x00 && trigger) - { - return new SolidRun(first, last); - } - - return null; - } - private Func WithinRangeOf(int addr, int range) { return x => (x.Offset >= addr) && ((x.Offset - addr) < range);