460 lines
9.3 KiB
C#
460 lines
9.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.MultiClient
|
|
{
|
|
public enum atype { BYTE, WORD, DWORD, SEPARATOR }; //TODO: more custom types too like 12.4 and 24.12 fixed point
|
|
public enum asigned { SIGNED, UNSIGNED, HEX };
|
|
|
|
/// <summary>
|
|
/// An object that represent a ram address and related properties
|
|
/// </summary>
|
|
public class Watch
|
|
{
|
|
public Watch()
|
|
{
|
|
address = 0;
|
|
value = 0;
|
|
type = atype.BYTE;
|
|
signed = asigned.UNSIGNED;
|
|
bigendian = true;
|
|
notes = "";
|
|
changecount = 0;
|
|
prev = 0;
|
|
}
|
|
|
|
public Watch(Watch w)
|
|
{
|
|
address = w.address;
|
|
value = w.value;
|
|
type = w.type;
|
|
signed = w.signed;
|
|
bigendian = w.bigendian;
|
|
notes = w.notes;
|
|
changecount = w.changecount;
|
|
prev = w.prev;
|
|
}
|
|
|
|
public Watch(int Address, int Value, atype Type, asigned Signed, bool BigEndian, string Notes)
|
|
{
|
|
address = Address;
|
|
value = Value;
|
|
type = Type;
|
|
signed = Signed;
|
|
bigendian = BigEndian;
|
|
notes = Notes;
|
|
changecount = 0;
|
|
prev = 0;
|
|
}
|
|
public int address { get; set; }
|
|
public int value { get; set; } //Current value
|
|
public int prev { get; set; }
|
|
public atype type { get; set; } //Address type (byte, word, dword, etc
|
|
public asigned signed { get; set; } //Signed/Unsigned?
|
|
public bool bigendian { get; set; }
|
|
public string notes { get; set; } //User notes
|
|
public int changecount { get; set; }
|
|
|
|
|
|
public bool SetTypeByChar(char c) //b = byte, w = word, d = dword
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'b':
|
|
type = atype.BYTE;
|
|
return true;
|
|
case 'w':
|
|
type = atype.WORD;
|
|
return true;
|
|
case 'd':
|
|
type = atype.DWORD;
|
|
return true;
|
|
case 'S':
|
|
type = atype.SEPARATOR;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public char GetTypeByChar()
|
|
{
|
|
switch (type)
|
|
{
|
|
case atype.BYTE:
|
|
return 'b';
|
|
case atype.WORD:
|
|
return 'w';
|
|
case atype.DWORD:
|
|
return 'd';
|
|
case atype.SEPARATOR:
|
|
return 'S';
|
|
default:
|
|
return 'b'; //Just in case
|
|
}
|
|
}
|
|
|
|
public bool SetSignedByChar(char c) //s = signed, u = unsigned, h = hex
|
|
{
|
|
switch (c)
|
|
{
|
|
case 's':
|
|
signed = asigned.SIGNED;
|
|
return true;
|
|
case 'u':
|
|
signed = asigned.UNSIGNED;
|
|
return true;
|
|
case 'h':
|
|
signed = asigned.HEX;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public char GetSignedByChar()
|
|
{
|
|
switch (signed)
|
|
{
|
|
case asigned.SIGNED:
|
|
return 's';
|
|
case asigned.UNSIGNED:
|
|
return 'u';
|
|
case asigned.HEX:
|
|
return 'h';
|
|
default:
|
|
return 's'; //Just in case
|
|
}
|
|
}
|
|
|
|
private void PeekByte(MemoryDomain domain)
|
|
{
|
|
value = domain.PeekByte(address);
|
|
}
|
|
|
|
private int PeekWord(MemoryDomain domain, int addr)
|
|
{
|
|
int temp = 0;
|
|
if (bigendian)
|
|
{
|
|
temp = ((domain.PeekByte(addr) * 256) +
|
|
domain.PeekByte(addr + 1));
|
|
}
|
|
else
|
|
{
|
|
temp = ((domain.PeekByte(addr) +
|
|
domain.PeekByte(addr + 1) * 256));
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
private void PeekDWord(MemoryDomain domain)
|
|
{
|
|
value = ((PeekWord(domain, address) * 65536) +
|
|
PeekWord(domain, address + 2));
|
|
}
|
|
|
|
public void PeekAddress(MemoryDomain domain)
|
|
{
|
|
if (type == atype.SEPARATOR)
|
|
return;
|
|
|
|
prev = value;
|
|
|
|
switch (type)
|
|
{
|
|
case atype.BYTE:
|
|
PeekByte(domain);
|
|
break;
|
|
case atype.WORD:
|
|
value = PeekWord(domain, address);
|
|
break;
|
|
case atype.DWORD:
|
|
PeekDWord(domain);
|
|
break;
|
|
}
|
|
|
|
if (value != prev)
|
|
changecount++;
|
|
}
|
|
|
|
private void PokeByte(MemoryDomain domain)
|
|
{
|
|
domain.PokeByte(address, (byte)value);
|
|
}
|
|
|
|
private void PokeWord(MemoryDomain domain)
|
|
{
|
|
if (bigendian)
|
|
{
|
|
domain.PokeByte(address, (byte)(value / 256));
|
|
domain.PokeByte(address + 1, (byte)(value % 256));
|
|
}
|
|
else
|
|
{
|
|
domain.PokeByte(address + 1, (byte)(value / 256));
|
|
domain.PokeByte(address, (byte)(value % 256));
|
|
}
|
|
}
|
|
|
|
private void PokeDWord(MemoryDomain domain)
|
|
{
|
|
if (bigendian)
|
|
{
|
|
domain.PokeByte(address, (byte)(value << 6));
|
|
domain.PokeByte(address + 1, (byte)(value << 4));
|
|
domain.PokeByte(address + 2, (byte)(value << 2));
|
|
domain.PokeByte(address + 3, (byte)(value));
|
|
}
|
|
else
|
|
{
|
|
domain.PokeByte(address + 1, (byte)(value << 6));
|
|
domain.PokeByte(address, (byte)(value << 4));
|
|
domain.PokeByte(address + 3, (byte)(value << 2));
|
|
domain.PokeByte(address + 2, (byte)(value));
|
|
}
|
|
}
|
|
|
|
public void PokeAddress(MemoryDomain domain)
|
|
{
|
|
if (type == atype.SEPARATOR)
|
|
return;
|
|
|
|
switch (type)
|
|
{
|
|
case atype.BYTE:
|
|
PokeByte(domain);
|
|
break;
|
|
case atype.WORD:
|
|
PokeWord(domain);
|
|
break;
|
|
case atype.DWORD:
|
|
PokeDWord(domain);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
if (type == atype.SEPARATOR)
|
|
return "----";
|
|
|
|
StringBuilder str = new StringBuilder(notes);
|
|
str.Append(": ");
|
|
str.Append(ValueToString());
|
|
return str.ToString();
|
|
}
|
|
|
|
public string ValueToString()
|
|
{
|
|
if (type == atype.SEPARATOR)
|
|
return "";
|
|
else
|
|
{
|
|
switch (signed)
|
|
{
|
|
case asigned.HEX:
|
|
switch (type)
|
|
{
|
|
default:
|
|
case atype.BYTE:
|
|
return String.Format("{0:X2}", value);
|
|
case atype.WORD:
|
|
return String.Format("{0:X4}", value);
|
|
case atype.DWORD:
|
|
return String.Format("{0:X8}", value);
|
|
}
|
|
case asigned.SIGNED:
|
|
return ((sbyte)value).ToString();
|
|
default:
|
|
case asigned.UNSIGNED:
|
|
return value.ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
public string PrevToString()
|
|
{
|
|
if (type == atype.SEPARATOR)
|
|
return "";
|
|
else
|
|
{
|
|
switch (signed)
|
|
{
|
|
case asigned.HEX:
|
|
switch (type)
|
|
{
|
|
default:
|
|
case atype.BYTE:
|
|
return String.Format("{0:X2}", prev);
|
|
case atype.WORD:
|
|
return String.Format("{0:X4}", prev);
|
|
case atype.DWORD:
|
|
return String.Format("{0:X8}", prev);
|
|
}
|
|
case asigned.SIGNED:
|
|
return ((sbyte)prev).ToString();
|
|
default:
|
|
case asigned.UNSIGNED:
|
|
return prev.ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
private int CompareAddress(Watch Other)
|
|
{
|
|
if (this.address < Other.address)
|
|
return -1;
|
|
else if (this.address > Other.address)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
private int CompareValue(Watch Other)
|
|
{
|
|
if (this.value < Other.value)
|
|
return -1;
|
|
else if (this.value > Other.value)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
private int ComparePrev(Watch Other)
|
|
{
|
|
if (this.prev < Other.prev)
|
|
return -1;
|
|
else if (this.prev > Other.prev)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
private int CompareChanges(Watch Other)
|
|
{
|
|
if (this.changecount < Other.changecount)
|
|
return -1;
|
|
else if (this.changecount > Other.changecount)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
private int CompareNotes(Watch Other)
|
|
{
|
|
if (this.notes == null & Other.notes == null)
|
|
return 0;
|
|
else if (this.notes == null)
|
|
return -1;
|
|
else if (Other.notes == null)
|
|
return 1;
|
|
else
|
|
return this.notes.CompareTo(Other.notes);
|
|
}
|
|
|
|
public int CompareTo(Watch Other, string parameter)
|
|
{
|
|
int compare = 0;
|
|
if (parameter == "Address")
|
|
{
|
|
compare = CompareAddress(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareValue(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareChanges(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = ComparePrev(Other);
|
|
if (compare == 0)
|
|
compare = CompareNotes(Other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (parameter == "Value")
|
|
{
|
|
compare = CompareValue(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareAddress(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareChanges(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = ComparePrev(Other);
|
|
if (compare == 0)
|
|
compare = CompareNotes(Other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (parameter == "Prev")
|
|
{
|
|
compare = ComparePrev(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareAddress(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareValue(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareChanges(Other);
|
|
if (compare == 0)
|
|
compare = CompareNotes(Other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (parameter == "Changes")
|
|
{
|
|
compare = CompareChanges(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareAddress(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareValue(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = ComparePrev(Other);
|
|
if (compare == 0)
|
|
compare = CompareNotes(Other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (parameter == "Notes")
|
|
{
|
|
compare = CompareNotes(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareAddress(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareValue(Other);
|
|
if (compare == 0)
|
|
{
|
|
compare = CompareChanges(Other);
|
|
if (compare == 0)
|
|
compare = ComparePrev(Other);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return compare;
|
|
}
|
|
}
|
|
}
|