2015-12-01 21:16:28 +00:00
|
|
|
|
using System;
|
2015-11-26 22:05:29 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
using BizHawk.Common.NumberExtensions;
|
|
|
|
|
using BizHawk.Common.StringExtensions;
|
|
|
|
|
using BizHawk.Emulation.Common;
|
|
|
|
|
|
2015-11-26 22:05:29 +00:00
|
|
|
|
namespace BizHawk.Client.Common
|
|
|
|
|
{
|
2015-12-01 21:16:28 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// This class holds a word (16 bits) <see cref="Watch"/>
|
|
|
|
|
/// </summary>
|
2015-11-26 22:05:29 +00:00
|
|
|
|
public sealed class WordWatch : Watch
|
|
|
|
|
{
|
2015-11-28 21:47:16 +00:00
|
|
|
|
#region Fields
|
|
|
|
|
|
2015-11-26 22:05:29 +00:00
|
|
|
|
private ushort _previous;
|
|
|
|
|
private ushort _value;
|
|
|
|
|
|
2015-11-28 21:47:16 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region cTor(s)
|
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Inialize a new instance of <see cref="WordWatch"/>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="domain"><see cref="MemoryDomain"/> where you want to track</param>
|
|
|
|
|
/// <param name="address">The address you want to track</param>
|
|
|
|
|
/// <param name="type">How you you want to display the value See <see cref="DisplayType"/></param>
|
|
|
|
|
/// <param name="bigEndian">Specify the endianess. true for big endian</param>
|
|
|
|
|
/// <param name="note">A custom note about the <see cref="Watch"/></param>
|
|
|
|
|
/// <param name="value">Current value</param>
|
|
|
|
|
/// <param name="previous">Previous value</param>
|
|
|
|
|
/// <param name="changeCount">How many times value has changed</param>
|
|
|
|
|
/// <exception cref="ArgumentException">Occurs when a <see cref="DisplayType"/> is incompatible with <see cref="WatchSize.Word"/></exception>
|
2015-11-28 21:47:16 +00:00
|
|
|
|
internal WordWatch(MemoryDomain domain, long address, DisplayType type, bool bigEndian, string note, ushort value, ushort previous, int changeCount)
|
|
|
|
|
: base(domain, address, WatchSize.Word, type, bigEndian, note)
|
2015-11-26 22:05:29 +00:00
|
|
|
|
{
|
2015-12-09 23:33:43 +00:00
|
|
|
|
if (value == 0)
|
|
|
|
|
{
|
2015-12-04 13:10:04 +00:00
|
|
|
|
this._value = GetWord();
|
2015-12-09 23:33:43 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this._value = value;
|
|
|
|
|
}
|
2015-11-28 21:47:16 +00:00
|
|
|
|
this._previous = previous;
|
|
|
|
|
this._changecount = changeCount;
|
|
|
|
|
}
|
2015-11-26 22:05:29 +00:00
|
|
|
|
|
2015-11-28 21:47:16 +00:00
|
|
|
|
#endregion
|
2015-11-26 22:05:29 +00:00
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
#region Methods
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Enumerate wich <see cref="DisplayType"/> are valid for a <see cref="WordWatch"/>
|
|
|
|
|
/// </summary>
|
2015-11-28 21:47:16 +00:00
|
|
|
|
public static IEnumerable<DisplayType> ValidTypes
|
|
|
|
|
{
|
|
|
|
|
get
|
2015-11-26 22:05:29 +00:00
|
|
|
|
{
|
2015-11-28 21:47:16 +00:00
|
|
|
|
yield return DisplayType.Unsigned;
|
|
|
|
|
yield return DisplayType.Signed;
|
|
|
|
|
yield return DisplayType.Hex;
|
|
|
|
|
yield return DisplayType.Binary;
|
|
|
|
|
yield return DisplayType.FixedPoint_12_4;
|
2015-11-26 22:05:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
#region Implements
|
2015-11-26 22:05:29 +00:00
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a list a <see cref="DisplayType"/> that can be used for this <see cref="WordWatch"/>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>An enumartion that contains all valid <see cref="DisplayType"/></returns>
|
|
|
|
|
public override IEnumerable<DisplayType> AvailableTypes()
|
2015-11-26 22:05:29 +00:00
|
|
|
|
{
|
2015-12-01 21:16:28 +00:00
|
|
|
|
return ValidTypes;
|
2015-11-26 22:05:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reset the previous value; set it to the current one
|
|
|
|
|
/// </summary>
|
2015-11-26 22:05:29 +00:00
|
|
|
|
public override void ResetPrevious()
|
|
|
|
|
{
|
|
|
|
|
_previous = GetWord();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Try to sets the value into the <see cref="MemoryDomain"/>
|
|
|
|
|
/// at the current <see cref="Watch"/> address
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="value">Value to set</param>
|
|
|
|
|
/// <returns>True if value successfully sets; othewise, false</returns>
|
2015-11-26 22:05:29 +00:00
|
|
|
|
public override bool Poke(string value)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ushort val = 0;
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
case DisplayType.Unsigned:
|
|
|
|
|
if (value.IsUnsigned())
|
|
|
|
|
{
|
|
|
|
|
val = (ushort)int.Parse(value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case DisplayType.Signed:
|
|
|
|
|
if (value.IsSigned())
|
|
|
|
|
{
|
|
|
|
|
val = (ushort)(short)int.Parse(value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case DisplayType.Hex:
|
|
|
|
|
if (value.IsHex())
|
|
|
|
|
{
|
|
|
|
|
val = (ushort)int.Parse(value, NumberStyles.HexNumber);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case DisplayType.Binary:
|
|
|
|
|
if (value.IsBinary())
|
|
|
|
|
{
|
|
|
|
|
val = (ushort)Convert.ToInt32(value, 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case DisplayType.FixedPoint_12_4:
|
|
|
|
|
if (value.IsFixedPoint())
|
|
|
|
|
{
|
|
|
|
|
val = (ushort)(double.Parse(value) * 16.0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Global.CheatList.Contains(Domain, _address))
|
|
|
|
|
{
|
|
|
|
|
var cheat = Global.CheatList.FirstOrDefault(c => c.Address == _address && c.Domain == Domain);
|
|
|
|
|
if (cheat != (Cheat)null)
|
|
|
|
|
{
|
|
|
|
|
cheat.PokeValue(val);
|
|
|
|
|
PokeWord(val);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PokeWord(val);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-01 21:16:28 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Update the Watch (read it from <see cref="MemoryDomain"/>
|
|
|
|
|
/// </summary>
|
2015-11-26 22:05:29 +00:00
|
|
|
|
public override void Update()
|
|
|
|
|
{
|
|
|
|
|
switch (Global.Config.RamWatchDefinePrevious)
|
|
|
|
|
{
|
|
|
|
|
case PreviousType.Original:
|
|
|
|
|
return;
|
|
|
|
|
case PreviousType.LastChange:
|
|
|
|
|
var temp = _value;
|
|
|
|
|
_value = GetWord();
|
|
|
|
|
|
|
|
|
|
if (_value != temp)
|
|
|
|
|
{
|
|
|
|
|
_previous = temp;
|
|
|
|
|
_changecount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case PreviousType.LastFrame:
|
|
|
|
|
_previous = _value;
|
|
|
|
|
_value = GetWord();
|
|
|
|
|
if (_value != Previous)
|
|
|
|
|
{
|
|
|
|
|
_changecount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-01 21:16:28 +00:00
|
|
|
|
|
|
|
|
|
#endregion Implements
|
|
|
|
|
|
|
|
|
|
//TODO: Implements IFormattable
|
|
|
|
|
public string FormatValue(ushort val)
|
|
|
|
|
{
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
case DisplayType.Unsigned:
|
|
|
|
|
return val.ToString();
|
|
|
|
|
case DisplayType.Signed:
|
|
|
|
|
return ((short)val).ToString();
|
|
|
|
|
case DisplayType.Hex:
|
|
|
|
|
return val.ToHexString(4);
|
|
|
|
|
case DisplayType.FixedPoint_12_4:
|
|
|
|
|
return string.Format("{0:F4}", val / 16.0);
|
|
|
|
|
case DisplayType.Binary:
|
|
|
|
|
return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
#region Implements
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a string representation of difference
|
|
|
|
|
/// between current value and the previous one
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override string Diff
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-10-06 01:58:26 +00:00
|
|
|
|
string diff = string.Empty;
|
|
|
|
|
int diffVal = _value - _previous;
|
|
|
|
|
if (diffVal > 0)
|
|
|
|
|
{
|
|
|
|
|
diff = "+";
|
|
|
|
|
}
|
|
|
|
|
else if (diffVal < 0)
|
|
|
|
|
{
|
|
|
|
|
diff = "-";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Format("{0}{1}", diff, FormatValue((ushort)Math.Abs(diffVal)));
|
2015-12-01 21:16:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the maximum possible value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override uint MaxValue
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return ushort.MaxValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the current value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override int Value
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return GetWord();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the current value
|
|
|
|
|
/// but with stuff I don't understand
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override int ValueNoFreeze
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return GetWord(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a string representation of the current value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override string ValueString
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return FormatValue(GetWord());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the previous value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override int Previous
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _previous;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a string representation of the previous value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override string PreviousStr
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return FormatValue(_previous);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Implements
|
|
|
|
|
|
|
|
|
|
#endregion
|
2015-11-26 22:05:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|