Add a 16-bit word operation and unit test

This commit is contained in:
Lucas Scharenbroich 2016-11-30 00:43:54 -06:00
parent ff48fefcd4
commit de3754e91e
3 changed files with 88 additions and 11 deletions

View File

@ -4,6 +4,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using SpriteCompiler.Problem;
using SpriteCompiler.AI;
using System.Diagnostics;
using System.Collections.Generic;
namespace SpriteCompiler.Test
{
@ -50,13 +51,9 @@ namespace SpriteCompiler.Test
Assert.AreEqual(14, (int)solution.Last().PathCost);
// Write out the solution
foreach (var step in solution.Skip(1))
{
Trace.WriteLine(step.Action.ToString());
}
WriteOutSolution(solution);
}
/*
[TestMethod]
public void TestSingleWordSprite()
{
@ -65,11 +62,31 @@ namespace SpriteCompiler.Test
var search = SpriteGeneratorSearchProblem.Create();
// Act : solve the problem
var solution = search.Search(problem, new SpriteGeneratorState());
var solution = search.Search(problem, new SpriteGeneratorState(new byte[] { 0xAA, 0x55 }));
// Assert : The initial state IS the goal state
Assert.AreEqual(1, solution.Count());
// Assert
//
// The fastest way to draw a single word at the current location should be
//
// TCS
// LDA #$55AA
// STA 0,s = 10 cycles
Assert.AreEqual(3, solution.Count());
Assert.AreEqual(10, (int)solution.Last().PathCost);
// Write out the solution
WriteOutSolution(solution);
}
private void WriteOutSolution(IEnumerable<SpriteGeneratorSearchNode> solution)
{
foreach (var step in solution.Skip(1))
{
Trace.WriteLine(step.Action.ToString());
}
Trace.WriteLine(string.Format("; Total Cost = {0} cycles", (int)solution.Last().PathCost));
}
*/
}
}

View File

@ -118,4 +118,31 @@ namespace SpriteCompiler.Problem
);
}
}
public sealed class STACK_REL_16_BIT_IMMEDIATE_STORE : CodeSequence
{
private readonly ushort value;
private readonly byte offset;
public STACK_REL_16_BIT_IMMEDIATE_STORE(ushort value, byte offset) : base(8) { this.value = value; this.offset = offset; }
public override SpriteGeneratorState Apply(SpriteGeneratorState state)
{
return state.Clone(_ =>
{
_.A = _.A.LoadConstant(value);
_.RemoveByte((ushort)(offset + _.S.Value));
_.RemoveByte((ushort)(offset + _.S.Value + 1));
});
}
public override string ToString()
{
return String.Join("\n",
FormatLine("", "LDA", "#$" + value.ToString("X4"), "3 cycles"),
FormatLine("", "STA", offset.ToString("X2") + ",s", "5 cycles")
);
}
}
}

View File

@ -242,6 +242,34 @@ namespace SpriteCompiler.Problem
actions.Add(new SHORT_M());
// Add any possible 16-bit data manipulations
if (state.S.IsScreenOffset)
{
var addr = state.S.Value;
// Look for consecutive bytes
var local = state.Bytes.Where(WithinRangeOf(addr, 257)).ToList(); // 16-bit value can extend to the 256th byte
var words = local
.Skip(1)
.Select((x, i) => new { High = x, Low = local[i] })
.Where(p => p.Low.Offset == (p.High.Offset - 1))
.ToList();
foreach (var word in words)
{
var offset = (byte)(word.Low.Offset - addr);
var data = (ushort)(word.Low.Data + (word.High.Data << 8));
actions.Add(new STACK_REL_16_BIT_IMMEDIATE_STORE(data, offset));
}
// We can LDA #$XXXX / STA X,s for any values within 256 bytes of the current address
foreach (var datum in state.Bytes.Where(WithinRangeOf(addr, 256)))
{
var offset = (byte)(datum.Offset - addr);
actions.Add(new STACK_REL_8_BIT_IMMEDIATE_STORE(datum.Data, offset));
}
}
}
else
{
@ -252,8 +280,8 @@ namespace SpriteCompiler.Problem
{
var addr = state.S.Value;
// We can LDA #$XX / STA X,s for any values within 256 bytes of the curren address
foreach (var datum in state.Bytes.Where(x => (x.Offset - addr) < 255))
// We can LDA #$XX / STA X,s for any values within 256 bytes of the current address
foreach (var datum in state.Bytes.Where(WithinRangeOf(addr, 256)))
{
var offset = datum.Offset - addr;
actions.Add(new STACK_REL_8_BIT_IMMEDIATE_STORE(datum.Data, (byte)offset));
@ -264,6 +292,11 @@ namespace SpriteCompiler.Problem
// Run through the actions to create a dictionary
return actions.ToDictionary(x => x, x => x.Apply(state));
}
private Func<SpriteByte, bool> WithinRangeOf(int addr, int range)
{
return x => (x.Offset >= addr) && ((x.Offset - addr) < range);
}
}
public class SpriteGeneratorHeuristicFunction : IHeuristicFunction<SpriteGeneratorState, IntegerPathCost>