mirror of
https://github.com/lscharen/iigs-sprite-compiler.git
synced 2024-12-22 07:30:11 +00:00
Resolve merge conflicts
This commit is contained in:
parent
05b56603f1
commit
28db7072d0
@ -11,13 +11,18 @@ namespace SpriteCompiler.Problem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class CodeSequence
|
public abstract class CodeSequence
|
||||||
{
|
{
|
||||||
|
protected CodeSequence()
|
||||||
|
: this(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected CodeSequence(int cycles)
|
protected CodeSequence(int cycles)
|
||||||
{
|
{
|
||||||
CycleCount = cycles;
|
CycleCount = cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of cycles that this code snippets takes to execute
|
// 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
|
// Function to generate a new state based on the code's operation
|
||||||
public abstract SpriteGeneratorState Apply(SpriteGeneratorState state);
|
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
|
public sealed class STACK_REL_8_BIT_READ_MODIFY_WRITE : CodeSequence
|
||||||
{
|
{
|
||||||
private readonly byte value;
|
private readonly byte value;
|
||||||
|
@ -6,8 +6,55 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
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 class StateHelpers
|
||||||
{
|
{
|
||||||
|
public static SolidRun FirstSolidRun(IEnumerable<SpriteByte> 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<ushort, SpriteByte> data)
|
public static SpriteByte? TryGetStackByte(this SpriteGeneratorState state, IDictionary<ushort, SpriteByte> data)
|
||||||
{
|
{
|
||||||
SpriteByte top;
|
SpriteByte top;
|
||||||
@ -74,6 +121,88 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of successor function that deal with very specific situations. A full successor function can
|
||||||
|
/// be composed of these functions
|
||||||
|
/// </summary>
|
||||||
|
public static class SuccessorFunctions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
public sealed class StackMove : ISuccessorFunction<CodeSequence, SpriteGeneratorState>
|
||||||
|
{
|
||||||
|
public IEnumerable<Tuple<CodeSequence, SpriteGeneratorState>> 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<SpriteByte?>().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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write the next 8-bit value that is not a solid byte. Must already be in 8-bit mode
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EighBitMixed : ISuccessorFunction<CodeSequence, SpriteGeneratorState>
|
||||||
|
{
|
||||||
|
public IEnumerable<Tuple<CodeSequence, SpriteGeneratorState>> 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<SpriteByte?>().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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This successor function does not try to leverage cached values in the X, Y or D registers
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
|
||||||
public sealed class SpriteGeneratorSuccessorFunction : ISuccessorFunction<CodeSequence, SpriteGeneratorState>
|
public sealed class SpriteGeneratorSuccessorFunction : ISuccessorFunction<CodeSequence, SpriteGeneratorState>
|
||||||
{
|
{
|
||||||
public IEnumerable<Tuple<CodeSequence, SpriteGeneratorState>> Successors(SpriteGeneratorState state)
|
public IEnumerable<Tuple<CodeSequence, SpriteGeneratorState>> Successors(SpriteGeneratorState state)
|
||||||
@ -94,7 +223,7 @@
|
|||||||
var firstByte = open.First();
|
var firstByte = open.First();
|
||||||
|
|
||||||
// Identify the first run of solid bytes
|
// 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
|
// In an initial state, the stack has not been set, but the accumulator contains a screen
|
||||||
// offset address. There are three possible options
|
// offset address. There are three possible options
|
||||||
@ -316,53 +445,6 @@
|
|||||||
pair.Item2.Mask == 0x00;
|
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<SpriteByte> 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<SpriteByte, bool> WithinRangeOf(int addr, int range)
|
private Func<SpriteByte, bool> WithinRangeOf(int addr, int range)
|
||||||
{
|
{
|
||||||
return x => (x.Offset >= addr) && ((x.Offset - addr) < range);
|
return x => (x.Offset >= addr) && ((x.Offset - addr) < range);
|
||||||
|
Loading…
Reference in New Issue
Block a user