643 lines
20 KiB
C#
643 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
using BizHawk.Common;
|
|
using BizHawk.Common.CollectionExtensions;
|
|
using BizHawk.Common.NumberExtensions;
|
|
using BizHawk.Emulation.Common;
|
|
|
|
// ReSharper disable PossibleInvalidCastExceptionInForeachLoop
|
|
namespace BizHawk.Client.Common.RamSearchEngine
|
|
{
|
|
public class RamSearchEngine
|
|
{
|
|
private Compare _compareTo = Compare.Previous;
|
|
|
|
private List<IMiniWatch> _watchList = new List<IMiniWatch>();
|
|
private readonly SearchEngineSettings _settings;
|
|
private readonly UndoHistory<IMiniWatch> _history = new UndoHistory<IMiniWatch>(true);
|
|
private bool _isSorted = true; // Tracks whether or not the list is sorted by address, if it is, binary search can be used for finding watches
|
|
|
|
public RamSearchEngine(SearchEngineSettings settings, IMemoryDomains memoryDomains)
|
|
{
|
|
_settings = new SearchEngineSettings(memoryDomains)
|
|
{
|
|
Mode = settings.Mode,
|
|
Domain = settings.Domain,
|
|
Size = settings.Size,
|
|
CheckMisAligned = settings.CheckMisAligned,
|
|
Type = settings.Type,
|
|
BigEndian = settings.BigEndian,
|
|
PreviousType = settings.PreviousType
|
|
};
|
|
}
|
|
|
|
public RamSearchEngine(SearchEngineSettings settings, IMemoryDomains memoryDomains, Compare compareTo, long? compareValue, int? differentBy)
|
|
: this(settings, memoryDomains)
|
|
{
|
|
_compareTo = compareTo;
|
|
DifferentBy = differentBy;
|
|
CompareValue = compareValue;
|
|
}
|
|
|
|
#region API
|
|
|
|
public IEnumerable<long> OutOfRangeAddress => _watchList
|
|
.Where(watch => watch.Address >= Domain.Size)
|
|
.Select(watch => watch.Address);
|
|
|
|
public void Start()
|
|
{
|
|
_history.Clear();
|
|
var domain = _settings.Domain;
|
|
var listSize = domain.Size;
|
|
if (!_settings.CheckMisAligned)
|
|
{
|
|
listSize /= (int)_settings.Size;
|
|
}
|
|
|
|
_watchList = new List<IMiniWatch>((int)listSize);
|
|
|
|
switch (_settings.Size)
|
|
{
|
|
default:
|
|
case WatchSize.Byte:
|
|
for (int i = 0; i < domain.Size; i++)
|
|
{
|
|
if (_settings.IsDetailed())
|
|
{
|
|
_watchList.Add(new MiniByteWatchDetailed(domain, i));
|
|
}
|
|
else
|
|
{
|
|
_watchList.Add(new MiniByteWatch(domain, i));
|
|
}
|
|
}
|
|
|
|
break;
|
|
case WatchSize.Word:
|
|
for (int i = 0; i < domain.Size - 1; i += _settings.CheckMisAligned ? 1 : 2)
|
|
{
|
|
if (_settings.IsDetailed())
|
|
{
|
|
_watchList.Add(new MiniWordWatchDetailed(domain, i, _settings.BigEndian));
|
|
}
|
|
else
|
|
{
|
|
_watchList.Add(new MiniWordWatch(domain, i, _settings.BigEndian));
|
|
}
|
|
}
|
|
|
|
break;
|
|
case WatchSize.DWord:
|
|
for (int i = 0; i < domain.Size - 3; i += _settings.CheckMisAligned ? 1 : 4)
|
|
{
|
|
if (_settings.IsDetailed())
|
|
{
|
|
_watchList.Add(new MiniDWordWatchDetailed(domain, i, _settings.BigEndian));
|
|
}
|
|
else
|
|
{
|
|
_watchList.Add(new MiniDWordWatch(domain, i, _settings.BigEndian));
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exposes the current watch state based on index
|
|
/// </summary>
|
|
public Watch this[int index] =>
|
|
Watch.GenerateWatch(
|
|
_settings.Domain,
|
|
_watchList[index].Address,
|
|
_settings.Size,
|
|
_settings.Type,
|
|
_settings.BigEndian,
|
|
"",
|
|
0,
|
|
_watchList[index].Previous,
|
|
_settings.IsDetailed() ? ((IMiniWatchDetails)_watchList[index]).ChangeCount : 0);
|
|
|
|
public int DoSearch()
|
|
{
|
|
int before = _watchList.Count;
|
|
|
|
_watchList = _compareTo switch
|
|
{
|
|
Compare.Previous => ComparePrevious(_watchList).ToList(),
|
|
Compare.SpecificValue => CompareSpecificValue(_watchList).ToList(),
|
|
Compare.SpecificAddress => CompareSpecificAddress(_watchList).ToList(),
|
|
Compare.Changes => CompareChanges(_watchList).ToList(),
|
|
Compare.Difference => CompareDifference(_watchList).ToList(),
|
|
_ => ComparePrevious(_watchList).ToList()
|
|
};
|
|
|
|
if (_settings.PreviousType == PreviousType.LastSearch)
|
|
{
|
|
SetPreviousToCurrent();
|
|
}
|
|
|
|
if (UndoEnabled)
|
|
{
|
|
_history.AddState(_watchList);
|
|
}
|
|
|
|
return before - _watchList.Count;
|
|
}
|
|
|
|
public bool Preview(long address)
|
|
{
|
|
var listOfOne = Enumerable.Repeat(_isSorted
|
|
? _watchList.BinarySearch(w => w.Address, address)
|
|
: _watchList.FirstOrDefault(w => w.Address == address), 1);
|
|
|
|
return _compareTo switch
|
|
{
|
|
Compare.Previous => !ComparePrevious(listOfOne).Any(),
|
|
Compare.SpecificValue => !CompareSpecificValue(listOfOne).Any(),
|
|
Compare.SpecificAddress => !CompareSpecificAddress(listOfOne).Any(),
|
|
Compare.Changes => !CompareChanges(listOfOne).Any(),
|
|
Compare.Difference => !CompareDifference(listOfOne).Any(),
|
|
_ => !ComparePrevious(listOfOne).Any()
|
|
};
|
|
}
|
|
|
|
public int Count => _watchList.Count;
|
|
|
|
public SearchMode Mode => _settings.Mode;
|
|
|
|
public MemoryDomain Domain => _settings.Domain;
|
|
|
|
/// <exception cref="InvalidOperationException">(from setter) <see cref="Mode"/> is <see cref="SearchMode.Fast"/> and <paramref name="value"/> is not <see cref="Compare.Changes"/></exception>
|
|
public Compare CompareTo
|
|
{
|
|
get => _compareTo;
|
|
set
|
|
{
|
|
if (CanDoCompareType(value))
|
|
{
|
|
_compareTo = value;
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
}
|
|
|
|
public long? CompareValue { get; set; }
|
|
|
|
public ComparisonOperator Operator { get; set; }
|
|
|
|
// zero 07-sep-2014 - this isn't ideal. but don't bother changing it (to a long, for instance) until it can support floats. maybe store it as a double here.
|
|
public int? DifferentBy { get; set; }
|
|
|
|
public void Update()
|
|
{
|
|
if (_settings.IsDetailed())
|
|
{
|
|
foreach (IMiniWatchDetails watch in _watchList)
|
|
{
|
|
watch.Update(_settings.PreviousType, _settings.Domain, _settings.BigEndian);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetType(DisplayType type) => _settings.Type = type;
|
|
|
|
public void SetEndian(bool bigEndian) => _settings.BigEndian = bigEndian;
|
|
|
|
/// <exception cref="InvalidOperationException"><see cref="Mode"/> is <see cref="SearchMode.Fast"/> and <paramref name="type"/> is <see cref="PreviousType.LastFrame"/></exception>
|
|
public void SetPreviousType(PreviousType type)
|
|
{
|
|
if (_settings.IsFastMode() && type == PreviousType.LastFrame)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
_settings.PreviousType = type;
|
|
}
|
|
|
|
public void SetPreviousToCurrent()
|
|
{
|
|
_watchList.ForEach(w => w.SetPreviousToCurrent(_settings.Domain, _settings.BigEndian));
|
|
}
|
|
|
|
public void ClearChangeCounts()
|
|
{
|
|
if (_settings.IsDetailed())
|
|
{
|
|
foreach (var watch in _watchList.Cast<IMiniWatchDetails>())
|
|
{
|
|
watch.ClearChangeCount();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a set of watches
|
|
/// However, this should not be used with large data sets (100k or more) as it uses a contains logic to perform the task
|
|
/// </summary>
|
|
public void RemoveSmallWatchRange(IEnumerable<Watch> watches)
|
|
{
|
|
if (UndoEnabled)
|
|
{
|
|
_history.AddState(_watchList);
|
|
}
|
|
|
|
var addresses = watches.Select(w => w.Address);
|
|
_watchList.RemoveAll(w => addresses.Contains(w.Address));
|
|
}
|
|
|
|
public void RemoveRange(IEnumerable<int> indices)
|
|
{
|
|
if (UndoEnabled)
|
|
{
|
|
_history.AddState(_watchList);
|
|
}
|
|
|
|
var removeList = indices.Select(i => _watchList[i]); // This will fail after int.MaxValue but RAM Search fails on domains that large anyway
|
|
_watchList = _watchList.Except(removeList).ToList();
|
|
}
|
|
|
|
public void AddRange(IEnumerable<long> addresses, bool append)
|
|
{
|
|
if (!append)
|
|
{
|
|
_watchList.Clear();
|
|
}
|
|
|
|
var list = _settings.Size switch
|
|
{
|
|
WatchSize.Byte => addresses.ToBytes(_settings),
|
|
WatchSize.Word => addresses.ToWords(_settings),
|
|
WatchSize.DWord => addresses.ToDWords(_settings),
|
|
_ => addresses.ToBytes(_settings)
|
|
};
|
|
|
|
_watchList.AddRange(list);
|
|
}
|
|
|
|
public void Sort(string column, bool reverse)
|
|
{
|
|
_isSorted = column == WatchList.Address && !reverse;
|
|
switch (column)
|
|
{
|
|
case WatchList.Address:
|
|
_watchList = _watchList.OrderBy(w => w.Address, reverse).ToList();
|
|
break;
|
|
case WatchList.Value:
|
|
_watchList = _watchList.OrderBy(w => GetValue(w.Address), reverse).ToList();
|
|
break;
|
|
case WatchList.Prev:
|
|
_watchList = _watchList.OrderBy(w => w.Previous, reverse).ToList();
|
|
break;
|
|
case WatchList.ChangesCol:
|
|
if (_settings.IsDetailed())
|
|
{
|
|
_watchList = _watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.OrderBy(w => w.ChangeCount, reverse)
|
|
.Cast<IMiniWatch>()
|
|
.ToList();
|
|
}
|
|
|
|
break;
|
|
case WatchList.Diff:
|
|
_watchList = _watchList.OrderBy(w => GetValue(w.Address) - w.Previous, reverse).ToList();
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Undo API
|
|
|
|
public bool UndoEnabled { get; set; }
|
|
|
|
|
|
public bool CanUndo => UndoEnabled && _history.CanUndo;
|
|
|
|
public bool CanRedo => UndoEnabled && _history.CanRedo;
|
|
|
|
public void ClearHistory() => _history.Clear();
|
|
|
|
public int Undo()
|
|
{
|
|
int origCount = _watchList.Count;
|
|
if (UndoEnabled)
|
|
{
|
|
_watchList = _history.Undo().ToList();
|
|
return _watchList.Count - origCount;
|
|
}
|
|
|
|
return _watchList.Count;
|
|
}
|
|
|
|
public int Redo()
|
|
{
|
|
int origCount = _watchList.Count;
|
|
if (UndoEnabled)
|
|
{
|
|
_watchList = _history.Redo().ToList();
|
|
return origCount - _watchList.Count;
|
|
}
|
|
|
|
return _watchList.Count;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Comparisons
|
|
|
|
private IEnumerable<IMiniWatch> ComparePrevious(IEnumerable<IMiniWatch> watchList)
|
|
{
|
|
switch (Operator)
|
|
{
|
|
default:
|
|
case ComparisonOperator.Equal:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat().HawkFloatEquality(w.Previous.ToFloat()))
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) == SignExtendAsNeeded(w.Previous));
|
|
case ComparisonOperator.NotEqual:
|
|
return watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) != SignExtendAsNeeded(w.Previous));
|
|
case ComparisonOperator.GreaterThan:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() > w.Previous.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) > SignExtendAsNeeded(w.Previous));
|
|
case ComparisonOperator.GreaterThanEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() >= w.Previous.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) >= SignExtendAsNeeded(w.Previous));
|
|
|
|
case ComparisonOperator.LessThan:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() < w.Previous.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) < SignExtendAsNeeded(w.Previous));
|
|
case ComparisonOperator.LessThanEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() <= w.Previous.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) <= SignExtendAsNeeded(w.Previous));
|
|
case ComparisonOperator.DifferentBy:
|
|
if (DifferentBy.HasValue)
|
|
{
|
|
var differentBy = DifferentBy.Value;
|
|
if (_settings.Type == DisplayType.Float)
|
|
{
|
|
return watchList.Where(w => (GetValue(w.Address).ToFloat() + differentBy).HawkFloatEquality(w.Previous.ToFloat())
|
|
|| (GetValue(w.Address).ToFloat() - differentBy).HawkFloatEquality(w.Previous.ToFloat()));
|
|
}
|
|
|
|
return watchList.Where(w =>
|
|
{
|
|
long val = SignExtendAsNeeded(GetValue(w.Address));
|
|
long prev = SignExtendAsNeeded(w.Previous);
|
|
return val + differentBy == prev
|
|
|| val - differentBy == prev;
|
|
});
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerable<IMiniWatch> CompareSpecificValue(IEnumerable<IMiniWatch> watchList)
|
|
{
|
|
if (CompareValue.HasValue)
|
|
{
|
|
var compareValue = CompareValue.Value;
|
|
switch (Operator)
|
|
{
|
|
default:
|
|
case ComparisonOperator.Equal:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat().HawkFloatEquality(compareValue.ToFloat()))
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) == SignExtendAsNeeded(compareValue));
|
|
case ComparisonOperator.NotEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => !GetValue(w.Address).ToFloat().HawkFloatEquality(compareValue.ToFloat()))
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) != SignExtendAsNeeded(compareValue));
|
|
case ComparisonOperator.GreaterThan:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() > compareValue.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) > SignExtendAsNeeded(compareValue));
|
|
case ComparisonOperator.GreaterThanEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() >= compareValue.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) >= SignExtendAsNeeded(compareValue));
|
|
case ComparisonOperator.LessThan:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() < compareValue.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) < SignExtendAsNeeded(compareValue));
|
|
|
|
case ComparisonOperator.LessThanEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() <= compareValue.ToFloat())
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) <= SignExtendAsNeeded(compareValue));
|
|
|
|
case ComparisonOperator.DifferentBy:
|
|
if (DifferentBy.HasValue)
|
|
{
|
|
var differentBy = DifferentBy.Value;
|
|
if (_settings.Type == DisplayType.Float)
|
|
{
|
|
return watchList.Where(w => (GetValue(w.Address).ToFloat() + differentBy).HawkFloatEquality(compareValue)
|
|
|| (GetValue(w.Address).ToFloat() - differentBy).HawkFloatEquality(compareValue));
|
|
}
|
|
|
|
return watchList.Where(w
|
|
=> SignExtendAsNeeded(GetValue(w.Address)) + differentBy == compareValue
|
|
|| SignExtendAsNeeded(GetValue(w.Address)) - differentBy == compareValue);
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
private IEnumerable<IMiniWatch> CompareSpecificAddress(IEnumerable<IMiniWatch> watchList)
|
|
{
|
|
if (CompareValue.HasValue)
|
|
{
|
|
var compareValue = CompareValue.Value;
|
|
switch (Operator)
|
|
{
|
|
default:
|
|
case ComparisonOperator.Equal:
|
|
return watchList.Where(w => w.Address == compareValue);
|
|
case ComparisonOperator.NotEqual:
|
|
return watchList.Where(w => w.Address != compareValue);
|
|
case ComparisonOperator.GreaterThan:
|
|
return watchList.Where(w => w.Address > compareValue);
|
|
case ComparisonOperator.GreaterThanEqual:
|
|
return watchList.Where(w => w.Address >= compareValue);
|
|
case ComparisonOperator.LessThan:
|
|
return watchList.Where(w => w.Address < compareValue);
|
|
case ComparisonOperator.LessThanEqual:
|
|
return watchList.Where(w => w.Address <= compareValue);
|
|
case ComparisonOperator.DifferentBy:
|
|
if (DifferentBy.HasValue)
|
|
{
|
|
return watchList.Where(w => w.Address + DifferentBy.Value == compareValue
|
|
|| w.Address - DifferentBy.Value == compareValue);
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
private IEnumerable<IMiniWatch> CompareChanges(IEnumerable<IMiniWatch> watchList)
|
|
{
|
|
if (_settings.IsDetailed() && CompareValue.HasValue)
|
|
{
|
|
var compareValue = CompareValue.Value;
|
|
switch (Operator)
|
|
{
|
|
default:
|
|
case ComparisonOperator.Equal:
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount == compareValue);
|
|
case ComparisonOperator.NotEqual:
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount != compareValue);
|
|
case ComparisonOperator.GreaterThan:
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount > compareValue);
|
|
case ComparisonOperator.GreaterThanEqual:
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount >= compareValue);
|
|
case ComparisonOperator.LessThan:
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount < compareValue);
|
|
case ComparisonOperator.LessThanEqual:
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount <= compareValue);
|
|
case ComparisonOperator.DifferentBy:
|
|
if (DifferentBy.HasValue)
|
|
{
|
|
return watchList
|
|
.Cast<IMiniWatchDetails>()
|
|
.Where(w => w.ChangeCount + DifferentBy.Value == compareValue
|
|
|| w.ChangeCount - DifferentBy.Value == compareValue);
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
|
|
throw new InvalidCastException();
|
|
}
|
|
|
|
private IEnumerable<IMiniWatch> CompareDifference(IEnumerable<IMiniWatch> watchList)
|
|
{
|
|
if (CompareValue.HasValue)
|
|
{
|
|
var compareValue = CompareValue.Value;
|
|
switch (Operator)
|
|
{
|
|
default:
|
|
case ComparisonOperator.Equal:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => (GetValue(w.Address).ToFloat() - w.Previous.ToFloat()).HawkFloatEquality(compareValue))
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) == compareValue);
|
|
case ComparisonOperator.NotEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => !(GetValue(w.Address).ToFloat() - w.Previous.ToFloat()).HawkFloatEquality(compareValue))
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) != compareValue);
|
|
case ComparisonOperator.GreaterThan:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() - w.Previous.ToFloat() > compareValue)
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) > compareValue);
|
|
case ComparisonOperator.GreaterThanEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() - w.Previous.ToFloat() >= compareValue)
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) >= compareValue);
|
|
case ComparisonOperator.LessThan:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() - w.Previous.ToFloat() < compareValue)
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) < compareValue);
|
|
case ComparisonOperator.LessThanEqual:
|
|
return _settings.Type == DisplayType.Float
|
|
? watchList.Where(w => GetValue(w.Address).ToFloat() - w.Previous.ToFloat() <= compareValue)
|
|
: watchList.Where(w => SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) <= compareValue);
|
|
case ComparisonOperator.DifferentBy:
|
|
if (DifferentBy.HasValue)
|
|
{
|
|
var differentBy = DifferentBy.Value;
|
|
if (_settings.Type == DisplayType.Float)
|
|
{
|
|
return watchList.Where(w => (GetValue(w.Address).ToFloat() - w.Previous.ToFloat() + differentBy).HawkFloatEquality(compareValue)
|
|
|| (GetValue(w.Address).ToFloat() - w.Previous.ToFloat() - differentBy).HawkFloatEquality(w.Previous));
|
|
}
|
|
|
|
return watchList.Where(w
|
|
=> SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) + differentBy == compareValue
|
|
|| SignExtendAsNeeded(GetValue(w.Address)) - SignExtendAsNeeded(w.Previous) - differentBy == compareValue);
|
|
}
|
|
|
|
throw new InvalidOperationException();
|
|
}
|
|
}
|
|
|
|
throw new InvalidCastException();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private long SignExtendAsNeeded(long val)
|
|
{
|
|
if (_settings.Type != DisplayType.Signed)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
return _settings.Size switch
|
|
{
|
|
WatchSize.Byte => (sbyte) val,
|
|
WatchSize.Word => (short) val,
|
|
WatchSize.DWord => (int) val,
|
|
_ => (sbyte) val
|
|
};
|
|
}
|
|
|
|
private long GetValue(long addr)
|
|
{
|
|
// do not return sign extended variables from here.
|
|
return _settings.Size switch
|
|
{
|
|
WatchSize.Byte => _settings.Domain.PeekByte(addr % Domain.Size),
|
|
WatchSize.Word => _settings.Domain.PeekUshort(addr % Domain.Size, _settings.BigEndian),
|
|
WatchSize.DWord => _settings.Domain.PeekUint(addr % Domain.Size, _settings.BigEndian),
|
|
_ => _settings.Domain.PeekByte(addr % Domain.Size)
|
|
};
|
|
}
|
|
|
|
private bool CanDoCompareType(Compare compareType)
|
|
{
|
|
return _settings.Mode switch
|
|
{
|
|
SearchMode.Detailed => true,
|
|
SearchMode.Fast => (compareType != Compare.Changes),
|
|
_ => true
|
|
};
|
|
}
|
|
}
|
|
}
|