Merge pull request #1 from Hathor86/NewrRelease

Newrrelease
This commit is contained in:
Hathor86 2015-10-11 19:55:39 +02:00
commit 10ed6514c9
76 changed files with 5305 additions and 4618 deletions

1
.gitignore vendored
View File

@ -246,6 +246,7 @@
/References/*.xml
/output/ELFSharp.dll
/output/dll/ELFSharp.dll
/output/GameTools/*.dll
*.opensdf
*.user
*.suo

View File

@ -672,7 +672,7 @@ namespace BizHawk.Client.Common
nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath);
break;
case "C64":
var c64 = new C64(nextComm, game, rom.RomData, rom.Extension);
var c64 = new C64(nextComm, game, rom.RomData, rom.Extension, GetCoreSettings<C64>(), GetCoreSyncSettings<C64>());
nextEmulator = c64;
break;
case "GBA":

View File

@ -157,8 +157,9 @@ namespace BizHawk.Client.Common
new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "Macros", Path = Path.Combine(".", "Movies", "Macros"), Ordinal = 10 },
new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "TAStudio states", Path = Path.Combine(".", "Movies", "TAStudio states"), Ordinal = 11 },
new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "Multi-Disk Bundles", Path = Path.Combine(".", "Tools"), Ordinal = 12 },
new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "GameTools", Path = Path.Combine(".", "GameTools"), Ordinal = 13 },
new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "Base", Path = Path.Combine(".", "Intellivision"), Ordinal = 0 },
new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "Base", Path = Path.Combine(".", "Intellivision"), Ordinal = 0 },
new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "ROM", Path = ".", Ordinal = 1 },
new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "Savestates", Path= Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "Save RAM", Path = Path.Combine(".", "SaveRAM"), Ordinal = 3 },

View File

@ -383,238 +383,139 @@ namespace BizHawk.Client.Common
private List<string> _justPressed = new List<string>();
}
/// SuuperW: I'm leaving the old class in case I accidentally screwed something up
/// adelikat: You did, the autofire feature this was controlling, putting it back, fix your class
public class AutoFireStickyXorAdapter : IController, ISticky
{
public int On { get; set; }
public int Off { get; set; }
public WorkingDictionary<string, int> buttonStarts = new WorkingDictionary<string, int>();
public WorkingDictionary<string, int> lagStarts = new WorkingDictionary<string, int>(); // TODO: need a data structure not misc dictionaries
private readonly HashSet<string> _stickySet = new HashSet<string>();
public IController Source { get; set; }
public void SetOnOffPatternFromConfig()
{
On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
}
public AutoFireStickyXorAdapter()
{
//On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
//Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
On = 1;
Off = 1;
}
public bool IsPressed(string button)
{
return this[button];
}
public bool this[string button]
{
get
{
var source = Source[button];
if (_stickySet.Contains(button))
{
var lagcount = 0;
if (Global.Emulator.CanPollInput() && Global.Config.AutofireLagFrames)
{
lagcount = Global.Emulator.AsInputPollable().LagCount;
}
var a = ((Global.Emulator.Frame - lagcount) - (buttonStarts[button] - lagStarts[button])) % (On + Off);
if (a < On)
{
return source ^= true;
}
else
{
return source ^= false;
}
}
return source;
}
set
{
throw new InvalidOperationException();
}
}
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
public bool Locked { get; set; } // Pretty much a hack,
// dumb passthrough for floats, because autofire doesn't care about them
public float GetFloat(string name)
{
return Source.GetFloat(name);
}
public void SetSticky(string button, bool isSticky)
{
if (isSticky)
{
_stickySet.Add(button);
buttonStarts.Add(button, Global.Emulator.Frame);
if (Global.Emulator.CanPollInput())
{
lagStarts.Add(button, Global.Emulator.AsInputPollable().LagCount);
}
else
{
lagStarts.Add(button, 0);
}
}
else
{
_stickySet.Remove(button);
buttonStarts.Remove(button);
lagStarts.Remove(button);
}
}
public bool IsSticky(string button)
{
return this._stickySet.Contains(button);
}
public HashSet<string> CurrentStickies
{
get
{
return this._stickySet;
}
}
public void ClearStickies()
{
_stickySet.Clear();
buttonStarts.Clear();
lagStarts.Clear();
}
public void MassToggleStickyState(List<string> buttons)
{
foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
{
if (_stickySet.Contains(button))
{
_stickySet.Remove(button);
}
else
{
_stickySet.Add(button);
}
}
_justPressed = buttons;
}
/// <summary>
/// Determines if a sticky is current mashing the button itself,
/// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
/// </summary>
public bool StickyIsInEffect(string button)
{
if (Source.IsPressed(button))
{
return false;
}
return (IsPressed(button)); // Shortcut logic since we know the Source isn't pressed, Ispressed can only return true if the autofire sticky is in effect for this frame
}
private List<string> _justPressed = new List<string>();
}
// commenting this out, it breaks the autofire hotkey
///// SuuperW: I'm leaving the old class in case I accidentally screwed something up
//public class AutoFireStickyXorAdapter : IController, ISticky
//{
// // TODO: Change the AutoHold adapter to be one of these, with an 'Off' value of 0?
// // Probably would have slightly lower performance, but it seems weird to have such a similar class that is only used once.
// private int On;
// private int Off;
// public int On { get; set; }
// public int Off { get; set; }
// public WorkingDictionary<string, int> buttonStarts = new WorkingDictionary<string, int>();
// public WorkingDictionary<string, int> lagStarts = new WorkingDictionary<string, int>(); // TODO: need a data structure not misc dictionaries
// private readonly HashSet<string> _stickySet = new HashSet<string>();
// public IController Source { get; set; }
// public void SetOnOffPatternFromConfig()
// {
// On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
// Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
// }
// private WorkingDictionary<string, AutoPatternBool> _boolPatterns = new WorkingDictionary<string, AutoPatternBool>();
// private WorkingDictionary<string, AutoPatternFloat> _floatPatterns = new WorkingDictionary<string, AutoPatternFloat>();
// public AutoFireStickyXorAdapter()
// {
// On = 1; Off = 1;
// //On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
// //Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
// On = 1;
// Off = 1;
// }
// public IController Source { get; set; }
// public ControllerDefinition Type
// {
// get { return Source.Type; }
// }
// public bool Locked { get; set; } // Pretty much a hack,
// public bool IsPressed(string button)
// {
// return this[button];
// }
// public void SetFloat(string name, float? value, AutoPatternFloat pattern = null)
// {
// if (value.HasValue)
// {
// if (pattern == null)
// pattern = new AutoPatternFloat(value.Value, On, 0, Off);
// _floatPatterns[name] = pattern;
// }
// else
// {
// _floatPatterns.Remove(name);
// }
// }
// public float GetFloat(string name)
// {
// if (_floatPatterns.ContainsKey(name))
// return _floatPatterns[name].PeekNextValue();
// if (Source == null)
// return 0;
// return Source.GetFloat(name);
// }
// public void ClearStickyFloats()
// {
// _floatPatterns.Clear();
// }
// public bool this[string button]
// {
// get
// {
// var source = Source[button];
// bool patternValue = false;
// if (_boolPatterns.ContainsKey(button))
// { // I can't figure a way to determine right here if it should Peek or Get.
// patternValue = _boolPatterns[button].PeekNextValue();
// if (_stickySet.Contains(button))
// {
// var lagcount = 0;
// if (Global.Emulator.CanPollInput() && Global.Config.AutofireLagFrames)
// {
// lagcount = Global.Emulator.AsInputPollable().LagCount;
// }
// var a = ((Global.Emulator.Frame - lagcount) - (buttonStarts[button] - lagStarts[button])) % (On + Off);
// if (a < On)
// {
// return source ^= true;
// }
// else
// {
// return source ^= false;
// }
// }
// source ^= patternValue;
// return source;
// }
// set
// {
// throw new InvalidOperationException();
// }
// }
// public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
// public bool Locked { get; set; } // Pretty much a hack,
// // dumb passthrough for floats, because autofire doesn't care about them
// public float GetFloat(string name)
// {
// return Source.GetFloat(name);
// }
// public void SetSticky(string button, bool isSticky)
// {
// if (isSticky)
// {
// _stickySet.Add(button);
// buttonStarts.Add(button, Global.Emulator.Frame);
// if (Global.Emulator.CanPollInput())
// {
// lagStarts.Add(button, Global.Emulator.AsInputPollable().LagCount);
// }
// else
// {
// lagStarts.Add(button, 0);
// }
// }
// else
// {
// _stickySet.Remove(button);
// buttonStarts.Remove(button);
// lagStarts.Remove(button);
// }
// }
// public bool IsSticky(string button)
// {
// return this._stickySet.Contains(button);
// }
// public HashSet<string> CurrentStickies
// {
// get
// {
// return this._stickySet;
// }
// }
// public void ClearStickies()
// {
// _stickySet.Clear();
// buttonStarts.Clear();
// lagStarts.Clear();
// }
// public void MassToggleStickyState(List<string> buttons)
// {
// foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
// {
// if (_stickySet.Contains(button))
// {
// _stickySet.Remove(button);
// }
// else
// {
// _stickySet.Add(button);
// }
// }
// _justPressed = buttons;
// }
// /// <summary>
@ -623,84 +524,174 @@ namespace BizHawk.Client.Common
// /// </summary>
// public bool StickyIsInEffect(string button)
// {
// if (IsSticky(button))
// if (Source.IsPressed(button))
// {
// return !Source.IsPressed(button);
// return false;
// }
// return false;
// return (IsPressed(button)); // Shortcut logic since we know the Source isn't pressed, Ispressed can only return true if the autofire sticky is in effect for this frame
// }
// public void SetSticky(string button, bool isSticky, AutoPatternBool pattern = null)
// {
// if (isSticky)
// {
// if (pattern == null)
// pattern = new AutoPatternBool(On, Off);
// _boolPatterns[button] = pattern;
// }
// else
// {
// _boolPatterns.Remove(button);
// }
// }
// public void Unset(string button)
// {
// _boolPatterns.Remove(button);
// _floatPatterns.Remove(button);
// }
// public bool IsSticky(string button)
// {
// return _boolPatterns.ContainsKey(button) || _floatPatterns.ContainsKey(button);
// }
// public HashSet<string> CurrentStickies
// {
// get
// {
// return new HashSet<string>(_boolPatterns.Keys);
// }
// }
// public void ClearStickies()
// {
// _boolPatterns.Clear();
// _floatPatterns.Clear();
// }
// public void IncrementLoops(bool lagged)
// {
// for (int i = 0; i < _boolPatterns.Count; i++)
// _boolPatterns.ElementAt(i).Value.GetNextValue(lagged);
// for (int i = 0; i < _floatPatterns.Count; i++)
// _floatPatterns.ElementAt(i).Value.GetNextValue(lagged);
// }
// // SuuperW: What does this even do? I set a breakpoint inside the loop and it wasn't reached.
// private WorkingDictionary<string, AutoPatternBool> _toggledButtons = new WorkingDictionary<string, AutoPatternBool>();
// private List<string> _justPressed = new List<string>();
// public void MassToggleStickyState(List<string> buttons)
// {
// foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
// {
// if (_boolPatterns.ContainsKey(button))
// {
// _toggledButtons[button] = _boolPatterns[button];
// SetSticky(button, false);
// }
// else
// {
// _boolPatterns[button] = _toggledButtons[button];
// _toggledButtons.Remove(button);
// }
// }
// _justPressed = buttons;
// }
//}
// commenting this out, it breaks the autofire hotkey
public class AutoFireStickyXorAdapter : IController, ISticky
{
// TODO: Change the AutoHold adapter to be one of these, with an 'Off' value of 0?
// Probably would have slightly lower performance, but it seems weird to have such a similar class that is only used once.
private int On;
private int Off;
public void SetOnOffPatternFromConfig()
{
On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
}
private WorkingDictionary<string, AutoPatternBool> _boolPatterns = new WorkingDictionary<string, AutoPatternBool>();
private WorkingDictionary<string, AutoPatternFloat> _floatPatterns = new WorkingDictionary<string, AutoPatternFloat>();
public AutoFireStickyXorAdapter()
{
On = 1; Off = 1;
}
public IController Source { get; set; }
public ControllerDefinition Type
{
get { return Source.Type; }
}
public bool Locked { get; set; } // Pretty much a hack,
public bool IsPressed(string button)
{
return this[button];
}
public void SetFloat(string name, float? value, AutoPatternFloat pattern = null)
{
if (value.HasValue)
{
if (pattern == null)
pattern = new AutoPatternFloat(value.Value, On, 0, Off);
_floatPatterns[name] = pattern;
}
else
{
_floatPatterns.Remove(name);
}
}
public float GetFloat(string name)
{
if (_floatPatterns.ContainsKey(name))
return _floatPatterns[name].PeekNextValue();
if (Source == null)
return 0;
return Source.GetFloat(name);
}
public void ClearStickyFloats()
{
_floatPatterns.Clear();
}
public bool this[string button]
{
get
{
var source = Source[button];
bool patternValue = false;
if (_boolPatterns.ContainsKey(button))
{ // I can't figure a way to determine right here if it should Peek or Get.
patternValue = _boolPatterns[button].PeekNextValue();
}
source ^= patternValue;
return source;
}
}
/// <summary>
/// Determines if a sticky is current mashing the button itself,
/// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
/// </summary>
public bool StickyIsInEffect(string button)
{
if (IsSticky(button))
{
return !Source.IsPressed(button);
}
return false;
}
public void SetSticky(string button, bool isSticky, AutoPatternBool pattern = null)
{
if (isSticky)
{
if (pattern == null)
pattern = new AutoPatternBool(On, Off);
_boolPatterns[button] = pattern;
}
else
{
_boolPatterns.Remove(button);
}
}
public void Unset(string button)
{
_boolPatterns.Remove(button);
_floatPatterns.Remove(button);
}
public bool IsSticky(string button)
{
return _boolPatterns.ContainsKey(button) || _floatPatterns.ContainsKey(button);
}
public HashSet<string> CurrentStickies
{
get
{
return new HashSet<string>(_boolPatterns.Keys);
}
}
public void ClearStickies()
{
_boolPatterns.Clear();
_floatPatterns.Clear();
}
public void IncrementLoops(bool lagged)
{
for (int i = 0; i < _boolPatterns.Count; i++)
_boolPatterns.ElementAt(i).Value.GetNextValue(lagged);
for (int i = 0; i < _floatPatterns.Count; i++)
_floatPatterns.ElementAt(i).Value.GetNextValue(lagged);
}
private List<string> _justPressed = new List<string>();
public void MassToggleStickyState(List<string> buttons)
{
foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
{
if (_boolPatterns.ContainsKey(button))
SetSticky(button, false);
else
SetSticky(button, true);
}
_justPressed = buttons;
}
}
/// <summary>
/// Just copies source to sink, or returns whatever a NullController would if it is disconnected. useful for immovable hardpoints.
/// </summary>

View File

@ -8,6 +8,12 @@ namespace BizHawk.Client.Common
// these are political numbers, designed to be in accord with tasvideos.org tradition. theyre not necessarily mathematical factualities (although they may be in some cases)
// it would be nice if we could turn this into a rational expression natively, and also, to write some comments about the derivation and ideal valees (since this seems to be where theyre all collected)
// are we collecting them anywhere else? for avi-writing code perhaps?
// just some constants, according to specs
private static readonly double PAL_CARRIER = 15625 * 283.75 + 25; // 4.43361875 MHz
private static readonly double NTSC_CARRIER = 4500000 * 227.5 / 286; // 3.579545454... MHz
private static readonly double PAL_N_CARRIER = 15625 * 229.25 + 25; // 3.58205625 MHz
private static readonly Dictionary<string, double> _rates = new Dictionary<string, double>
{
{ "NES", 60.098813897440515532 }, // discussion here: http://forums.nesdev.com/viewtopic.php?t=492 ; a rational expression would be (19687500 / 11) / ((341*262-0.529780.5)/3) -> (118125000 / 1965513) -> 60.098813897440515529533511098629 (so our chosen number is very close)
@ -48,6 +54,11 @@ namespace BizHawk.Client.Common
{"PSX", 44100.0*768*11/7/263/3413}, //59.292862562
{"PSX_PAL", 44100.0*768*11/7/314/3406}, //49.7645593576
{"C64_PAL", PAL_CARRIER*2/9/312/63},
{"C64_NTSC", NTSC_CARRIER*2/7/263/65},
{"C64_NTSC_OLD", NTSC_CARRIER*2/7/262/64},
{"C64_DREAN", PAL_N_CARRIER*2/7/312/65},
//according to ryphecha, using
//clocks[2] = { 53.693182e06, 53.203425e06 }; //ntsc console, pal console
//lpf[2][2] = { { 263, 262.5 }, { 314, 312.5 } }; //ntsc,pal; noninterlaced, interlaced

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
namespace BizHawk.Client.Common
{
@ -15,6 +16,20 @@ namespace BizHawk.Client.Common
public int Frame { get; set; }
public void Write(BinaryWriter w)
{
w.Write(Frame);
w.Write(_state.Length);
w.Write(_state);
}
public static StateManagerState Read(BinaryReader r, TasStateManager m)
{
int frame = r.ReadInt32();
byte[] data = r.ReadBytes(r.ReadInt32());
return new StateManagerState(m, data, frame);
}
public byte[] State
{
get

View File

@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using BizHawk.Bizware.BizwareGL;
@ -22,6 +23,19 @@ namespace BizHawk.Client.Common
public class TasBranchCollection : List<TasBranch>
{
public new void Add(TasBranch item)
{
if (item.UniqueIdentifier == Guid.Empty)
{
var currentHashes = this.Select(b => b.UniqueIdentifier.GetHashCode()).ToList();
do item.UniqueIdentifier = Guid.NewGuid();
while (currentHashes.Contains(item.UniqueIdentifier.GetHashCode()));
}
base.Add(item);
}
public void Save(BinaryStateSaver bs)
{
var nheader = new IndexedStateLump(BinaryStateLump.BranchHeader);

View File

@ -22,7 +22,7 @@ namespace BizHawk.Client.Common
private readonly Dictionary<int, IController> InputStateCache = new Dictionary<int, IController>();
public readonly List<string> VerificationLog = new List<string>(); // For movies that do not begin with power-on, this is the input required to get into the initial state
private readonly TasBranchCollection Branches = new TasBranchCollection();
public readonly TasBranchCollection Branches = new TasBranchCollection();
private BackgroundWorker _progressReportWorker = null;
public void NewBGWorker(BackgroundWorker newWorker)
@ -82,8 +82,21 @@ namespace BizHawk.Client.Common
public bool BindMarkersToInput { get; set; }
public bool UseInputCache { get; set; }
public int BranchCount { get { return Branches.Count; } }
public TasBranch GetBranch(int index) { return Branches[index]; }
public int BranchHashByIndex(int index) { return Branches[index].UniqueIdentifier.GetHashCode(); }
public TasBranch GetBranch(int index)
{
if (index >= Branches.Count)
return null; // are we allowed?
else
return Branches[index];
}
public int BranchHashByIndex(int index)
{
if (index >= Branches.Count)
return -1;
else
return Branches[index].UniqueIdentifier.GetHashCode();
}
public int BranchIndexByHash(int hash)
{
@ -524,12 +537,6 @@ namespace BizHawk.Client.Common
public void AddBranch(TasBranch branch)
{
// before adding, make sure guid hash is unique too, we can't afford branch id clashes
do
{
branch.UniqueIdentifier = Guid.NewGuid();
} while (BranchIndexByHash(branch.UniqueIdentifier.GetHashCode()) != -1);
Branches.Add(branch);
TasStateManager.AddBranch();
Changes = true;
@ -545,6 +552,7 @@ namespace BizHawk.Client.Common
public void UpdateBranch(TasBranch old, TasBranch newBranch)
{
int index = Branches.IndexOf(old);
newBranch.UniqueIdentifier = old.UniqueIdentifier;
Branches[index] = newBranch;
TasStateManager.UpdateBranch(index);
Changes = true;

View File

@ -218,6 +218,8 @@ namespace BizHawk.Client.Common
{
if (this[i].Frame >= startFrame)
{
if (i == 0)
continue;
_movie.ChangeLog.AddMarkerChange(null, this[i].Frame, this[i].Message);
RemoveAt(i);
deletedCount++;

View File

@ -221,11 +221,20 @@ namespace BizHawk.Client.Common
/// </summary>
private Point StateToRemove()
{
int markerSkips = maxStates / 2;
// X is frame, Y is branch
Point shouldRemove = new Point(-1, -1);
if (BranchStates.Any() && Settings.EraseBranchStatesFirst)
{
var kvp = BranchStates.Count() > 1 ? BranchStates.ElementAt(1) : BranchStates.ElementAt(0);
shouldRemove.X = kvp.Key;
shouldRemove.Y = kvp.Value.Keys[0];
return shouldRemove;
}
int i = 0;
int markerSkips = maxStates / 2;
// lowPrioritySates (e.g. states with only lag frames between them)
do
{
@ -263,9 +272,9 @@ namespace BizHawk.Client.Common
if (shouldRemove.X < 1) // only found marker states above
{
if (BranchStates.Any())
if (BranchStates.Any() && !Settings.EraseBranchStatesFirst)
{
var kvp = BranchStates.ElementAt(1);
var kvp = BranchStates.Count() > 1 ? BranchStates.ElementAt(1) : BranchStates.ElementAt(0);
shouldRemove.X = kvp.Key;
shouldRemove.Y = kvp.Value.Keys[0];
}
@ -289,7 +298,7 @@ namespace BizHawk.Client.Common
return _movie.Markers.IsMarker(States[frame].Frame + 1);
else
{
if (_movie.GetBranch(branch).Markers == null)
if (_movie.GetBranch(_movie.BranchIndexByHash(branch)).Markers == null)
return _movie.Markers.IsMarker(States[frame].Frame + 1);
else
return _movie.GetBranch(branch).Markers.Any(m => m.Frame + 1 == frame);
@ -356,7 +365,7 @@ namespace BizHawk.Client.Common
{
if (branch == -1)
accessed.Remove(States[frame]);
else
else if (accessed.Contains(BranchStates[frame][branch]) && !Settings.EraseBranchStatesFirst)
accessed.Remove(BranchStates[frame][branch]);
StateManagerState state;
@ -503,25 +512,6 @@ namespace BizHawk.Client.Common
MaybeRemoveStates();
}
// TODO: save/load BranchStates
public void Save(BinaryWriter bw)
{
List<int> noSave = ExcludeStates();
bw.Write(States.Count - noSave.Count);
for (int i = 0; i < States.Count; i++)
{
if (noSave.Contains(i))
continue;
StateAccessed(States.ElementAt(i).Key);
KeyValuePair<int, StateManagerState> kvp = States.ElementAt(i);
bw.Write(kvp.Key);
bw.Write(kvp.Value.Length);
bw.Write(kvp.Value.State);
}
}
private List<int> ExcludeStates()
{
List<int> ret = new List<int>();
@ -556,6 +546,41 @@ namespace BizHawk.Client.Common
return ret;
}
public void Save(BinaryWriter bw)
{
List<int> noSave = ExcludeStates();
bw.Write(States.Count - noSave.Count);
for (int i = 0; i < States.Count; i++)
{
if (noSave.Contains(i))
continue;
StateAccessed(States.ElementAt(i).Key);
KeyValuePair<int, StateManagerState> kvp = States.ElementAt(i);
bw.Write(kvp.Key);
bw.Write(kvp.Value.Length);
bw.Write(kvp.Value.State);
}
bw.Write(currentBranch);
if (Settings.BranchStatesInTasproj)
{
bw.Write(BranchStates.Count);
foreach (var s in BranchStates)
{
bw.Write(s.Key);
bw.Write(s.Value.Count);
foreach (var t in s.Value)
{
bw.Write(t.Key);
t.Value.Write(bw);
}
}
}
}
public void Load(BinaryReader br)
{
States.Clear();
@ -574,6 +599,32 @@ namespace BizHawk.Client.Common
//Used += len;
}
//}
try
{
currentBranch = br.ReadInt32();
if (Settings.BranchStatesInTasproj)
{
int c = br.ReadInt32();
BranchStates = new SortedList<int, SortedList<int, StateManagerState>>(c);
while (c > 0)
{
int key = br.ReadInt32();
int c2 = br.ReadInt32();
var list = new SortedList<int, StateManagerState>(c2);
while (c2 > 0)
{
int key2 = br.ReadInt32();
var state = StateManagerState.Read(br, this);
list.Add(key2, state);
c2--;
}
BranchStates.Add(key, list);
c--;
}
}
}
catch (EndOfStreamException) { }
}
public KeyValuePair<int, byte[]> GetStateClosestToFrame(int frame)
@ -666,8 +717,8 @@ namespace BizHawk.Client.Common
if (!BranchStates[frame].ContainsKey(branchHash))
return -2;
stateToMatch = BranchStates[frame][branchHash];
if (States.ContainsKey(frame) && States[frame] == stateToMatch)
return -1;
//if (States.ContainsKey(frame) && States[frame] == stateToMatch)
// return -1;
}
// there's no state for that frame at all
@ -695,7 +746,10 @@ namespace BizHawk.Client.Common
if (!States.ContainsValue(s))
{
if (BranchStates.ContainsKey(s.Frame))
ret.Y = BranchStates[s.Frame].Values.IndexOf(s);
{
int index = BranchStates[s.Frame].Values.IndexOf(s);
ret.Y = BranchStates[s.Frame].Keys.ElementAt(index);
}
if (ret.Y == -1)
return new Point(-1, -2);
}

View File

@ -13,6 +13,8 @@ namespace BizHawk.Client.Common
DiskSaveCapacitymb = 512;
Capacitymb = 512;
DiskCapacitymb = 512;
BranchStatesInTasproj = false;
EraseBranchStatesFirst = true;
}
public TasStateManagerSettings(TasStateManagerSettings settings)
@ -20,6 +22,8 @@ namespace BizHawk.Client.Common
DiskSaveCapacitymb = settings.DiskSaveCapacitymb;
Capacitymb = settings.Capacitymb;
DiskCapacitymb = settings.DiskCapacitymb;
BranchStatesInTasproj = settings.BranchStatesInTasproj;
EraseBranchStatesFirst = settings.EraseBranchStatesFirst;
}
/// <summary>
@ -50,6 +54,20 @@ namespace BizHawk.Client.Common
[Description("The size limit of the state history buffer on the disk. When this limit is reached it will start removing previous savestates")]
public int DiskCapacitymb { get; set; }
/// <summary>
/// Put branch states to .tasproj
/// </summary>
[DisplayName("Put branch states to .tasproj")]
[Description("Put branch states to .tasproj")]
public bool BranchStatesInTasproj { get; set; }
/// <summary>
/// Erase branch states before greenzone states when capacity is met
/// </summary>
[DisplayName("Erase branch states first")]
[Description("Erase branch states before greenzone states when capacity is met")]
public bool EraseBranchStatesFirst { get; set; }
/// <summary>
/// The total state capacity in bytes.
/// </summary>
@ -77,6 +95,8 @@ namespace BizHawk.Client.Common
sb.AppendLine(DiskSaveCapacitymb.ToString());
sb.AppendLine(Capacitymb.ToString());
sb.AppendLine(DiskCapacitymb.ToString());
sb.AppendLine(BranchStatesInTasproj.ToString());
sb.AppendLine(EraseBranchStatesFirst.ToString());
return sb.ToString();
}
@ -88,6 +108,7 @@ namespace BizHawk.Client.Common
string[] lines = settings.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
Capacitymb = int.Parse(lines[1]);
int refCapacity;
if (!int.TryParse(lines[0], out refCapacity))
{
if (bool.Parse(lines[0]))
@ -97,10 +118,21 @@ namespace BizHawk.Client.Common
}
else
DiskSaveCapacitymb = refCapacity;
if (lines.Length > 2)
DiskCapacitymb = int.Parse(lines[2]);
else
DiskCapacitymb = 512;
if (lines.Length > 3)
BranchStatesInTasproj = bool.Parse(lines[3]);
else
BranchStatesInTasproj = false;
if (lines.Length > 4)
EraseBranchStatesFirst = bool.Parse(lines[4]);
else
EraseBranchStatesFirst = true;
}
}
}

View File

@ -35,7 +35,6 @@
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.HR = new BizHawk.Client.EmuHawk.HorizontalLine();
this.label5 = new System.Windows.Forms.Label();
this.mom2 = new System.Windows.Forms.PictureBox();
this.pictureBox2 = new System.Windows.Forms.PictureBox();
@ -43,9 +42,14 @@
this.pictureBox4 = new System.Windows.Forms.PictureBox();
this.pictureBox3 = new System.Windows.Forms.PictureBox();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.pictureBox5 = new BizHawk.Client.EmuHawk.MyViewportPanel();
this.CloseBtn = new System.Windows.Forms.Button();
this.btnBizBox = new System.Windows.Forms.Button();
this.tbBranch = new System.Windows.Forms.TextBox();
this.tbCommit = new System.Windows.Forms.TextBox();
this.label6 = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.pictureBox5 = new BizHawk.Client.EmuHawk.MyViewportPanel();
this.HR = new BizHawk.Client.EmuHawk.HorizontalLine();
((System.ComponentModel.ISupportInitialize)(this.mom2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.mom1)).BeginInit();
@ -100,15 +104,6 @@
this.label4.TabIndex = 5;
this.label4.Text = "(LEVAR BURTON\r\nCAMEO)";
//
// HR
//
this.HR.Font = new System.Drawing.Font("Microsoft Sans Serif", 26.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.HR.Location = new System.Drawing.Point(349, 213);
this.HR.Name = "HR";
this.HR.Size = new System.Drawing.Size(158, 2);
this.HR.TabIndex = 4;
this.HR.Text = "COPYRITE 2001";
//
// label5
//
this.label5.AutoSize = true;
@ -178,17 +173,9 @@
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// pictureBox5
//
this.pictureBox5.Enabled = false;
this.pictureBox5.Location = new System.Drawing.Point(71, 223);
this.pictureBox5.Name = "pictureBox5";
this.pictureBox5.Size = new System.Drawing.Size(376, 48);
this.pictureBox5.TabIndex = 15;
this.pictureBox5.TabStop = false;
//
// CloseBtn
//
this.CloseBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.CloseBtn.Location = new System.Drawing.Point(424, 462);
this.CloseBtn.Name = "CloseBtn";
this.CloseBtn.Size = new System.Drawing.Size(75, 23);
@ -200,6 +187,7 @@
//
// btnBizBox
//
this.btnBizBox.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnBizBox.Location = new System.Drawing.Point(-4, -3);
this.btnBizBox.Name = "btnBizBox";
this.btnBizBox.Size = new System.Drawing.Size(75, 23);
@ -208,12 +196,69 @@
this.btnBizBox.UseVisualStyleBackColor = true;
this.btnBizBox.Click += new System.EventHandler(this.btnBizBox_Click);
//
// tbBranch
//
this.tbBranch.Location = new System.Drawing.Point(49, 476);
this.tbBranch.Name = "tbBranch";
this.tbBranch.ReadOnly = true;
this.tbBranch.Size = new System.Drawing.Size(100, 20);
this.tbBranch.TabIndex = 20;
//
// tbCommit
//
this.tbCommit.Location = new System.Drawing.Point(203, 476);
this.tbCommit.Name = "tbCommit";
this.tbCommit.ReadOnly = true;
this.tbCommit.Size = new System.Drawing.Size(100, 20);
this.tbCommit.TabIndex = 20;
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(2, 479);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(44, 13);
this.label6.TabIndex = 21;
this.label6.Text = "Branch:";
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(155, 479);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(44, 13);
this.label7.TabIndex = 22;
this.label7.Text = "Commit:";
//
// pictureBox5
//
this.pictureBox5.Enabled = false;
this.pictureBox5.Location = new System.Drawing.Point(71, 223);
this.pictureBox5.Name = "pictureBox5";
this.pictureBox5.Size = new System.Drawing.Size(376, 48);
this.pictureBox5.TabIndex = 15;
this.pictureBox5.TabStop = false;
//
// HR
//
this.HR.Font = new System.Drawing.Font("Microsoft Sans Serif", 26.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.HR.Location = new System.Drawing.Point(349, 213);
this.HR.Name = "HR";
this.HR.Size = new System.Drawing.Size(158, 2);
this.HR.TabIndex = 4;
this.HR.Text = "COPYRITE 2001";
//
// AboutBox
//
this.AcceptButton = this.CloseBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CloseBtn;
this.ClientSize = new System.Drawing.Size(519, 497);
this.Controls.Add(this.label7);
this.Controls.Add(this.label6);
this.Controls.Add(this.tbCommit);
this.Controls.Add(this.tbBranch);
this.Controls.Add(this.btnBizBox);
this.Controls.Add(this.CloseBtn);
this.Controls.Add(this.pictureBox5);
@ -268,5 +313,9 @@
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button CloseBtn;
private System.Windows.Forms.Button btnBizBox;
private System.Windows.Forms.TextBox tbBranch;
private System.Windows.Forms.TextBox tbCommit;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.Label label7;
}
}

View File

@ -37,6 +37,9 @@ namespace BizHawk.Client.EmuHawk
pictureBox2.BringToFront();
pictureBox1.BringToFront();
pictureBox5.Visible = false;
tbBranch.Text = SubWCRev.GIT_BRANCH;
tbCommit.Text = SubWCRev.GIT_SHORTHASH;
}
protected override void OnClosed(EventArgs e)
@ -160,9 +163,9 @@ namespace BizHawk.Client.EmuHawk
private void AboutBox_Load(object sender, EventArgs e)
{
#if DEBUG
Text = "BizHawk Developer Build (DEBUG MODE) GIT " + SubWCRev.GIT_BRANCH + "-" + SubWCRev.SVN_REV + "#" + SubWCRev.GIT_SHORTHASH;
Text = "BizHawk Developer Build (DEBUG MODE) GIT " + SubWCRev.GIT_BRANCH + "#" + SubWCRev.GIT_SHORTHASH;
#else
Text = "BizHawk Developer Build (RELEASE MODE) GIT " + SubWCRev.GIT_BRANCH + "-"+SubWCRev.SVN_REV + "#" + SubWCRev.GIT_SHORTHASH;
Text = "BizHawk Developer Build (RELEASE MODE) GIT " + SubWCRev.GIT_BRANCH + "#" + SubWCRev.GIT_SHORTHASH;
#endif
if (DateTime.Now.Month == 12)
if (DateTime.Now.Day > 17 && DateTime.Now.Day <= 25)

View File

@ -36,7 +36,6 @@
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.VersionLabel = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
@ -44,6 +43,9 @@
this.label37 = new System.Windows.Forms.Label();
this.CoreInfoPanel = new System.Windows.Forms.Panel();
this.textBox1 = new System.Windows.Forms.TextBox();
this.VersionLabel = new System.Windows.Forms.Label();
this.btnCopyHash = new System.Windows.Forms.Button();
this.linkLabel2 = new System.Windows.Forms.LinkLabel();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
@ -119,14 +121,6 @@
this.label4.TabIndex = 6;
this.label4.Text = "A multi-Platform Emulator";
//
// VersionLabel
//
this.VersionLabel.AutoSize = true;
this.VersionLabel.Location = new System.Drawing.Point(198, 52);
this.VersionLabel.Name = "VersionLabel";
this.VersionLabel.Size = new System.Drawing.Size(0, 13);
this.VersionLabel.TabIndex = 7;
//
// label5
//
this.label5.AutoSize = true;
@ -196,6 +190,39 @@
this.textBox1.TabIndex = 16;
this.textBox1.Text = "jabo_direct3d8_patched.dll is distributed with the special permission of the auth" +
"or.";
//
// VersionLabel
//
this.VersionLabel.AutoSize = true;
this.VersionLabel.Location = new System.Drawing.Point(198, 52);
this.VersionLabel.Name = "VersionLabel";
this.VersionLabel.Size = new System.Drawing.Size(0, 13);
this.VersionLabel.TabIndex = 7;
//
// btnCopyHash
//
this.btnCopyHash.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnCopyHash.AutoSize = true;
this.btnCopyHash.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnCopyHash.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Duplicate;
this.btnCopyHash.Location = new System.Drawing.Point(12, 505);
this.btnCopyHash.Name = "btnCopyHash";
this.btnCopyHash.Size = new System.Drawing.Size(22, 22);
this.btnCopyHash.TabIndex = 18;
this.btnCopyHash.UseVisualStyleBackColor = true;
this.btnCopyHash.Click += new System.EventHandler(this.btnCopyHash_Click);
//
// linkLabel2
//
this.linkLabel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.linkLabel2.AutoSize = true;
this.linkLabel2.Location = new System.Drawing.Point(40, 509);
this.linkLabel2.Name = "linkLabel2";
this.linkLabel2.Size = new System.Drawing.Size(100, 13);
this.linkLabel2.TabIndex = 19;
this.linkLabel2.TabStop = true;
this.linkLabel2.Text = "Commit #XXXXXXX";
this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked);
//
// BizBox
//
@ -204,6 +231,8 @@
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.OK;
this.ClientSize = new System.Drawing.Size(448, 536);
this.Controls.Add(this.linkLabel2);
this.Controls.Add(this.btnCopyHash);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.CoreInfoPanel);
this.Controls.Add(this.label37);
@ -240,7 +269,6 @@
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label VersionLabel;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.Label label7;
@ -248,5 +276,8 @@
private System.Windows.Forms.Label label37;
private System.Windows.Forms.Panel CoreInfoPanel;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Label VersionLabel;
private System.Windows.Forms.Button btnCopyHash;
private System.Windows.Forms.LinkLabel linkLabel2;
}
}

View File

@ -28,11 +28,11 @@ namespace BizHawk.Client.EmuHawk
{
if (VersionInfo.DeveloperBuild)
{
Text = " BizHawk (GIT " + SubWCRev.GIT_BRANCH + "-" + SubWCRev.SVN_REV + "#" + SubWCRev.GIT_SHORTHASH + ")";
Text = " BizHawk (GIT " + SubWCRev.GIT_BRANCH + "#" + SubWCRev.GIT_SHORTHASH + ")";
}
else
{
Text = "Version " + VersionInfo.MAINVERSION + " (GIT " + SubWCRev.GIT_BRANCH + "-" + SubWCRev.SVN_REV + "#" + SubWCRev.GIT_SHORTHASH + ")";
Text = "Version " + VersionInfo.MAINVERSION + " (GIT " + SubWCRev.GIT_BRANCH + "#" + SubWCRev.GIT_SHORTHASH + ")";
}
VersionLabel.Text = "Version " + VersionInfo.MAINVERSION + " " + VersionInfo.RELEASEDATE;
@ -55,6 +55,18 @@ namespace BizHawk.Client.EmuHawk
});
}
linkLabel2.Text = "Commit # " + SubWCRev.GIT_SHORTHASH;
}
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start("https://github.com/TASVideos/BizHawk/commit/" + SubWCRev.GIT_SHORTHASH);
}
private void btnCopyHash_Click(object sender, EventArgs e)
{
System.Windows.Forms.Clipboard.SetText(SubWCRev.GIT_SHORTHASH);
}
}
}

View File

@ -412,12 +412,6 @@
<Compile Include="config\ProfileConfig.Designer.cs">
<DependentUpon>ProfileConfig.cs</DependentUpon>
</Compile>
<Compile Include="config\PSX\PSXControllerConfig.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="config\PSX\PSXControllerConfig.Designer.cs">
<DependentUpon>PSXControllerConfig.cs</DependentUpon>
</Compile>
<Compile Include="config\PSX\PSXControllerConfigNew.cs">
<SubType>Form</SubType>
</Compile>
@ -787,6 +781,7 @@
<Compile Include="tools\HexEditor\HexFind.Designer.cs">
<DependentUpon>HexFind.cs</DependentUpon>
</Compile>
<Compile Include="tools\ICustomGameTool.cs" />
<Compile Include="tools\IToolForm.cs" />
<Compile Include="tools\Lua\EnvironmentSandbox.cs" />
<Compile Include="tools\Lua\Libraries\EmuLuaLibrary.Client.cs" />
@ -1271,9 +1266,6 @@
<EmbeddedResource Include="config\ProfileConfig.resx">
<DependentUpon>ProfileConfig.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="config\PSX\PSXControllerConfig.resx">
<DependentUpon>PSXControllerConfig.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="config\PSX\PSXControllerConfigNew.resx">
<DependentUpon>PSXControllerConfigNew.cs</DependentUpon>
</EmbeddedResource>

View File

@ -330,6 +330,8 @@
this.ForumsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.FeaturesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.AboutMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.C64SubMenu = new System.Windows.Forms.ToolStripMenuItem();
this.C64SettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MainStatusBar = new StatusStripEx();
this.DumpStatusButton = new System.Windows.Forms.ToolStripDropDownButton();
this.EmuStatus = new System.Windows.Forms.ToolStripStatusLabel();
@ -433,6 +435,7 @@
this.GenesisSubMenu,
this.wonderSwanToolStripMenuItem,
this.AppleSubMenu,
this.C64SubMenu,
this.HelpSubMenu});
this.MainformMenu.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.Flow;
this.MainformMenu.Location = new System.Drawing.Point(0, 0);
@ -2552,28 +2555,28 @@
//
this.PSXControllerSettingsMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.GameController;
this.PSXControllerSettingsMenuItem.Name = "PSXControllerSettingsMenuItem";
this.PSXControllerSettingsMenuItem.Size = new System.Drawing.Size(172, 22);
this.PSXControllerSettingsMenuItem.Text = "Controller Settings";
this.PSXControllerSettingsMenuItem.Size = new System.Drawing.Size(234, 22);
this.PSXControllerSettingsMenuItem.Text = "Controller / Memcard Settings";
this.PSXControllerSettingsMenuItem.Click += new System.EventHandler(this.PSXControllerSettingsMenuItem_Click);
//
// PSXOptionsMenuItem
//
this.PSXOptionsMenuItem.Name = "PSXOptionsMenuItem";
this.PSXOptionsMenuItem.Size = new System.Drawing.Size(172, 22);
this.PSXOptionsMenuItem.Size = new System.Drawing.Size(234, 22);
this.PSXOptionsMenuItem.Text = "&Options";
this.PSXOptionsMenuItem.Click += new System.EventHandler(this.PSXOptionsMenuItem_Click);
//
// PSXDiscControlsMenuItem
//
this.PSXDiscControlsMenuItem.Name = "PSXDiscControlsMenuItem";
this.PSXDiscControlsMenuItem.Size = new System.Drawing.Size(172, 22);
this.PSXDiscControlsMenuItem.Size = new System.Drawing.Size(234, 22);
this.PSXDiscControlsMenuItem.Text = "&Disc Controls";
this.PSXDiscControlsMenuItem.Click += new System.EventHandler(this.PSXDiscControlsMenuItem_Click);
//
// PSXHashDiscsToolStripMenuItem
//
this.PSXHashDiscsToolStripMenuItem.Name = "PSXHashDiscsToolStripMenuItem";
this.PSXHashDiscsToolStripMenuItem.Size = new System.Drawing.Size(172, 22);
this.PSXHashDiscsToolStripMenuItem.Size = new System.Drawing.Size(234, 22);
this.PSXHashDiscsToolStripMenuItem.Text = "&Hash Discs";
this.PSXHashDiscsToolStripMenuItem.Click += new System.EventHandler(this.PSXHashDiscsToolStripMenuItem_Click);
//
@ -2926,6 +2929,21 @@
this.AboutMenuItem.Text = "&About";
this.AboutMenuItem.Click += new System.EventHandler(this.AboutMenuItem_Click);
//
// C64SubMenu
//
this.C64SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.C64SettingsMenuItem});
this.C64SubMenu.Name = "C64SubMenu";
this.C64SubMenu.Size = new System.Drawing.Size(39, 19);
this.C64SubMenu.Text = "&C64";
//
// C64SettingsMenuItem
//
this.C64SettingsMenuItem.Name = "C64SettingsMenuItem";
this.C64SettingsMenuItem.Size = new System.Drawing.Size(152, 22);
this.C64SettingsMenuItem.Text = "&Settings...";
this.C64SettingsMenuItem.Click += new System.EventHandler(this.C64SettingsMenuItem_Click);
//
// MainStatusBar
//
this.MainStatusBar.ClickThrough = true;
@ -3973,6 +3991,8 @@
private System.Windows.Forms.ToolStripMenuItem Speed400MenuItem;
private System.Windows.Forms.ToolStripMenuItem BasicBotMenuItem;
private System.Windows.Forms.ToolStripMenuItem DisplayMessagesMenuItem;
private System.Windows.Forms.ToolStripMenuItem C64SubMenu;
private System.Windows.Forms.ToolStripMenuItem C64SettingsMenuItem;
}
}

View File

@ -1746,7 +1746,7 @@ namespace BizHawk.Client.EmuHawk
private void PSXControllerSettingsMenuItem_Click(object sender, EventArgs e)
{
new PSXControllerConfig().ShowDialog();
new PSXControllerConfigNew().ShowDialog();
}
#endregion
@ -2063,6 +2063,15 @@ namespace BizHawk.Client.EmuHawk
#endregion
#region C64
private void C64SettingsMenuItem_Click(object sender, EventArgs e)
{
GenericCoreConfig.DoDialog(this, "C64 Settings");
}
#endregion
#region Help
private void OnlineHelpMenuItem_Click(object sender, EventArgs e)

View File

@ -1595,6 +1595,7 @@ namespace BizHawk.Client.EmuHawk
GenesisSubMenu.Visible = false;
wonderSwanToolStripMenuItem.Visible = false;
AppleSubMenu.Visible = false;
C64SubMenu.Visible = false;
switch (system)
{
@ -1675,6 +1676,9 @@ namespace BizHawk.Client.EmuHawk
case "AppleII":
AppleSubMenu.Visible = true;
break;
case "C64":
C64SubMenu.Visible = true;
break;
}
}
@ -1965,7 +1969,7 @@ namespace BizHawk.Client.EmuHawk
if (VersionInfo.DeveloperBuild)
{
return FormatFilter(
"Rom Files", "*.nes;*.fds;*unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.col;.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.psf;*.minipsf;*.nsf;%ARCH%",
"Rom Files", "*.nes;*.fds;*unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.col;.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.psf;*.minipsf;*.nsf;%ARCH%",
"Music Files", "*.psf;*.minipsf;*.sid;*.nsf",
"Disc Images", "*.cue;*.ccd;*.m3u",
"NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%",
@ -1986,7 +1990,7 @@ namespace BizHawk.Client.EmuHawk
"PlayStation", "*.cue;*.ccd;*.m3u",
"PSX Executables (experimental)", "*.exe",
"PSF Playstation Sound File", "*.psf;*.minipsf",
"Commodore 64 (experimental)", "*.prg; *.d64, *.g64; *.crt;%ARCH%",
"Commodore 64 (experimental)", "*.prg; *.d64, *.g64; *.crt; *.tap;%ARCH%",
"SID Commodore 64 Music File", "*.sid;%ARCH%",
"Nintendo 64", "*.z64;*.v64;*.n64",
"WonderSwan", "*.ws;*.wsc;%ARCH%",
@ -2956,7 +2960,7 @@ namespace BizHawk.Client.EmuHawk
{
Global.AutoFireController.IncrementStarts();
}
//Global.AutofireStickyXORAdapter.IncrementLoops(IsLagFrame);
Global.AutofireStickyXORAdapter.IncrementLoops(IsLagFrame);
PressFrameAdvance = false;
@ -3540,6 +3544,8 @@ namespace BizHawk.Client.EmuHawk
Console.WriteLine(" {0} : {1}", f.FirmwareId, f.Hash);
}
}
GlobalWin.Tools.Load<ICustomGameTool>();
return true;
}
else

View File

@ -67,6 +67,7 @@
//
// propertyGrid1
//
this.propertyGrid1.CategoryForeColor = System.Drawing.SystemColors.InactiveCaptionText;
this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
this.propertyGrid1.Location = new System.Drawing.Point(3, 3);
this.propertyGrid1.Name = "propertyGrid1";
@ -88,6 +89,7 @@
//
// propertyGrid2
//
this.propertyGrid2.CategoryForeColor = System.Drawing.SystemColors.InactiveCaptionText;
this.propertyGrid2.Dock = System.Windows.Forms.DockStyle.Fill;
this.propertyGrid2.Location = new System.Drawing.Point(3, 3);
this.propertyGrid2.Name = "propertyGrid2";
@ -143,6 +145,7 @@
this.Controls.Add(this.tabControl1);
this.Name = "GenericCoreConfig";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "GenericCoreConfig";
this.Load += new System.EventHandler(this.GenericCoreConfig_Load);
this.tabControl1.ResumeLayout(false);

View File

@ -58,8 +58,6 @@ namespace BizHawk.Client.EmuHawk
SyncSettings.Controls = ctrls;
SyncSettings.Controls = ctrls;
if (changed)
{
GlobalWin.MainForm.PutCoreSyncSettings(SyncSettings);

View File

@ -1,96 +0,0 @@
namespace BizHawk.Client.EmuHawk
{
partial class PSXControllerConfig
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PSXControllerConfig));
this.CancelBtn = new System.Windows.Forms.Button();
this.OkBtn = new System.Windows.Forms.Button();
this.btnTest = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// CancelBtn
//
this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.CancelBtn.Location = new System.Drawing.Point(294, 227);
this.CancelBtn.Name = "CancelBtn";
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
this.CancelBtn.TabIndex = 5;
this.CancelBtn.Text = "&Cancel";
this.CancelBtn.UseVisualStyleBackColor = true;
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
//
// OkBtn
//
this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OkBtn.Location = new System.Drawing.Point(228, 227);
this.OkBtn.Name = "OkBtn";
this.OkBtn.Size = new System.Drawing.Size(60, 23);
this.OkBtn.TabIndex = 4;
this.OkBtn.Text = "&Ok";
this.OkBtn.UseVisualStyleBackColor = true;
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
//
// btnTest
//
this.btnTest.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnTest.Location = new System.Drawing.Point(12, 227);
this.btnTest.Name = "btnTest";
this.btnTest.Size = new System.Drawing.Size(60, 23);
this.btnTest.TabIndex = 6;
this.btnTest.Text = "Test";
this.btnTest.UseVisualStyleBackColor = true;
this.btnTest.Click += new System.EventHandler(this.btnTest_Click);
//
// PSXControllerConfig
//
this.AcceptButton = this.OkBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CancelBtn;
this.ClientSize = new System.Drawing.Size(366, 262);
this.Controls.Add(this.btnTest);
this.Controls.Add(this.CancelBtn);
this.Controls.Add(this.OkBtn);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "PSXControllerConfig";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Controller Settings";
this.Load += new System.EventHandler(this.PSXControllerConfig_Load);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button CancelBtn;
private System.Windows.Forms.Button OkBtn;
private System.Windows.Forms.Button btnTest;
}
}

View File

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BizHawk.Common;
using BizHawk.Emulation.Cores.Sony.PSX;
using BizHawk.Client.Common;
using BizHawk.Client.EmuHawk.WinFormExtensions;
using BizHawk.Common.ReflectionExtensions;
namespace BizHawk.Client.EmuHawk
{
public partial class PSXControllerConfig : Form
{
public PSXControllerConfig()
{
InitializeComponent();
}
private void PSXControllerConfig_Load(object sender, EventArgs e)
{
var psxSettings = ((Octoshock)Global.Emulator).GetSyncSettings();
for (int i = 0; i < psxSettings.Controllers.Length; i++)
{
Controls.Add(new Label
{
Text = "Controller " + (i + 1),
Location = new Point(15, 19 + (i * 25)),
Width = 85
});
Controls.Add(new CheckBox
{
Text = "Connected",
Name = "Controller" + i,
Location = new Point(105, 15 + (i * 25)),
Checked = psxSettings.Controllers[i].IsConnected,
Width = 90
});
var dropdown = new ComboBox
{
Name = "Controller" + i,
DropDownStyle = ComboBoxStyle.DropDownList,
Location = new Point(200, 15 + (i * 25))
};
dropdown.PopulateFromEnum<Octoshock.ControllerSetting.ControllerType>(psxSettings.Controllers[i].Type);
Controls.Add(dropdown);
}
}
private void OkBtn_Click(object sender, EventArgs e)
{
var psxSettings = ((Octoshock)Global.Emulator).GetSyncSettings();
Controls
.OfType<CheckBox>()
.OrderBy(c => c.Name)
.ToList()
.ForEach(c =>
{
var index = int.Parse(c.Name.Replace("Controller", ""));
psxSettings.Controllers[index].IsConnected = c.Checked;
});
Controls
.OfType<ComboBox>()
.OrderBy(c => c.Name)
.ToList()
.ForEach(c =>
{
var index = int.Parse(c.Name.Replace("Controller", ""));
psxSettings.Controllers[index].Type = c.SelectedItem.ToString().GetEnumFromDescription<Octoshock.ControllerSetting.ControllerType>();
});
GlobalWin.MainForm.PutCoreSyncSettings(psxSettings);
DialogResult = DialogResult.OK;
Close();
}
private void CancelBtn_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void btnTest_Click(object sender, EventArgs e)
{
new PSXControllerConfigNew().ShowDialog();
}
}
}

View File

@ -1,624 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAwAMDAQAAAABABoBgAAxgAAACAgEAAAAAQA6AIAAC4HAAAYGBAAAAAEAOgBAAAWCgAAEBAQAAAA
BAAoAQAA/gsAADAwAAAAAAgAqA4AACYNAAAgIAAAAAAIAKgIAADOGwAAGBgAAAAACADIBgAAdiQAABAQ
AAAAAAgAaAUAAD4rAAAwMAAAAAAgAKglAACmMAAAICAAAAAAIACoEAAATlYAABgYAAAAACAAiAkAAPZm
AAAQEAAAAAAgAGgEAAB+cAAAKAAAADAAAABgAAAAAQAEAAAAAACABAAAAAAAAAAAAAAQAAAAEAAAAAAA
AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP//
/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAHR3AAAAAAAAAAAAAAAAAAAAAAAAAAAAdHdEcAAAAAAAAAAAAAAAAA
AAAAAAAAAHd0d3QAAAAAAAAAAAAAAAAAAAAAAAAAAEd8d3UAAAAAAAAAAAAAAAAAAAAAAAAAB3yHfHZw
AAAAAAAAAAAAAAAAAAAAAAAAd3fIyHVwAAAAAAAAAAAAAAAAAAAAAAAAfHh3jIxwAAAAAAAAAAAAAAAA
AAAAAAAHd8jIyHdgAAAAAAAAAAAAAAAAAAAAAAAHd4yHfIdAAAAAAAAAAAAAAAAAAAAAAAAHyMjIyMhQ
AAAAAAAAAAAAAAAAAAAAAAB3d3eMh4dgAAAAAAAAAAAAAAAAAAAAAAB8jIyIfIdQAAAAAAAAAAAAAAAA
AAAAAAB3h4jIiMh3AAAAAAAAAAAAAAAAAAAAAAB8jIeHeIjHAAAAAAAAAAAAAAAAAAAAAAeIiHh4eMiE
AAAAAAAAAAAAB0dHcAAAAAd8h4eIiIiHcAAAAAAAAAB0d3d3RwAAAAeIeIiIiIh3RwAAAAAAAHR3d8h3
dAAAAAfIh4iIiHiIx0cAAAAAdHh3eIeHhwAAAAeHiIiIiIiId3R3dHR0eHd4h4eHhAAAAAd4eIiIiIiH
x3d2d3eId4iIiIiIhwAAAAd4eIiI+IiIh3d3eHh3iIiIiIeHwAAAAAfIjHeIiIiIyIeHh4iIiIiIiIiI
cAAAAAeIQ0R3h3iIiMiIiIiIiIiIiIiEAAAAAAfIR3d3d0iIiIh4iIeIiIiIiHhAAAAAAAB4d3d3SHiI
h4fTiIi3iIiIeIwAAAAAAAB3h4d3eIeIiHiJiIuIiIh4jHAAAAAAAAAHyId3h3h4iIh4iIiIiIiHeAAA
AAAAAAAAB8iMiMjIiIiIh4h3aMjHAAAAAAAAAAAAAAdYyIeIiIiMjId6d4eAAAAAAAAAAAAAAAAHdsjH
eIeH6MiId3AAAAAAAAAAAAAAAIiIh4V8jIh4eIfHcAAAAAAAAAAAAACIiIh3AAAHd3h3fHcAAAAAAAAA
AAAAAAiIjHgAAAAAAHx8eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////
AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A
H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP////
AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA
AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/
AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC
AAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/
AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAAAAAAAAAAAAA
AAd0dAAAAAAAAAAAAAAAAAB3x3cAAAAAAAAAAAAAAAAAd3fHcAAAAAAAAAAAAAAAB3yMh3AAAAAAAAAA
AAAAAAfIeMdwAAAAAAAAAAAAAAAHjIyHQAAAAAAAAAAAAAAAfId4yHAAAAAAAAAAAAAAAHjIyIdQAAAA
AAAAAAAAAAB3iId4YAAAAAAAAAdwAAAAjIiIiIUAAAAAAHd3dAAAB4iIiHh8cAAAAHd3x4dwAAd4iIiI
h3Z3d3R3yIh4cAAHh4iIiIfHd3d4iIiIh3AAB3jHiIiIiHeHiIiIiIwAAAh3dXh4iMiIiIiIiIhwAAAA
yGd0d4iIeIi4iIiMAAAAAIeHd4iIh32IiIiIcAAAAAAAd4jIyIiIiHeHyAAAAAAAAAB3h4iIh8h3dwAA
AAAAAAAIh8fIh4eIaAAAAAAAAACIiHAAB8jIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
////////////////////n////g////wP///8B///+Af///gH///4B///8Af///AH///wB//n8AP/A+AB
/AHgAAAB4AAAAeAAAAPgAAAH8AAAD/AAAB/8AAA//wAA//4AA//weA//////////////////////////
//8oAAAAGAAAADAAAAABAAQAAAAAACABAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAA
AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRwAAAAAAAAAAAAB3dAAAAAAAAAAAAA
d8dwAAAAAAAAAAAAfId3AAAAAAAAAAAHeMjHAAAAAAAAAAAHyHh3AAAAAAAAAAAHh3eEAAAAAAAAAAAI
yIiHAAAAAHd2cAAIiIiIQAAAd3d4UACHiIiId3d3eHiIcACHh4iIyHeHiIiIcAAIR3d4iIiIiIiMAAAH
d3eIh3iIiIhwAAAAeMh4iIiHiMAAAAAAAHfIiMh4aAAAAAAAiIgHyIfIAAAAAAAIgAAAAIAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD8f/8A+H//APB/
/wDwP/8A4D//AOA//wDgP/8A4D/BAOAfAQDAAAEAwAABAOAAAwDgAAcA8AAfAPwAPwDwgP8A5/f/AP//
/wD///8A////ACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA
AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAd1AAAAAAAAB8cAAAAAAAB4eAAAAAAAAHyMgAAAAAAAiIhwAAAHcACI
iHcAd3hwAIz4jIeIiIAAd3eIiIiIAACHeIiIiHAAAACMeMh4AAAAiAAIgAAAAAAAAAAAAAAAAAAAAAAA
AAD//wAA//8AAP//AADj/wAA4/8AAMP/AADB/wAAwfkAAMDBAADAAQAAwAMAAMAHAADwDwAAzn8AAP//
AAD//wAAKAAAADAAAABgAAAAAQAIAAAAAAAACQAAAAAAAAAAAAAAAQAAAAEAAAAAAAA9OzsAZD8/AGg8
PABtPj4AQkNDAEZIRwBWQkIAV0REAF5AQABbRkYAVklJAFxPTwBTU1MAXFJSAF5ZWQBkQEAAYUREAGZF
RQBqQkEAYEtLAGNPTwBwQUEAfUZGAHJKSgB2SUkAfU9PAGBRUQBgVFQAZlZWAGZYWABqWVkAclZWAHpU
VAB9W1oAbmJiAGtoaABtaWkAcWdnAHdnZwB8Y2MAe2pqAHJxcQB+dHQAd3l5AHl6egCGT08AiU9PAIFP
UACGU1MAjVFRAIlWVgCMV1cAg1xbAIxaWQCQUlIAlVJSAJFXVgCXVVUAmVVVAJZaWQCSXV0AlV9eAJpZ
WgCeW1sAml5eAKBZWgCgXFwAql9fAIRmZQCIZWQAhWtrAI5ragCTYmEAnGBhAJ9kYwCaZmYAk25uAJ1s
awCFdHQAiXd3AIt+fgCWd3cAmHR0AJV5eQCbfHwAo2JhAKZhYQChZWUApGVkAKplZACsZGQAqmhnAKZr
agCnbGsAqmloAKlubQCsbW0AtGZnALhsbACxb3AAv29wAKVxcACrc3IAr35+ALN0cwC5c3MAvXBxALR4
dgC1fHsAunt6AMNtbgDGb3AAw3FyAMZwcQDGdXUAyHR1AMp3eADBeXkAxnt7AMB/fgDLensANLBSAEWf
TgBBtFwAPMdnADHkdgDciiIAvoF/AISrdwDln0sA35lhAN2XfADgmmEA8LdlAO61cAArWPIALWT+AEh5
+gDOf4AAfoCAAHiA1ABZv9wAZrnUAGK+2ABxnv4Ad6P/ADPX/QBw0OcAW+D7AIKEgwCPgoIAjI2NAJuC
ggCUiIgAmYqKAJGSkgCjhIQAqoKCAKKLiwC+hIMAsoqKALaSgQCum5sAsZubALqqlQCdgr4Ar6ytALGh
oAC6pKQAwoSDAMyBggDGiIYAyYiHAMWMigDMjIoA0ISFANKHiADUjIwA2Y6NAMCUjQDIk44A0JCPANaP
kADHlZQAzpSSAMScmwDUkpIA2ZSVANWYlgDampcA2ZeYANWcnADam5sA4p2cAMChjwDeoJ4A5aCFAOaj
jQDlpJoA2p6hAMOkowDOoaEAy62tANegoADdoqEA2aGpANGsrwDdq6kAwbG4ANGysQDdtLQA2ri3AOGk
owDjqKYA66ylAOGnqADjq6oA6a2rAOOwrwDssK4A5K+wAOaztADttLIA57i2AO24tgDmurgA6rq6APC1
swDyuLYA9Ly5APi+uwD1wL0A+cC9AKKMwACkk8QAqprMALSayACptsEAlaDkAOy/wACRxtQAgOv9AJnr
9wDEwsoA5sbGAOzCwgDuyMcA7MzMAPPEwgDxy8oA9dPTAPja2gAAAAAAAAAAAP///wAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAoIJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAACYXODs4BCUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
KTNDQ0M7OAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALllbYmJZQBcAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYYWNwcHBwWy8mAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFLanBwcHBwYz0eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABpqcHBwcHBwZVkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl11w
cHBwcHBwcGcSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIXdwcHBwcHBwcGkSAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPXBwcHBwcHBwd2wYAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAACXbnBwdXB5dXl0eW4hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAid3R5eXl5eXl5q6wzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9eXV5
i7CxsbGxsblLKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABndYuwsbm8uby5vMFnHgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJt3q7G3vMHB1cLBwdWuEgAAAAAAAAAAAAAAAAAA
AAAAAAAeEhMSCiUAAAAAAAAAAEexsbm/1dXZ2dnZ1da5ZgwAAAAAAAAAAAAAAAAAAAAjEjNZaW5qXRMl
AAAAAAAAADW5s7/V2N7i4uLi3dzZrQQPAAAAAAAAAAAAAAAAHxhZbm5uaWltd6ASAAAAAAAAAEmzvMLZ
3uP29/fw4uTkuUAWCy0AAAAAAAAAAB4YYXd3gG13vbm5vb8zAAAAAAAAAE6xwdXd4/b6+/r38OTl1Vlc
OAMIFAweFBQSM2mtrYB3vdXT0NXExNU1AAAAAAAAAE65wtXe8Pr7/Pz79+fn1WphZ25pXV1mbHetrXd3
tdXT4vXw49nZ3NYgAAAAAAAAAEu3wdje9vv7/Pz79+fn34B3d2xtoHeud66uudXT4vD39/Dj49zk5G0A
AAAAAAAAAD2xwcwoH0/L/Pukyenp5K27u7m5uczM0Nve4vb3+vr56OPl5eXl1igAAAAAAAAAADWxwQgB
BQYNmveZK/Dp6cG/wcTV2eP3+vr6+/r6+ejm5ufn5+nkIgAAAAAAAAAAAJmruR4sjC2WLFCdDd3p6dXW
1tXI3vn67pCO9Ojp6efo5+fm59wiAAAAAAAAAAAAAABLsZ0FmC0qKgHMRcjp6dzc1Y2KiO3RlfKTj+np
5ubm5eXk1SIAAAAAAAAAAAAAAACdab/Lp5aWnEfV1cHm6ebk6pGSiabZ8fOU0uXl5eTk3NyuRQAAAAAA
AAAAAAAAAAAAn0ux0KFTaMHBv7nC6efp3Ovv7OTm3OPl3Nzc3NfW1U6fAAAAAAAAAAAAAAAAAAAAAABF
Wa25t7yxs7Gw5+fn5Obk18XG3NyBfHvD1cSgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAFUzarGwsHl5sefn
39zEgoZ/hL19fnqirj2jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj09ZXV0cLzn3NXChYeDub+1pbQ9
VQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0rXj+rpInTBDcHCz5NW/ucG5u7GAM1QAAAAAAAAAAAAAAAAA
AAAAAAAAAADLytDi9tOemQAAAAAAUy9EecLEsa1uPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPj11Mme
VakAAAAAAAAAAAAATS84M0akAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////
AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A
H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP////
AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA
AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/
AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAgAAAAAAAAE
AAAAAAAAAAAAAAABAAAAAQAAAAAAAFFNTQBRUlIAU1RUAGJHRwBiT08Aa0lIAGJTUwBrVlYAYllZAGZc
XABpWloAb1xbAHNTUwB7V1YAc1hXAHFbWwBkZWUAaWFhAG5kZABpamkAcGFhAHlubgB2cHAAf3V1AH55
eQB8fX0AgUpKAI1PTwCLWFcAhlhYAI9ZWQCKXFsAm1ZWAJJZWQCWWVgAmlpbAJtcWwCiXFwAl2BfAIBg
YACAZ2YAgG9vAI9oaACWZWQAmGBhAJ5kZACcaWoAmm9vAIV0dACNcHAAiXZ2AIB8fACac3IAm3V0AJ51
dQCZfHwAnHx8AKNmZgCnZmYAqmJiAK5jYwCvb24AtWVmALBtbgC5bW0AvmxtAKx+fQCxcnIAtHBwALZz
dACydXQAtnd2ALlwcAC5dnYAt3p5ALh5eAC8fHsAun18ALx+fQDGb3AAxnBxAMdzdADAd3YAyHJzAMlz
dADJdXYAynd4AMd/fwDMe3wAzXx9AHunbwBhvHIAYsN4ANuLOwC2hn4A4Zt5APC3ZABte9sAX47+AHWM
5QAl0foAY+P8AIeDgwCFhoYAioSEAJOIiACWi4sAmpKRAKGCgQCmhYUAqYGBAKuDhACniooApYyMAKiO
jQCyhYMAvoWEALeNjQCrj5AAr5eXALSVlAC9lJMAmbCEAK6RugDBgYAAwoSCAMWDhADChoQAxYeFAM6A
gQDFiIYAxoqIAMqIiQDMi4oAy4yKAMiPjQDPj44A0ISFANKJigDUi4wA04+NANWNjgDKkY8A0JCOANud
iQDWj5AAzJSTAM2XlgDGm5oA1pGSANOUkgDVl5EA1pOUANiVlgDYmJUA2ZeYANKenADbmpsA3pmYANuc
mgDbn5wA1aacAN6gngDqqZoA3Z+gAMyjowDCra0AxqysAMqpqQDboaAA3qKiAN6logDbp6UA3aWkANer
qgDWsbMA0rW0ANe0tADfs7IA4aSiAOGlpQDkp6UA46imAOWopgDsraIA6qimAOGoqADhrqwA6a2rAOqv
rADpsK4A7LGuAOGzswDlsbEA7bKxAO+1sgDotrYA5rm3AO+4twDot7sA6bq5AOu9uwDrv70A8bazAPG2
tADxuLUA9Lm2APC9uwD2vboA9L+9APi+uwD4v7wA8sC+APXAvgD5wL0AkILJAKqXzACsu8cAqr/LALLV
3QDawMIA48XFAOvDwQDswMAA7cTDAO/ExQDgxsgA8cbEAPTGxADwyskA9MvJAPLNzQD21dYA+NjZAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAMEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHCEcBQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAayU9PSYbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdQlBSQiJpAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAM0pSUlJQPRcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnUlJSUlJGFQAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAFJSUlJSUkoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzUlJSWVJZfxAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5XWYqKioqGDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASoqMkpqa
mqAsAAAAAAAAAAAAAAAAAABoNAAAAAAAAACMjJyuvLy2toYHAAAAAAAAAAAAABcOIDouBgAAAAAAc4yc
tsHKysPAriIKAAAAAAAAABYgRk1LTX+DEAAAAABukqXB4ejo4dHPQCIEChcXEwggTXV/k66unKMpAAAA
AG6Srsro6ero0dN/Rk1NRk2Dg4STrsbh4cHAt2sAAAAAbpKuOXPe6ajW15KGg4OGk528yuHo5eHPz882
AAAAAAB4jCkDAxSoMabXt5yjt8ro3ePo5dbT09HTdAAAAAAAAABGcBFoGgFwdtfDwHxi2dpmZcrX09HP
z0MAAAAAAAAAAHh/qWwaOa6cz9PNZGPYsdzbzc3DwLk2AAAAAAAAAAAAAAAvhpKakoyg19HNyKS5wHtb
orZ/cwAAAAAAAAAAAAAAAAAANkaKWVm5zb1gYV6cXVxfNgAAAAAAAAAAAAAAAAAAALGvlTIuP1K5tqCR
l4xfLwAAAAAAAAAAAAAAAAAAsbPBenkAAAAAcCVYjE0scwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////+f///+D////A////wH
///4B///+Af///gH///wB///8Af///AH/+fwA/8D4AH8AeAAAAHgAAAB4AAAA+AAAAfwAAAP8AAAH/wA
AD//AAD//gAD//B4D////////////////////////////ygAAAAYAAAAMAAAAAEACAAAAAAAQAIAAAAA
AAAAAAAAAAEAAAABAAAAAAAAWlJSAHBJSQB1SEgAe1dXAHdYWAB5WlkAel1dAGBiYgB1bGwAfWtrAHh2
dgB9fn4Ag01NAIRXVwCIV1cAhV9eAItbWgCgX14ApV1dAJhgXwCNYGAAnWtqAJhtbQCCdnYAh3x8AI15
eACeensAqGBgAKhoZwCga2oArGpqALNqagCzb28AtG1tALltbQCxb3AApnVzAKlzcwCqdHMApnp6AKd+
fgCpensAq3x7ALZ3dgC8dHQAvH59AMZvcADGcHEAxXN0AMhycwDJdncAynh5AMx5egDNfn8Ajo1wAOek
VgDGgH8A4p53AEZ2+gB8u4AAd8PaAIuEhACOh4cAjo6OAJ+DggCejo4Ao4SEAKSIiACsi4sAqo2MAK6P
jgC+gYAAvoaGAL+KiACskJAAtJeXALWenQC5np4At6iOAKmyjgC9nroAwYSDAMaGhADOhoYAxomHAMiK
iQDJjYwA0oeIANOOjwDUjY0A2ZiPANaPkADGkZEAx5eXAMySkADGnZwA1ZOSANeTlADWl5YA2JSVANGZ
mADan50A3J6dAOCcmwDVoJ8A7K2fAMOtrQDXo6IA3aCgAN+kpADVq6oA3ay3AMu0tADPtrYA3L+/AOCi
oQDhpqUA5KelAOinpgDlq6gA46usAOOvrQDqrqwA7LGuAOayswDjtrQA5re1AOqysQDts7EA57y6AO+8
ugDrvL0A8LOwAPC1sgDwtrQA87q3APS6twD2vboA8b69APi/vAD2wb4A+cC9AJmTzwDHqMMAu8PMAIHf
8QDByNAA7cLCAO3FwwDvxsQA5cjIAOzOzgDwxcQA9cbEAPPP0AD10tIAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BQMJAAAAAAAAAAAAAAAAAAAAAAAAAAAPHBMNAAAAAAAAAAAAAAAAAAAAAAAAABojLy8TAAAAAAAAAAAA
AAAAAAAAAAAAAB0wMDAiPgAAAAAAAAAAAAAAAAAAAAAAQjAwMDAtGAAAAAAAAAAAAAAAAAAAAAAAFzIy
NTU5CgAAAAAAAAAAAAAAAAAAAAAAIjZYWFxcBwAAAAAAAAAAAAAAAAAAAAAANlxtdW11JQAAAAAAAAAA
PgcRDgkAAAAAXG1/lISAZgMAAAAAABkVLC5SVhcAAABNY3WWnJuLfB8UBAcQHkhWaX91dSsAAABNY2BM
mJeCiVJSVl9laX+WloSJgEIAAAAAXAEIC0tGjnR0dJaRk5qNjIyJQwAAAAAAJkNADBtdjIaPO1GSPYuJ
hnVEAAAAAAAAAClISWRcd4xwkGp8UE90VwAAAAAAAAAAAAAAKSQ1NYZ7OjhbPDdGAAAAAAAAAAAAAHNv
YGsAKyJoXFYmRwAAAAAAAAAAAAAAcnIAAAAAAAAATgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP//
/wD///8A////APx//wD4f/8A8H//APA//wDgP/8A4D//AOA//wDgP8EA4B8BAMAAAQDAAAEA4AADAOAA
BwDwAB8A/AA/APCA/wDn9/8A////AP///wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAQAAAAAAAAAA
AAAAAQAAAAEAAAAAAABjZGQAdmRjAHtpaQB/eHgAgU9PAKBaWgCFbm0AlWtqAKptbgCwZ2cAsGhoAKxw
cACteHkAvnJyAMZvcADGcHEAy3l5AMx9fgCFmXQAwIB/ANeUfQDhoX8AlIqJAJWMjACYiIgAoIaGAK2K
igCxh4cAvoGAALKKigC4iYgAuJWVAL2cnACss50AuqKhAL+mpgDLgoIAxImHAMeNjADLkI8AxpWTANCS
kQDYlZUA1J6dANqZmgDdnp4A1J+oAMaiogDOr68AzLKyANi5uADhpaIA4qypAOWtqADrrqsA4bKwAOay
sgDtuLYA57++AOy4uADxtLIA8be0APa9ugDswL4A9sG+ALCcxwC5ncIA06zBALnH0QC2ytQA7sPDAPLS
0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAZBgUAAAAAAAAAAAAAAAAACw8KAAAAAAAAAAAAAAAAGhAQDgAAAAAAAAAAAAAAAAkRESUYAAAA
AAAAAAAAAAAlKy4uBwAAAAAAAAcDAAAAKzlHPCYCAAAYCB0oKgAAAC0wSDs0FB0nLDlAOiwAAAANAQQb
Pi9DRkVBPzUAAAAAJB4cKz5EQjMiNSkAAAAAAAAAHwwRNxYVEyQAAAAAAAAxMgAAACEgAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA4/8AAOP/AADD/wAAwf8AAMH5
AADAwQAAwAEAAMADAADABwAA8A8AAM5/AAD//wAA//8AACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAkAAAAJAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAUAAAAOAEBAVUAAABUAAAANQAAABAAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAkFBSUvGRl5TCkpwlYuLtxDJCTQFw0NmQAA
AEkAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGAwMKE8rK6V6RET2klJR/5ZS
U/+OT0//ZDc38B0QEJoAAAAyAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYDAwYVzAwoopP
T/ygXVz/oFtb/55ZWf+bWFf/k1NT/1UvL9wGAwNcAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AARNKipxhk5O+adkY/+uZWX/tWdo/7VmZ/+qYWH/nltb/3hERPcfERGCAAAAFgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADEZGS1zQ0LXqGdm/7ptbf/Fb3D/x3Bx/8hwcf/BbW7/q2Vl/4hPT/82HR2gAAAAIAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAB1gxMYyYXl3/vXFx/8Zwcf/HcHH/x3Bx/8dwcf/HcHH/uG1t/5NY
V/9EJia2AAAAKQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPB8fNH1MS+K4cnH/x3Fy/8dwcf/HcHH/x3Bx/8dw
cf/HcHH/wHBx/51gX/9PLCzGAAAAMwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
AAMAAAAAAAAAAAAAAAAAAAAALhAQFIZXVs/RjIz/1Y2O/9qYmP/eoaL/46qr/+aysv/ot7f/6rm5/+m4
uf/otbX/5q+v/+uvrf/jqab/wYeF/28/P/QhEhKvAAAAXwAAACgAAAANAAAABQAAAAMAAAACAAAAAwAA
AAUAAAAKAAAAFQAAADAdDg9oSSkptHZHRu2dYmL+t3Z1/758e/+6enn/tnh3/7d5eP+8fn3/w4SD/7Z6
ef9eODfbBgICTgAAAAgAAAAAAAAAAAAAAAAAAAAAPhwcJJVjYuPXkZH/2JOU/92fn//iqqr/57O0/+u8
vP/uwsL/78XG/+/Exf/twMD/67i4/+60sv/wtrP/zZKQ/5taWv9xQED2MRsaxAgEBIcAAABaAAAAQQAA
ADcAAAA2AAAAOwAAAEUEAgJZHA4OfUcnJ7l5SkntqGxr/8CAfv/DgoH/vH59/7p+ff/DiIb/zZGP/9GT
kf/UlJP/1peV/9eZl/+GVlbuGQsLVwAAAAcAAAAAAAAAAAAAAAAAAAAARiIiLZ9rauvZk5P/2peY/+Ck
pP/lsLD/6ru7/+/Fxf/yzMz/9NDQ//PPz//xycr/7sDA//K5tv/1u7j/36Kg/6dmZf+mZWX/j1ZW/WM6
OutDJSXQNBwcvDAaGrQ0HBy1PiIivUwsLMtkPDzfh1VU9a1xcP/EhIP/xIWE/7+Cgf/Ch4b/zZST/9mk
ov/grq3/4a6t/96lo//eoJ7/36Kg/+Cjof+IWVjnGwwMQwAAAAIAAAAAAAAAAAAAAAAAAAAARyQkL6Br
auzZk5P/25qb/+GnqP/ntLT/7cDA//LLy//209T/+NjY//fX1//00ND/8cbG//W9u//4vrz/46ak/7d0
c/+vb27/s3Jy/7d2df+ucXD/pWpp/6Npaf+nbWz/sHVz/7p9fP/EhYT/yImI/8WIhv/DiIb/ypGP/9eg
n//hr63/57q5/+rCwP/rwsD/6bq4/+evrf/nq6n/6q6r/9qgnv9wRkbDBwAAHgAAAAAAAAAAAAAAAAAA
AAAAAAAASCQkLZ1nZuvYkpP/25uc/+Opqv/qtrf/7cHB//TOzv/52Nj/+tzc//na2v/xz9D/8MfH//fA
vv/6wb7/6a6r/8OBgP/DgoD/vX58/7h7ev+8fn3/woOC/8aHhv/HiYj/xoqJ/8aLif/Ijoz/zZST/9eg
nv/hrav/6Lm3/+zCwf/uyMf/78nH/+/Dwf/uvLr/7ba0/+60sf/vtLL/8ri1/7J+fflMKSltAAAABAAA
AAAAAAAAAAAAAAAAAAAAAAAAQyEhI5JcXOPWj5D/3Juc/8qVlf+BZmb/bl5e/4l4eP/AqKj/8tPT//LO
zv+5p6b/w6qq//fBv//7wr//8LWy/86Ojf/Ojoz/0ZGP/9GSkP/OkY//zpOR/9GamP/VoJ//2qel/+Gv
rf/nt7X/6727/+3Dwf/wycf/8czL//LLyf/yxsT/8cC+//G7uf/yubf/87m3//S7uP/4vrv/1J6c/3JH
RrAdCgsWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANRcXEYJNTcvPiIn/15aW/2VNTf85Ojr/Q0VF/0JF
RP9dXFz/n5GR/+S/v/+bh4f/hXp6/+25uP/7wr//9bu4/9qcmv/Zmpj/252b/96gnf/ipKH/5q+s/+u+
vP/vycf/8srI/+3Hxv/wysj/9c7M//TNy//0ysj/9MbE//TBv//1vrz/9r26//e9u//4vrv/+L+8//vB
vv/hqqf/g1ZVzDwcHC4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW4+Ppq/env/05OT/2ZX
V/9rbm7/fX9//3l6ev99f3//cHJy/5F9ff+ff3//XFhY/9eop//8wr//+L+8/+Wppv/ipaP/5qil/96i
pP/Kmaz/1qi1//LGxP/tyMf/qb3J/23E3P9kw9//vMTN//jDwP/3wb//+MC9//i/vf/5v73/+b+8//i/
vP/3vrv/+L68/92mo/+IWlnRRSMjOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFcv
L0mbX1/y15GS/6GAgP9XV1b/iYuL/4CBgf98fX3/cnR0/1dPT/++j4//km9w/9Sfnv/6wL3/+cC9/+6z
sP/ssK3/0Z+u/4OH1P9YffD/QGPs/7KYyv/Ct7z/Ytrz/3Ts//8s2f//cbvU//m+u//4v7z/+L67//e9
uv/1vLn/9Lq3//O5tv/zuLX/0puZ/4RVVctGIyM4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADIXFwdrPDySq2ts/diZmf/ApKT/sKur/4CBgP95enr/iYiI/49zdP/do6P/36Ch/96e
nv/zuLX/+sK///W7uP/1ubT/qZC//2qY+/9tnf//MGT6/56FxP/esK//nMbS/57n8/9+z+T/ybG3//a6
t//zubb/8re0//C1s//utLH/7rKw/+qvrP++iIb9dklJtkMgISoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHIyMSazw8kZ5hYvXNjI3/2aSk/7OMjP+bd3f/sIKC/9KV
lv/cnJz/2peY/9aRkf/koqL/+sG+//nAvf/5v7z/4amw/6qZx/+aouP/qpvP/+mxtv/2urj/6rGv/+S6
u//ptrX/466n/+Ovqf/ssK7/6q6s/+isqv/oq6n/2J2b/6JubfFoPT2NOxoaFwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBoaCFowMFd7SEjAomZm9sWC
gv/XkZL/25SV/9iSk//Wj5D/1IyN/9KHiP/UiIj/8bOx//rCv//3vbv/9ru4//O3s//xuLX/7q6e/+ej
hf/npIn/7bCp/+Otp/+KsX3/ULdm/1WjWv+7oYz/5KWk/9uenP+4gH79glJRzVYuLlQgCAkGAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA8HBwQVy4uS3FBQaCPV1fjsG5v/cmAgf/ShYb/0YKD/85+f//LeXr/2I2M//e8uf/1vLn/7rOx/+2y
sP/lpJX/5qFY/+6xXP/djS3/35h9/86gl/9SwW7/Nd90/0WxXP+vlH//wYSE/49cW+VlOTmBQR4eHAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGk7OhqIWFd8oG5u8J5qav+eX2D/tmts/8Z0df/KdHX/yXJz/92T
k//3vLn/7LGu/+Snpf/dm5L/4Z1q/+61dP/fmmX/15WM/9eYlv/Bm43/r6uR/6uNgP+WYWDtbkBAnUwn
JzQVAQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiFJSBnhC
QgpqNDQJWSUlB08dHQdfKisKfENDFJJWViinbGtRvYOCjtOcm8/pt7X157y6/7eOjfhxRUW7aTk5m4RK
StehWlr6uGdo/8Zwcf/dkpH/8bSx/+OnpP/YmZj/1ZWT/9ealP/Vl5X/0JCP/8eIhv+zdnb/lFtc6nA/
QKRSKio/JQwNBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADTn6AB2qioDMuUlCHBhYU8voCAWcCBgXTEhoaLzZGQqdeensngrKvn47Sz/NOop/+yiIfyi2Bgs2k+
PlZXKysPAAAAAUYlJRxcMTFYcj4+pYpMTeWmXF3+xnl5/9+Zl//dnJr/z46M/8KCgf+vc3L/ll9e831L
S8hlOTl/TigoMy0REQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABzQUIDnmprDriGhifHlpZMzp6eeNCgoZ7On5+2yJqaybuPj9WnfHzVj2RkunVJ
SYNbLy8/PRQUCgAAAAAAAAAAAAAAAAAAAAAAAAAAKRUVBU0pKSphNDRtd0BAsotNTd2ZW1vrkVlY4HtJ
Sb5lOTmCUysrQTsbGxEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWCwsA2Y4OA5xQkImdkhIRHhKSll0R0dibUBAWWI2
NkNUKCgoOhISDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMhkZB0km
Jh5LJiYsRSEhITATFAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAD/+H////8AAP/gH////wAA/8Af////
AAD/gA////8AAP+AD////wAA/wAP////AAD/AA////8AAP4AB////wAA/gAH////AAD8AAf///8AAPwA
B////wAA/AAH////AAD8AAf///8AAPgAB////wAA+AAH//4HAAD4AAP/8AEAAPgAAf/AAQAA8AAA/wAA
AADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAEAAPAAAAAAAQAA8AAAAAADAADwAAAAAAcAAPAA
AAAADwAA+AAAAAAfAAD4AAAAAD8AAPwAAAAAfwAA/gAAAAD/AAD/gAAAA/8AAP/gAAAH/wAAgAAAAB//
AAAAAAAAf/8AAAAD4AP//wAAgB/8H///AAD///////8AAP///////wAA////////AAD///////8AAP//
/////wAA////////AAAoAAAAIAAAAEAAAAABACAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAYAAAAZAAAAGQAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAARCQkYOh8fb0ooKK80HByiCQUFTAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAIhERFmA2Np2ITUz3lVNT/4dLS/5IKCi9AAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAANjODiBllhY+61kZP+vY2P/pV5e/3xHRvEhEhJfAAAAAgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAASSgoN41VVeS6bW3/xW9w/8dwcf+9bG3/klZW/jogIIEAAAAGAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ1RkWcs2xs/8dxcv/HcHH/x3Bx/8Zwcf+iYWH/SSkpmAAA
AAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUC0tMZtgX+fGcnP/x3Bx/8dwcf/HcHH/x3Fy/61q
av9UMTGqAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxRER1tm9v/8hxcv/HcHH/x3Bx/8dw
cf/HcnP/tnRz/185OboAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAACIxXV7TEdHT/yHJz/8l1
dv/Kd3j/ynd4/8p4eP/Bf37/bURDywAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNKysjo2Zm4Mt4
ef/NfH3/z4GC/9GFhf/RhYb/0YWF/82Mi/9+UVHeCAICOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAJAAAACwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAGc+
Pkm1c3P30IGC/9OJiv/XkZL/2ZaW/9mWl//YlJX/2JmY/5hnZfMeEBBrAAAABwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA0FAgItHhAQWzAbG4IqFxeHDQcHWwAAABkAAAAAAAAAAAAA
AAAAAAAAek1MdMN/f//VjI3/2piZ/9+io//hqKn/4qmp/+Clpf/jpqT/wImH/04xMLwAAAA6AAAABQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABEbDg5GRygokW5CQs+MVlbxnGJh/JdfXvxnPz7hHA8PbgAA
AAwAAAAAAAAAAAAAAACMW1qbz4qK/9qXl//gpqb/5rKz/+q6u//rvLz/6La2/+qxr//epKL/j1lZ+DUc
HLACAQFPAAAAHQAAAA8AAAAPAAAAEwAAACIbDg5MVDExnYZUU+SpbWz+uXl4/7x+fP/AgoD/xoeF/72A
f/9fOzu1AAAAHAAAAAAAAAAAAAAABJhkZK/VkZH/3Z+g/+axsf/twMD/8svL//LNzf/vxcX/8Lq4/+6z
sf+1dHP/j1VU+144N9g7IiKqMhwclDcfH5RGKSmiYTw7v4tZWOiydXT+woOC/8aKiP/Ol5X/2aWj/9ui
of/cnpz/2pyb/35TUrgAAAAVAAAAAAAAAAAAAAAFmmVkstaTk//hpaX/7Lm6//TLy//419f/+NnZ//TP
z//1wb//9Lq3/8aGhP+1dHP/s3Rz/6xwb/+pb27+rnNy/7Z7ev/BhIL/yY2L/8+WlP/apqT/5be2/+vB
v//rvrz/6bKw/+uvrf/Um5n/bUVEgAAAAAMAAAAAAAAAAAAAAAOTXV2q1ZGR/9CYmP+dfX7/o4yM/9e8
vP/z0tL/zLOz/+u8u//5v7z/1peV/8uLif/Ki4r/yoyL/86Ukv/TnJv/2qSi/+Gtq//nuLb/7cPB//DJ
x//xxsT/8b+9//G6t//zubf/77az/6d1dM89Hx8lAAAAAAAAAAAAAAAAAAAAAIJOTojNiIn/jGlp/01O
Tv9UVlb/dnNz/7uhof+Pfn7/xJ+e//zCv//lqKb/3J2b/+Chnv/hpaT/7Ly5/+vHxv/MxMn/0MjN//LK
yf/1x8X/9sLA//a/vP/3vrv/+L+8//S7uP+5hoXhYTo5RwAAAAAAAAAAAAAAAAAAAAAAAAAAaTs7RrVz
dPKmfn7/cXJx/4SGhv97fX3/b2Zm/516ev+7kJD/+sG+//C2s//lqqr/rpbA/3aB2/+ql83/tMHK/2jc
9P9OzOz/2r3B//q/vP/3vrv/9ry6//a8uf/ss7D/tYGA32c+Pk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAvEhIHg01Njbp9fvrCn5//nI+P/4R7ev+fgID/2Jyd/9ybnP/ytrT/+b+8/+ewtf+Mld3/ZI36/5eI
zv/Ttrn/sNLc/6/Czv/stLT/8re0/++0sf/tsq//2qCe/6Rxb8phODg+AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABCIB8MeUZGbqRpata8gYH8x4mJ/9eTk//YkpP/04qL/+Cbmv/5wL3/9726/+Sw
t//Zrrn/56qY/+2smf/lr6n/nLWJ/4Gtdf/Pppn/3qGf/7yEg/KJWViYTyoqIAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQh0dGXJAQGOXXl7NtnR1/8V7fP/MfH3/znt8/+il
o//0urj/7LCu/+Whg//rq13/35VX/9Kek/9yvXz/ZbNv/6iCdfqYY2O/aj4+TCUJCgcAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACcamsBjFRVB4FERAh9PT0JjU1ND6VnZx+/hINF0JqZiNOjoty0iIf2hFBQw5lX
V8+wY2P4xXR0/+aioP/oq6j/2pqT/92fif/Vlor/yYqJ/7N8efiVZmPGdERFYkEfHxIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALiFhgXFkJEdx5CQSMqSknbNlZWbz5uaws2cnOXBlJPnqH18r4dc
XFFULy8OSCUlFm07O0+FSUmeoV1d3sF9fPrGhoX/snZ295xkZNiFUlKbbD4+T0UdHxIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc0JDA5FgYRKdbm46onR0Zp9ycnuWampzhFlZVmY6
OikvDAwHAAAAAAAAAAAAAAAAAAAAAB0ODgRULCwhbjo7UXhERGVrPDxHTCYmGxAAAQMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//////////////////////D////gf///wH///4A///+AP///AD///wA///8AP//+AD
///gA//D4AH+AeAA+ADgAAAAwAAAAMAAAADAAAAB4AAAA+AAAAfgAAAP8AAAH/wAAD8AAAD/AAAD/wB4
D//H////////////////////KAAAABgAAAAwAAAAAQAgAAAAAABgCQAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAABMAAAAtAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAgIO1cwMM1qOjrsHhAQmwAA
ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAATCgogfUhI6ahgYP6lXV3+f0hI9wIBAT0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsGBgFPLy6kuW1t/sZv
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
</value>
</data>
</root>

View File

@ -28,413 +28,431 @@
/// </summary>
private void InitializeComponent()
{
this.cbMultitap_1 = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.lbl_p_1_4 = new System.Windows.Forms.Label();
this.lbl_p_1_3 = new System.Windows.Forms.Label();
this.lbl_p_1_2 = new System.Windows.Forms.Label();
this.lbl_p_1_1 = new System.Windows.Forms.Label();
this.lbl_1_4 = new System.Windows.Forms.Label();
this.lbl_1_3 = new System.Windows.Forms.Label();
this.lbl_1_2 = new System.Windows.Forms.Label();
this.lbl_1_1 = new System.Windows.Forms.Label();
this.combo_1_4 = new System.Windows.Forms.ComboBox();
this.combo_1_3 = new System.Windows.Forms.ComboBox();
this.combo_1_2 = new System.Windows.Forms.ComboBox();
this.combo_1_1 = new System.Windows.Forms.ComboBox();
this.cbMemcard_1 = new System.Windows.Forms.CheckBox();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.lbl_p_2_4 = new System.Windows.Forms.Label();
this.lbl_p_2_3 = new System.Windows.Forms.Label();
this.lbl_p_2_2 = new System.Windows.Forms.Label();
this.lbl_p_2_1 = new System.Windows.Forms.Label();
this.lbl_2_4 = new System.Windows.Forms.Label();
this.lbl_2_3 = new System.Windows.Forms.Label();
this.lbl_2_2 = new System.Windows.Forms.Label();
this.lbl_2_1 = new System.Windows.Forms.Label();
this.combo_2_4 = new System.Windows.Forms.ComboBox();
this.combo_2_3 = new System.Windows.Forms.ComboBox();
this.combo_2_2 = new System.Windows.Forms.ComboBox();
this.combo_2_1 = new System.Windows.Forms.ComboBox();
this.cbMemcard_2 = new System.Windows.Forms.CheckBox();
this.cbMultitap_2 = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// cbMultitap_1
//
this.cbMultitap_1.AutoSize = true;
this.cbMultitap_1.Location = new System.Drawing.Point(18, 43);
this.cbMultitap_1.Name = "cbMultitap_1";
this.cbMultitap_1.Size = new System.Drawing.Size(63, 17);
this.cbMultitap_1.TabIndex = 0;
this.cbMultitap_1.Text = "Multitap";
this.cbMultitap_1.UseVisualStyleBackColor = true;
this.cbMultitap_1.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.lbl_p_1_4);
this.groupBox1.Controls.Add(this.lbl_p_1_3);
this.groupBox1.Controls.Add(this.lbl_p_1_2);
this.groupBox1.Controls.Add(this.lbl_p_1_1);
this.groupBox1.Controls.Add(this.lbl_1_4);
this.groupBox1.Controls.Add(this.lbl_1_3);
this.groupBox1.Controls.Add(this.lbl_1_2);
this.groupBox1.Controls.Add(this.lbl_1_1);
this.groupBox1.Controls.Add(this.combo_1_4);
this.groupBox1.Controls.Add(this.combo_1_3);
this.groupBox1.Controls.Add(this.combo_1_2);
this.groupBox1.Controls.Add(this.combo_1_1);
this.groupBox1.Controls.Add(this.cbMemcard_1);
this.groupBox1.Controls.Add(this.cbMultitap_1);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(273, 136);
this.groupBox1.TabIndex = 1;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Port 1";
//
// lbl_p_1_4
//
this.lbl_p_1_4.AutoSize = true;
this.lbl_p_1_4.Location = new System.Drawing.Point(241, 105);
this.lbl_p_1_4.Name = "lbl_p_1_4";
this.lbl_p_1_4.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_4.TabIndex = 12;
this.lbl_p_1_4.Text = "P1";
this.lbl_p_1_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_1_3
//
this.lbl_p_1_3.AutoSize = true;
this.lbl_p_1_3.Location = new System.Drawing.Point(241, 78);
this.lbl_p_1_3.Name = "lbl_p_1_3";
this.lbl_p_1_3.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_3.TabIndex = 11;
this.lbl_p_1_3.Text = "P1";
this.lbl_p_1_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_1_2
//
this.lbl_p_1_2.AutoSize = true;
this.lbl_p_1_2.Location = new System.Drawing.Point(241, 50);
this.lbl_p_1_2.Name = "lbl_p_1_2";
this.lbl_p_1_2.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_2.TabIndex = 10;
this.lbl_p_1_2.Text = "P1";
this.lbl_p_1_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_1_1
//
this.lbl_p_1_1.AutoSize = true;
this.lbl_p_1_1.Location = new System.Drawing.Point(241, 24);
this.lbl_p_1_1.Name = "lbl_p_1_1";
this.lbl_p_1_1.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_1.TabIndex = 9;
this.lbl_p_1_1.Text = "P1";
this.lbl_p_1_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_4
//
this.lbl_1_4.AutoSize = true;
this.lbl_1_4.Location = new System.Drawing.Point(94, 105);
this.lbl_1_4.Name = "lbl_1_4";
this.lbl_1_4.Size = new System.Drawing.Size(15, 13);
this.lbl_1_4.TabIndex = 8;
this.lbl_1_4.Text = "D";
this.lbl_1_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_3
//
this.lbl_1_3.AutoSize = true;
this.lbl_1_3.Location = new System.Drawing.Point(94, 78);
this.lbl_1_3.Name = "lbl_1_3";
this.lbl_1_3.Size = new System.Drawing.Size(14, 13);
this.lbl_1_3.TabIndex = 7;
this.lbl_1_3.Text = "C";
this.lbl_1_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_2
//
this.lbl_1_2.AutoSize = true;
this.lbl_1_2.Location = new System.Drawing.Point(94, 51);
this.lbl_1_2.Name = "lbl_1_2";
this.lbl_1_2.Size = new System.Drawing.Size(14, 13);
this.lbl_1_2.TabIndex = 6;
this.lbl_1_2.Text = "B";
this.lbl_1_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_1
//
this.lbl_1_1.AutoSize = true;
this.lbl_1_1.Location = new System.Drawing.Point(94, 24);
this.lbl_1_1.Name = "lbl_1_1";
this.lbl_1_1.Size = new System.Drawing.Size(14, 13);
this.lbl_1_1.TabIndex = 2;
this.lbl_1_1.Text = "A";
this.lbl_1_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// combo_1_4
//
this.combo_1_4.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_4.FormattingEnabled = true;
this.combo_1_4.Location = new System.Drawing.Point(114, 102);
this.combo_1_4.Name = "combo_1_4";
this.combo_1_4.Size = new System.Drawing.Size(121, 21);
this.combo_1_4.TabIndex = 5;
this.combo_1_4.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_1_3
//
this.combo_1_3.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_3.FormattingEnabled = true;
this.combo_1_3.Location = new System.Drawing.Point(114, 75);
this.combo_1_3.Name = "combo_1_3";
this.combo_1_3.Size = new System.Drawing.Size(121, 21);
this.combo_1_3.TabIndex = 4;
this.combo_1_3.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_1_2
//
this.combo_1_2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_2.FormattingEnabled = true;
this.combo_1_2.Location = new System.Drawing.Point(114, 48);
this.combo_1_2.Name = "combo_1_2";
this.combo_1_2.Size = new System.Drawing.Size(121, 21);
this.combo_1_2.TabIndex = 3;
this.combo_1_2.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_1_1
//
this.combo_1_1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_1.FormattingEnabled = true;
this.combo_1_1.Location = new System.Drawing.Point(114, 21);
this.combo_1_1.Name = "combo_1_1";
this.combo_1_1.Size = new System.Drawing.Size(121, 21);
this.combo_1_1.TabIndex = 2;
this.combo_1_1.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// cbMemcard_1
//
this.cbMemcard_1.AutoSize = true;
this.cbMemcard_1.Location = new System.Drawing.Point(18, 21);
this.cbMemcard_1.Name = "cbMemcard_1";
this.cbMemcard_1.Size = new System.Drawing.Size(70, 17);
this.cbMemcard_1.TabIndex = 1;
this.cbMemcard_1.Text = "Memcard";
this.cbMemcard_1.UseVisualStyleBackColor = true;
this.cbMemcard_1.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(408, 163);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
this.btnOK.TabIndex = 2;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(489, 163);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.lbl_p_2_4);
this.groupBox2.Controls.Add(this.lbl_p_2_3);
this.groupBox2.Controls.Add(this.lbl_p_2_2);
this.groupBox2.Controls.Add(this.lbl_p_2_1);
this.groupBox2.Controls.Add(this.lbl_2_4);
this.groupBox2.Controls.Add(this.lbl_2_3);
this.groupBox2.Controls.Add(this.lbl_2_2);
this.groupBox2.Controls.Add(this.lbl_2_1);
this.groupBox2.Controls.Add(this.combo_2_4);
this.groupBox2.Controls.Add(this.combo_2_3);
this.groupBox2.Controls.Add(this.combo_2_2);
this.groupBox2.Controls.Add(this.combo_2_1);
this.groupBox2.Controls.Add(this.cbMemcard_2);
this.groupBox2.Controls.Add(this.cbMultitap_2);
this.groupBox2.Location = new System.Drawing.Point(291, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(273, 136);
this.groupBox2.TabIndex = 13;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Port 2";
//
// lbl_p_2_4
//
this.lbl_p_2_4.AutoSize = true;
this.lbl_p_2_4.Location = new System.Drawing.Point(241, 105);
this.lbl_p_2_4.Name = "lbl_p_2_4";
this.lbl_p_2_4.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_4.TabIndex = 12;
this.lbl_p_2_4.Text = "P1";
this.lbl_p_2_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_2_3
//
this.lbl_p_2_3.AutoSize = true;
this.lbl_p_2_3.Location = new System.Drawing.Point(241, 78);
this.lbl_p_2_3.Name = "lbl_p_2_3";
this.lbl_p_2_3.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_3.TabIndex = 11;
this.lbl_p_2_3.Text = "P1";
this.lbl_p_2_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_2_2
//
this.lbl_p_2_2.AutoSize = true;
this.lbl_p_2_2.Location = new System.Drawing.Point(241, 50);
this.lbl_p_2_2.Name = "lbl_p_2_2";
this.lbl_p_2_2.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_2.TabIndex = 10;
this.lbl_p_2_2.Text = "P1";
this.lbl_p_2_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_2_1
//
this.lbl_p_2_1.AutoSize = true;
this.lbl_p_2_1.Location = new System.Drawing.Point(241, 24);
this.lbl_p_2_1.Name = "lbl_p_2_1";
this.lbl_p_2_1.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_1.TabIndex = 9;
this.lbl_p_2_1.Text = "P1";
this.lbl_p_2_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_4
//
this.lbl_2_4.AutoSize = true;
this.lbl_2_4.Location = new System.Drawing.Point(94, 105);
this.lbl_2_4.Name = "lbl_2_4";
this.lbl_2_4.Size = new System.Drawing.Size(15, 13);
this.lbl_2_4.TabIndex = 8;
this.lbl_2_4.Text = "D";
this.lbl_2_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_3
//
this.lbl_2_3.AutoSize = true;
this.lbl_2_3.Location = new System.Drawing.Point(94, 78);
this.lbl_2_3.Name = "lbl_2_3";
this.lbl_2_3.Size = new System.Drawing.Size(14, 13);
this.lbl_2_3.TabIndex = 7;
this.lbl_2_3.Text = "C";
this.lbl_2_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_2
//
this.lbl_2_2.AutoSize = true;
this.lbl_2_2.Location = new System.Drawing.Point(94, 51);
this.lbl_2_2.Name = "lbl_2_2";
this.lbl_2_2.Size = new System.Drawing.Size(14, 13);
this.lbl_2_2.TabIndex = 6;
this.lbl_2_2.Text = "B";
this.lbl_2_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_1
//
this.lbl_2_1.AutoSize = true;
this.lbl_2_1.Location = new System.Drawing.Point(94, 24);
this.lbl_2_1.Name = "lbl_2_1";
this.lbl_2_1.Size = new System.Drawing.Size(14, 13);
this.lbl_2_1.TabIndex = 2;
this.lbl_2_1.Text = "A";
this.lbl_2_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// combo_2_4
//
this.combo_2_4.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_4.FormattingEnabled = true;
this.combo_2_4.Location = new System.Drawing.Point(114, 102);
this.combo_2_4.Name = "combo_2_4";
this.combo_2_4.Size = new System.Drawing.Size(121, 21);
this.combo_2_4.TabIndex = 5;
this.combo_2_4.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_2_3
//
this.combo_2_3.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_3.FormattingEnabled = true;
this.combo_2_3.Location = new System.Drawing.Point(114, 75);
this.combo_2_3.Name = "combo_2_3";
this.combo_2_3.Size = new System.Drawing.Size(121, 21);
this.combo_2_3.TabIndex = 4;
this.combo_2_3.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_2_2
//
this.combo_2_2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_2.FormattingEnabled = true;
this.combo_2_2.Location = new System.Drawing.Point(114, 48);
this.combo_2_2.Name = "combo_2_2";
this.combo_2_2.Size = new System.Drawing.Size(121, 21);
this.combo_2_2.TabIndex = 3;
this.combo_2_2.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_2_1
//
this.combo_2_1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_1.FormattingEnabled = true;
this.combo_2_1.Location = new System.Drawing.Point(114, 21);
this.combo_2_1.Name = "combo_2_1";
this.combo_2_1.Size = new System.Drawing.Size(121, 21);
this.combo_2_1.TabIndex = 2;
this.combo_2_1.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// cbMemcard_2
//
this.cbMemcard_2.AutoSize = true;
this.cbMemcard_2.Location = new System.Drawing.Point(18, 21);
this.cbMemcard_2.Name = "cbMemcard_2";
this.cbMemcard_2.Size = new System.Drawing.Size(70, 17);
this.cbMemcard_2.TabIndex = 1;
this.cbMemcard_2.Text = "Memcard";
this.cbMemcard_2.UseVisualStyleBackColor = true;
this.cbMemcard_2.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// cbMultitap_2
//
this.cbMultitap_2.AutoSize = true;
this.cbMultitap_2.Location = new System.Drawing.Point(18, 43);
this.cbMultitap_2.Name = "cbMultitap_2";
this.cbMultitap_2.Size = new System.Drawing.Size(63, 17);
this.cbMultitap_2.TabIndex = 0;
this.cbMultitap_2.Text = "Multitap";
this.cbMultitap_2.UseVisualStyleBackColor = true;
this.cbMultitap_2.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// PSXControllerConfigNew
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(586, 201);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOK);
this.Controls.Add(this.groupBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PSXControllerConfigNew";
this.Text = "PSX FrontIO Configuration";
this.Load += new System.EventHandler(this.PSXControllerConfigNew_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.ResumeLayout(false);
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PSXControllerConfigNew));
this.cbMultitap_1 = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.lbl_p_1_4 = new System.Windows.Forms.Label();
this.lbl_p_1_3 = new System.Windows.Forms.Label();
this.lbl_p_1_2 = new System.Windows.Forms.Label();
this.lbl_p_1_1 = new System.Windows.Forms.Label();
this.lbl_1_4 = new System.Windows.Forms.Label();
this.lbl_1_3 = new System.Windows.Forms.Label();
this.lbl_1_2 = new System.Windows.Forms.Label();
this.lbl_1_1 = new System.Windows.Forms.Label();
this.combo_1_4 = new System.Windows.Forms.ComboBox();
this.combo_1_3 = new System.Windows.Forms.ComboBox();
this.combo_1_2 = new System.Windows.Forms.ComboBox();
this.combo_1_1 = new System.Windows.Forms.ComboBox();
this.cbMemcard_1 = new System.Windows.Forms.CheckBox();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.lbl_p_2_4 = new System.Windows.Forms.Label();
this.lbl_p_2_3 = new System.Windows.Forms.Label();
this.lbl_p_2_2 = new System.Windows.Forms.Label();
this.lbl_p_2_1 = new System.Windows.Forms.Label();
this.lbl_2_4 = new System.Windows.Forms.Label();
this.lbl_2_3 = new System.Windows.Forms.Label();
this.lbl_2_2 = new System.Windows.Forms.Label();
this.lbl_2_1 = new System.Windows.Forms.Label();
this.combo_2_4 = new System.Windows.Forms.ComboBox();
this.combo_2_3 = new System.Windows.Forms.ComboBox();
this.combo_2_2 = new System.Windows.Forms.ComboBox();
this.combo_2_1 = new System.Windows.Forms.ComboBox();
this.cbMemcard_2 = new System.Windows.Forms.CheckBox();
this.cbMultitap_2 = new System.Windows.Forms.CheckBox();
this.label1 = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// cbMultitap_1
//
this.cbMultitap_1.AutoSize = true;
this.cbMultitap_1.Enabled = false;
this.cbMultitap_1.Location = new System.Drawing.Point(18, 43);
this.cbMultitap_1.Name = "cbMultitap_1";
this.cbMultitap_1.Size = new System.Drawing.Size(63, 17);
this.cbMultitap_1.TabIndex = 0;
this.cbMultitap_1.Text = "Multitap";
this.cbMultitap_1.UseVisualStyleBackColor = true;
this.cbMultitap_1.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.lbl_p_1_4);
this.groupBox1.Controls.Add(this.lbl_p_1_3);
this.groupBox1.Controls.Add(this.lbl_p_1_2);
this.groupBox1.Controls.Add(this.lbl_p_1_1);
this.groupBox1.Controls.Add(this.lbl_1_4);
this.groupBox1.Controls.Add(this.lbl_1_3);
this.groupBox1.Controls.Add(this.lbl_1_2);
this.groupBox1.Controls.Add(this.lbl_1_1);
this.groupBox1.Controls.Add(this.combo_1_4);
this.groupBox1.Controls.Add(this.combo_1_3);
this.groupBox1.Controls.Add(this.combo_1_2);
this.groupBox1.Controls.Add(this.combo_1_1);
this.groupBox1.Controls.Add(this.cbMemcard_1);
this.groupBox1.Controls.Add(this.cbMultitap_1);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(273, 136);
this.groupBox1.TabIndex = 1;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Port 1";
//
// lbl_p_1_4
//
this.lbl_p_1_4.AutoSize = true;
this.lbl_p_1_4.Location = new System.Drawing.Point(241, 105);
this.lbl_p_1_4.Name = "lbl_p_1_4";
this.lbl_p_1_4.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_4.TabIndex = 12;
this.lbl_p_1_4.Text = "P1";
this.lbl_p_1_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_1_3
//
this.lbl_p_1_3.AutoSize = true;
this.lbl_p_1_3.Location = new System.Drawing.Point(241, 78);
this.lbl_p_1_3.Name = "lbl_p_1_3";
this.lbl_p_1_3.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_3.TabIndex = 11;
this.lbl_p_1_3.Text = "P1";
this.lbl_p_1_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_1_2
//
this.lbl_p_1_2.AutoSize = true;
this.lbl_p_1_2.Location = new System.Drawing.Point(241, 50);
this.lbl_p_1_2.Name = "lbl_p_1_2";
this.lbl_p_1_2.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_2.TabIndex = 10;
this.lbl_p_1_2.Text = "P1";
this.lbl_p_1_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_1_1
//
this.lbl_p_1_1.AutoSize = true;
this.lbl_p_1_1.Location = new System.Drawing.Point(241, 24);
this.lbl_p_1_1.Name = "lbl_p_1_1";
this.lbl_p_1_1.Size = new System.Drawing.Size(20, 13);
this.lbl_p_1_1.TabIndex = 9;
this.lbl_p_1_1.Text = "P1";
this.lbl_p_1_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_4
//
this.lbl_1_4.AutoSize = true;
this.lbl_1_4.Location = new System.Drawing.Point(94, 105);
this.lbl_1_4.Name = "lbl_1_4";
this.lbl_1_4.Size = new System.Drawing.Size(15, 13);
this.lbl_1_4.TabIndex = 8;
this.lbl_1_4.Text = "D";
this.lbl_1_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_3
//
this.lbl_1_3.AutoSize = true;
this.lbl_1_3.Location = new System.Drawing.Point(94, 78);
this.lbl_1_3.Name = "lbl_1_3";
this.lbl_1_3.Size = new System.Drawing.Size(14, 13);
this.lbl_1_3.TabIndex = 7;
this.lbl_1_3.Text = "C";
this.lbl_1_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_2
//
this.lbl_1_2.AutoSize = true;
this.lbl_1_2.Location = new System.Drawing.Point(94, 51);
this.lbl_1_2.Name = "lbl_1_2";
this.lbl_1_2.Size = new System.Drawing.Size(14, 13);
this.lbl_1_2.TabIndex = 6;
this.lbl_1_2.Text = "B";
this.lbl_1_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_1_1
//
this.lbl_1_1.AutoSize = true;
this.lbl_1_1.Location = new System.Drawing.Point(94, 24);
this.lbl_1_1.Name = "lbl_1_1";
this.lbl_1_1.Size = new System.Drawing.Size(14, 13);
this.lbl_1_1.TabIndex = 2;
this.lbl_1_1.Text = "A";
this.lbl_1_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// combo_1_4
//
this.combo_1_4.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_4.FormattingEnabled = true;
this.combo_1_4.Location = new System.Drawing.Point(114, 102);
this.combo_1_4.Name = "combo_1_4";
this.combo_1_4.Size = new System.Drawing.Size(121, 21);
this.combo_1_4.TabIndex = 5;
this.combo_1_4.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_1_3
//
this.combo_1_3.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_3.FormattingEnabled = true;
this.combo_1_3.Location = new System.Drawing.Point(114, 75);
this.combo_1_3.Name = "combo_1_3";
this.combo_1_3.Size = new System.Drawing.Size(121, 21);
this.combo_1_3.TabIndex = 4;
this.combo_1_3.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_1_2
//
this.combo_1_2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_2.FormattingEnabled = true;
this.combo_1_2.Location = new System.Drawing.Point(114, 48);
this.combo_1_2.Name = "combo_1_2";
this.combo_1_2.Size = new System.Drawing.Size(121, 21);
this.combo_1_2.TabIndex = 3;
this.combo_1_2.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_1_1
//
this.combo_1_1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_1_1.FormattingEnabled = true;
this.combo_1_1.Location = new System.Drawing.Point(114, 21);
this.combo_1_1.Name = "combo_1_1";
this.combo_1_1.Size = new System.Drawing.Size(121, 21);
this.combo_1_1.TabIndex = 2;
this.combo_1_1.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// cbMemcard_1
//
this.cbMemcard_1.AutoSize = true;
this.cbMemcard_1.Location = new System.Drawing.Point(18, 21);
this.cbMemcard_1.Name = "cbMemcard_1";
this.cbMemcard_1.Size = new System.Drawing.Size(70, 17);
this.cbMemcard_1.TabIndex = 1;
this.cbMemcard_1.Text = "Memcard";
this.cbMemcard_1.UseVisualStyleBackColor = true;
this.cbMemcard_1.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(408, 163);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(75, 23);
this.btnOK.TabIndex = 2;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(489, 163);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.lbl_p_2_4);
this.groupBox2.Controls.Add(this.lbl_p_2_3);
this.groupBox2.Controls.Add(this.lbl_p_2_2);
this.groupBox2.Controls.Add(this.lbl_p_2_1);
this.groupBox2.Controls.Add(this.lbl_2_4);
this.groupBox2.Controls.Add(this.lbl_2_3);
this.groupBox2.Controls.Add(this.lbl_2_2);
this.groupBox2.Controls.Add(this.lbl_2_1);
this.groupBox2.Controls.Add(this.combo_2_4);
this.groupBox2.Controls.Add(this.combo_2_3);
this.groupBox2.Controls.Add(this.combo_2_2);
this.groupBox2.Controls.Add(this.combo_2_1);
this.groupBox2.Controls.Add(this.cbMemcard_2);
this.groupBox2.Controls.Add(this.cbMultitap_2);
this.groupBox2.Location = new System.Drawing.Point(291, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(273, 136);
this.groupBox2.TabIndex = 13;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Port 2";
//
// lbl_p_2_4
//
this.lbl_p_2_4.AutoSize = true;
this.lbl_p_2_4.Location = new System.Drawing.Point(241, 105);
this.lbl_p_2_4.Name = "lbl_p_2_4";
this.lbl_p_2_4.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_4.TabIndex = 12;
this.lbl_p_2_4.Text = "P1";
this.lbl_p_2_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_2_3
//
this.lbl_p_2_3.AutoSize = true;
this.lbl_p_2_3.Location = new System.Drawing.Point(241, 78);
this.lbl_p_2_3.Name = "lbl_p_2_3";
this.lbl_p_2_3.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_3.TabIndex = 11;
this.lbl_p_2_3.Text = "P1";
this.lbl_p_2_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_2_2
//
this.lbl_p_2_2.AutoSize = true;
this.lbl_p_2_2.Location = new System.Drawing.Point(241, 50);
this.lbl_p_2_2.Name = "lbl_p_2_2";
this.lbl_p_2_2.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_2.TabIndex = 10;
this.lbl_p_2_2.Text = "P1";
this.lbl_p_2_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_p_2_1
//
this.lbl_p_2_1.AutoSize = true;
this.lbl_p_2_1.Location = new System.Drawing.Point(241, 24);
this.lbl_p_2_1.Name = "lbl_p_2_1";
this.lbl_p_2_1.Size = new System.Drawing.Size(20, 13);
this.lbl_p_2_1.TabIndex = 9;
this.lbl_p_2_1.Text = "P1";
this.lbl_p_2_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_4
//
this.lbl_2_4.AutoSize = true;
this.lbl_2_4.Location = new System.Drawing.Point(94, 105);
this.lbl_2_4.Name = "lbl_2_4";
this.lbl_2_4.Size = new System.Drawing.Size(15, 13);
this.lbl_2_4.TabIndex = 8;
this.lbl_2_4.Text = "D";
this.lbl_2_4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_3
//
this.lbl_2_3.AutoSize = true;
this.lbl_2_3.Location = new System.Drawing.Point(94, 78);
this.lbl_2_3.Name = "lbl_2_3";
this.lbl_2_3.Size = new System.Drawing.Size(14, 13);
this.lbl_2_3.TabIndex = 7;
this.lbl_2_3.Text = "C";
this.lbl_2_3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_2
//
this.lbl_2_2.AutoSize = true;
this.lbl_2_2.Location = new System.Drawing.Point(94, 51);
this.lbl_2_2.Name = "lbl_2_2";
this.lbl_2_2.Size = new System.Drawing.Size(14, 13);
this.lbl_2_2.TabIndex = 6;
this.lbl_2_2.Text = "B";
this.lbl_2_2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lbl_2_1
//
this.lbl_2_1.AutoSize = true;
this.lbl_2_1.Location = new System.Drawing.Point(94, 24);
this.lbl_2_1.Name = "lbl_2_1";
this.lbl_2_1.Size = new System.Drawing.Size(14, 13);
this.lbl_2_1.TabIndex = 2;
this.lbl_2_1.Text = "A";
this.lbl_2_1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// combo_2_4
//
this.combo_2_4.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_4.FormattingEnabled = true;
this.combo_2_4.Location = new System.Drawing.Point(114, 102);
this.combo_2_4.Name = "combo_2_4";
this.combo_2_4.Size = new System.Drawing.Size(121, 21);
this.combo_2_4.TabIndex = 5;
this.combo_2_4.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_2_3
//
this.combo_2_3.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_3.FormattingEnabled = true;
this.combo_2_3.Location = new System.Drawing.Point(114, 75);
this.combo_2_3.Name = "combo_2_3";
this.combo_2_3.Size = new System.Drawing.Size(121, 21);
this.combo_2_3.TabIndex = 4;
this.combo_2_3.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_2_2
//
this.combo_2_2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_2.FormattingEnabled = true;
this.combo_2_2.Location = new System.Drawing.Point(114, 48);
this.combo_2_2.Name = "combo_2_2";
this.combo_2_2.Size = new System.Drawing.Size(121, 21);
this.combo_2_2.TabIndex = 3;
this.combo_2_2.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// combo_2_1
//
this.combo_2_1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_2_1.FormattingEnabled = true;
this.combo_2_1.Location = new System.Drawing.Point(114, 21);
this.combo_2_1.Name = "combo_2_1";
this.combo_2_1.Size = new System.Drawing.Size(121, 21);
this.combo_2_1.TabIndex = 2;
this.combo_2_1.SelectedIndexChanged += new System.EventHandler(this.combo_SelectedIndexChanged);
//
// cbMemcard_2
//
this.cbMemcard_2.AutoSize = true;
this.cbMemcard_2.Location = new System.Drawing.Point(18, 21);
this.cbMemcard_2.Name = "cbMemcard_2";
this.cbMemcard_2.Size = new System.Drawing.Size(70, 17);
this.cbMemcard_2.TabIndex = 1;
this.cbMemcard_2.Text = "Memcard";
this.cbMemcard_2.UseVisualStyleBackColor = true;
this.cbMemcard_2.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// cbMultitap_2
//
this.cbMultitap_2.AutoSize = true;
this.cbMultitap_2.Enabled = false;
this.cbMultitap_2.Location = new System.Drawing.Point(18, 43);
this.cbMultitap_2.Name = "cbMultitap_2";
this.cbMultitap_2.Size = new System.Drawing.Size(63, 17);
this.cbMultitap_2.TabIndex = 0;
this.cbMultitap_2.Text = "Multitap";
this.cbMultitap_2.UseVisualStyleBackColor = true;
this.cbMultitap_2.CheckedChanged += new System.EventHandler(this.cb_changed);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 172);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(177, 13);
this.label1.TabIndex = 14;
this.label1.Text = "Sorry, multitap not supported just yet";
//
// PSXControllerConfigNew
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(586, 201);
this.Controls.Add(this.label1);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOK);
this.Controls.Add(this.groupBox1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PSXControllerConfigNew";
this.Text = "Controller / Memcard Configuration";
this.Load += new System.EventHandler(this.PSXControllerConfigNew_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
@ -470,6 +488,7 @@
private System.Windows.Forms.ComboBox combo_2_2;
private System.Windows.Forms.ComboBox combo_2_1;
private System.Windows.Forms.CheckBox cbMemcard_2;
private System.Windows.Forms.CheckBox cbMultitap_2;
private System.Windows.Forms.CheckBox cbMultitap_2;
private System.Windows.Forms.Label label1;
}
}

View File

@ -34,15 +34,56 @@ namespace BizHawk.Client.EmuHawk
combo.SelectedIndex = 0;
}
var psxSettings = ((Octoshock)Global.Emulator).GetSyncSettings();
GuiFromUserConfig(psxSettings.FIOConfig);
RefreshLabels();
}
void GuiFromUserConfig(OctoshockFIOConfigUser user)
{
cbMemcard_1.Checked = user.Memcards[0];
cbMemcard_2.Checked = user.Memcards[1];
cbMultitap_1.Checked = user.Multitaps[0];
cbMultitap_2.Checked = user.Multitaps[1];
var combos = new[] { combo_1_1, combo_1_2, combo_1_3, combo_1_4, combo_2_1, combo_2_2, combo_2_3, combo_2_4 };
for (int i = 0; i < 8; i++)
{
var combo = combos[i];
if (user.Devices8[i] == OctoshockDll.ePeripheralType.None) combo.SelectedIndex = 0;
if (user.Devices8[i] == OctoshockDll.ePeripheralType.DualAnalog) combo.SelectedIndex = 1;
if (user.Devices8[i] == OctoshockDll.ePeripheralType.DualShock) combo.SelectedIndex = 2;
}
}
OctoshockFIOConfigUser UserConfigFromGui()
{
OctoshockFIOConfigUser uc = new OctoshockFIOConfigUser();
uc.Memcards[0] = cbMemcard_1.Checked;
uc.Memcards[1] = cbMemcard_2.Checked;
uc.Multitaps[0] = cbMultitap_1.Checked;
uc.Multitaps[1] = cbMultitap_2.Checked;
var combos = new[] { combo_1_1, combo_1_2, combo_1_3, combo_1_4, combo_2_1, combo_2_2, combo_2_3, combo_2_4 };
for (int i = 0; i < 8; i++)
{
var combo = combos[i];
if (combo.SelectedIndex == 0) uc.Devices8[i] = OctoshockDll.ePeripheralType.None;
if (combo.SelectedIndex == 1) uc.Devices8[i] = OctoshockDll.ePeripheralType.DualAnalog;
if (combo.SelectedIndex == 2) uc.Devices8[i] = OctoshockDll.ePeripheralType.DualShock;
}
return uc;
}
void RefreshLabels()
{
bool multitap_1 = cbMultitap_1.Checked;
bool multitap_2 = cbMultitap_2.Checked;
{
var uc = UserConfigFromGui();
bool b1 = multitap_1;
bool b1 = uc.Multitaps[0];
lbl_1_1.Visible = b1;
lbl_1_2.Visible = b1;
lbl_1_3.Visible = b1;
@ -52,9 +93,9 @@ namespace BizHawk.Client.EmuHawk
combo_1_4.Enabled = b1;
lbl_p_1_2.Visible = b1;
lbl_p_1_3.Visible = b1;
lbl_p_1_4.Visible = b1;
bool b2 = multitap_2;
lbl_p_1_4.Visible = b1;
bool b2 = uc.Multitaps[1];
lbl_2_1.Visible = b2;
lbl_2_2.Visible = b2;
lbl_2_3.Visible = b2;
@ -66,21 +107,7 @@ namespace BizHawk.Client.EmuHawk
lbl_p_2_3.Visible = b2;
lbl_p_2_4.Visible = b2;
OctoshockControlUserConfig uc = new OctoshockControlUserConfig();
uc.Multitaps[0] = multitap_1;
uc.Multitaps[1] = multitap_2;
var combos = new[] { combo_1_1, combo_1_2, combo_1_3, combo_1_4, combo_2_1, combo_2_2, combo_2_3, combo_2_4};
for (int i = 0; i < 8; i++)
{
var combo = combos[i];
if (combo.SelectedIndex == 0) uc.Devices8[i] = OctoshockDll.ePeripheralType.None;
if (combo.SelectedIndex == 1) uc.Devices8[i] = OctoshockDll.ePeripheralType.DualAnalog;
if (combo.SelectedIndex == 2) uc.Devices8[i] = OctoshockDll.ePeripheralType.DualShock;
}
var LC = uc.ToLogicalConfig();
var LC = uc.ToLogical();
var p_labels = new[] { lbl_p_1_1,lbl_p_1_2,lbl_p_1_3,lbl_p_1_4,lbl_p_2_1,lbl_p_2_2,lbl_p_2_3,lbl_p_2_4};
for (int i = 0; i < 8; i++)
@ -94,7 +121,6 @@ namespace BizHawk.Client.EmuHawk
lbl.Visible = true;
}
}
}
private void cb_changed(object sender, EventArgs e)
@ -105,6 +131,18 @@ namespace BizHawk.Client.EmuHawk
private void combo_SelectedIndexChanged(object sender, EventArgs e)
{
RefreshLabels();
}
private void btnOK_Click(object sender, EventArgs e)
{
var psxSettings = ((Octoshock)Global.Emulator).GetSyncSettings();
psxSettings.FIOConfig = UserConfigFromGui();
GlobalWin.MainForm.PutCoreSyncSettings(psxSettings);
DialogResult = DialogResult.OK;
Close();
}
}
}

View File

@ -1,120 +1,624 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAwAMDAQAAAABABoBgAAxgAAACAgEAAAAAQA6AIAAC4HAAAYGBAAAAAEAOgBAAAWCgAAEBAQAAAA
BAAoAQAA/gsAADAwAAAAAAgAqA4AACYNAAAgIAAAAAAIAKgIAADOGwAAGBgAAAAACADIBgAAdiQAABAQ
AAAAAAgAaAUAAD4rAAAwMAAAAAAgAKglAACmMAAAICAAAAAAIACoEAAATlYAABgYAAAAACAAiAkAAPZm
AAAQEAAAAAAgAGgEAAB+cAAAKAAAADAAAABgAAAAAQAEAAAAAACABAAAAAAAAAAAAAAQAAAAEAAAAAAA
AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP//
/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAHR3AAAAAAAAAAAAAAAAAAAAAAAAAAAAdHdEcAAAAAAAAAAAAAAAAA
AAAAAAAAAHd0d3QAAAAAAAAAAAAAAAAAAAAAAAAAAEd8d3UAAAAAAAAAAAAAAAAAAAAAAAAAB3yHfHZw
AAAAAAAAAAAAAAAAAAAAAAAAd3fIyHVwAAAAAAAAAAAAAAAAAAAAAAAAfHh3jIxwAAAAAAAAAAAAAAAA
AAAAAAAHd8jIyHdgAAAAAAAAAAAAAAAAAAAAAAAHd4yHfIdAAAAAAAAAAAAAAAAAAAAAAAAHyMjIyMhQ
AAAAAAAAAAAAAAAAAAAAAAB3d3eMh4dgAAAAAAAAAAAAAAAAAAAAAAB8jIyIfIdQAAAAAAAAAAAAAAAA
AAAAAAB3h4jIiMh3AAAAAAAAAAAAAAAAAAAAAAB8jIeHeIjHAAAAAAAAAAAAAAAAAAAAAAeIiHh4eMiE
AAAAAAAAAAAAB0dHcAAAAAd8h4eIiIiHcAAAAAAAAAB0d3d3RwAAAAeIeIiIiIh3RwAAAAAAAHR3d8h3
dAAAAAfIh4iIiHiIx0cAAAAAdHh3eIeHhwAAAAeHiIiIiIiId3R3dHR0eHd4h4eHhAAAAAd4eIiIiIiH
x3d2d3eId4iIiIiIhwAAAAd4eIiI+IiIh3d3eHh3iIiIiIeHwAAAAAfIjHeIiIiIyIeHh4iIiIiIiIiI
cAAAAAeIQ0R3h3iIiMiIiIiIiIiIiIiEAAAAAAfIR3d3d0iIiIh4iIeIiIiIiHhAAAAAAAB4d3d3SHiI
h4fTiIi3iIiIeIwAAAAAAAB3h4d3eIeIiHiJiIuIiIh4jHAAAAAAAAAHyId3h3h4iIh4iIiIiIiHeAAA
AAAAAAAAB8iMiMjIiIiIh4h3aMjHAAAAAAAAAAAAAAdYyIeIiIiMjId6d4eAAAAAAAAAAAAAAAAHdsjH
eIeH6MiId3AAAAAAAAAAAAAAAIiIh4V8jIh4eIfHcAAAAAAAAAAAAACIiIh3AAAHd3h3fHcAAAAAAAAA
AAAAAAiIjHgAAAAAAHx8eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////
AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A
H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP////
AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA
AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/
AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC
AAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/
AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAAAAAAAAAAAAA
AAd0dAAAAAAAAAAAAAAAAAB3x3cAAAAAAAAAAAAAAAAAd3fHcAAAAAAAAAAAAAAAB3yMh3AAAAAAAAAA
AAAAAAfIeMdwAAAAAAAAAAAAAAAHjIyHQAAAAAAAAAAAAAAAfId4yHAAAAAAAAAAAAAAAHjIyIdQAAAA
AAAAAAAAAAB3iId4YAAAAAAAAAdwAAAAjIiIiIUAAAAAAHd3dAAAB4iIiHh8cAAAAHd3x4dwAAd4iIiI
h3Z3d3R3yIh4cAAHh4iIiIfHd3d4iIiIh3AAB3jHiIiIiHeHiIiIiIwAAAh3dXh4iMiIiIiIiIhwAAAA
yGd0d4iIeIi4iIiMAAAAAIeHd4iIh32IiIiIcAAAAAAAd4jIyIiIiHeHyAAAAAAAAAB3h4iIh8h3dwAA
AAAAAAAIh8fIh4eIaAAAAAAAAACIiHAAB8jIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
////////////////////n////g////wP///8B///+Af///gH///4B///8Af///AH///wB//n8AP/A+AB
/AHgAAAB4AAAAeAAAAPgAAAH8AAAD/AAAB/8AAA//wAA//4AA//weA//////////////////////////
//8oAAAAGAAAADAAAAABAAQAAAAAACABAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAA
AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRwAAAAAAAAAAAAB3dAAAAAAAAAAAAA
d8dwAAAAAAAAAAAAfId3AAAAAAAAAAAHeMjHAAAAAAAAAAAHyHh3AAAAAAAAAAAHh3eEAAAAAAAAAAAI
yIiHAAAAAHd2cAAIiIiIQAAAd3d4UACHiIiId3d3eHiIcACHh4iIyHeHiIiIcAAIR3d4iIiIiIiMAAAH
d3eIh3iIiIhwAAAAeMh4iIiHiMAAAAAAAHfIiMh4aAAAAAAAiIgHyIfIAAAAAAAIgAAAAIAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD8f/8A+H//APB/
/wDwP/8A4D//AOA//wDgP/8A4D/BAOAfAQDAAAEAwAABAOAAAwDgAAcA8AAfAPwAPwDwgP8A5/f/AP//
/wD///8A////ACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA
AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAd1AAAAAAAAB8cAAAAAAAB4eAAAAAAAAHyMgAAAAAAAiIhwAAAHcACI
iHcAd3hwAIz4jIeIiIAAd3eIiIiIAACHeIiIiHAAAACMeMh4AAAAiAAIgAAAAAAAAAAAAAAAAAAAAAAA
AAD//wAA//8AAP//AADj/wAA4/8AAMP/AADB/wAAwfkAAMDBAADAAQAAwAMAAMAHAADwDwAAzn8AAP//
AAD//wAAKAAAADAAAABgAAAAAQAIAAAAAAAACQAAAAAAAAAAAAAAAQAAAAEAAAAAAAA9OzsAZD8/AGg8
PABtPj4AQkNDAEZIRwBWQkIAV0REAF5AQABbRkYAVklJAFxPTwBTU1MAXFJSAF5ZWQBkQEAAYUREAGZF
RQBqQkEAYEtLAGNPTwBwQUEAfUZGAHJKSgB2SUkAfU9PAGBRUQBgVFQAZlZWAGZYWABqWVkAclZWAHpU
VAB9W1oAbmJiAGtoaABtaWkAcWdnAHdnZwB8Y2MAe2pqAHJxcQB+dHQAd3l5AHl6egCGT08AiU9PAIFP
UACGU1MAjVFRAIlWVgCMV1cAg1xbAIxaWQCQUlIAlVJSAJFXVgCXVVUAmVVVAJZaWQCSXV0AlV9eAJpZ
WgCeW1sAml5eAKBZWgCgXFwAql9fAIRmZQCIZWQAhWtrAI5ragCTYmEAnGBhAJ9kYwCaZmYAk25uAJ1s
awCFdHQAiXd3AIt+fgCWd3cAmHR0AJV5eQCbfHwAo2JhAKZhYQChZWUApGVkAKplZACsZGQAqmhnAKZr
agCnbGsAqmloAKlubQCsbW0AtGZnALhsbACxb3AAv29wAKVxcACrc3IAr35+ALN0cwC5c3MAvXBxALR4
dgC1fHsAunt6AMNtbgDGb3AAw3FyAMZwcQDGdXUAyHR1AMp3eADBeXkAxnt7AMB/fgDLensANLBSAEWf
TgBBtFwAPMdnADHkdgDciiIAvoF/AISrdwDln0sA35lhAN2XfADgmmEA8LdlAO61cAArWPIALWT+AEh5
+gDOf4AAfoCAAHiA1ABZv9wAZrnUAGK+2ABxnv4Ad6P/ADPX/QBw0OcAW+D7AIKEgwCPgoIAjI2NAJuC
ggCUiIgAmYqKAJGSkgCjhIQAqoKCAKKLiwC+hIMAsoqKALaSgQCum5sAsZubALqqlQCdgr4Ar6ytALGh
oAC6pKQAwoSDAMyBggDGiIYAyYiHAMWMigDMjIoA0ISFANKHiADUjIwA2Y6NAMCUjQDIk44A0JCPANaP
kADHlZQAzpSSAMScmwDUkpIA2ZSVANWYlgDampcA2ZeYANWcnADam5sA4p2cAMChjwDeoJ4A5aCFAOaj
jQDlpJoA2p6hAMOkowDOoaEAy62tANegoADdoqEA2aGpANGsrwDdq6kAwbG4ANGysQDdtLQA2ri3AOGk
owDjqKYA66ylAOGnqADjq6oA6a2rAOOwrwDssK4A5K+wAOaztADttLIA57i2AO24tgDmurgA6rq6APC1
swDyuLYA9Ly5APi+uwD1wL0A+cC9AKKMwACkk8QAqprMALSayACptsEAlaDkAOy/wACRxtQAgOv9AJnr
9wDEwsoA5sbGAOzCwgDuyMcA7MzMAPPEwgDxy8oA9dPTAPja2gAAAAAAAAAAAP///wAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAoIJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAACYXODs4BCUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
KTNDQ0M7OAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALllbYmJZQBcAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYYWNwcHBwWy8mAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFLanBwcHBwYz0eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABpqcHBwcHBwZVkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl11w
cHBwcHBwcGcSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIXdwcHBwcHBwcGkSAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPXBwcHBwcHBwd2wYAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAACXbnBwdXB5dXl0eW4hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAid3R5eXl5eXl5q6wzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9eXV5
i7CxsbGxsblLKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABndYuwsbm8uby5vMFnHgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJt3q7G3vMHB1cLBwdWuEgAAAAAAAAAAAAAAAAAA
AAAAAAAeEhMSCiUAAAAAAAAAAEexsbm/1dXZ2dnZ1da5ZgwAAAAAAAAAAAAAAAAAAAAjEjNZaW5qXRMl
AAAAAAAAADW5s7/V2N7i4uLi3dzZrQQPAAAAAAAAAAAAAAAAHxhZbm5uaWltd6ASAAAAAAAAAEmzvMLZ
3uP29/fw4uTkuUAWCy0AAAAAAAAAAB4YYXd3gG13vbm5vb8zAAAAAAAAAE6xwdXd4/b6+/r38OTl1Vlc
OAMIFAweFBQSM2mtrYB3vdXT0NXExNU1AAAAAAAAAE65wtXe8Pr7/Pz79+fn1WphZ25pXV1mbHetrXd3
tdXT4vXw49nZ3NYgAAAAAAAAAEu3wdje9vv7/Pz79+fn34B3d2xtoHeud66uudXT4vD39/Dj49zk5G0A
AAAAAAAAAD2xwcwoH0/L/Pukyenp5K27u7m5uczM0Nve4vb3+vr56OPl5eXl1igAAAAAAAAAADWxwQgB
BQYNmveZK/Dp6cG/wcTV2eP3+vr6+/r6+ejm5ufn5+nkIgAAAAAAAAAAAJmruR4sjC2WLFCdDd3p6dXW
1tXI3vn67pCO9Ojp6efo5+fm59wiAAAAAAAAAAAAAABLsZ0FmC0qKgHMRcjp6dzc1Y2KiO3RlfKTj+np
5ubm5eXk1SIAAAAAAAAAAAAAAACdab/Lp5aWnEfV1cHm6ebk6pGSiabZ8fOU0uXl5eTk3NyuRQAAAAAA
AAAAAAAAAAAAn0ux0KFTaMHBv7nC6efp3Ovv7OTm3OPl3Nzc3NfW1U6fAAAAAAAAAAAAAAAAAAAAAABF
Wa25t7yxs7Gw5+fn5Obk18XG3NyBfHvD1cSgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAFUzarGwsHl5sefn
39zEgoZ/hL19fnqirj2jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj09ZXV0cLzn3NXChYeDub+1pbQ9
VQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0rXj+rpInTBDcHCz5NW/ucG5u7GAM1QAAAAAAAAAAAAAAAAA
AAAAAAAAAADLytDi9tOemQAAAAAAUy9EecLEsa1uPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPj11Mme
VakAAAAAAAAAAAAATS84M0akAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////
AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A
H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP////
AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA
AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/
AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAgAAAAAAAAE
AAAAAAAAAAAAAAABAAAAAQAAAAAAAFFNTQBRUlIAU1RUAGJHRwBiT08Aa0lIAGJTUwBrVlYAYllZAGZc
XABpWloAb1xbAHNTUwB7V1YAc1hXAHFbWwBkZWUAaWFhAG5kZABpamkAcGFhAHlubgB2cHAAf3V1AH55
eQB8fX0AgUpKAI1PTwCLWFcAhlhYAI9ZWQCKXFsAm1ZWAJJZWQCWWVgAmlpbAJtcWwCiXFwAl2BfAIBg
YACAZ2YAgG9vAI9oaACWZWQAmGBhAJ5kZACcaWoAmm9vAIV0dACNcHAAiXZ2AIB8fACac3IAm3V0AJ51
dQCZfHwAnHx8AKNmZgCnZmYAqmJiAK5jYwCvb24AtWVmALBtbgC5bW0AvmxtAKx+fQCxcnIAtHBwALZz
dACydXQAtnd2ALlwcAC5dnYAt3p5ALh5eAC8fHsAun18ALx+fQDGb3AAxnBxAMdzdADAd3YAyHJzAMlz
dADJdXYAynd4AMd/fwDMe3wAzXx9AHunbwBhvHIAYsN4ANuLOwC2hn4A4Zt5APC3ZABte9sAX47+AHWM
5QAl0foAY+P8AIeDgwCFhoYAioSEAJOIiACWi4sAmpKRAKGCgQCmhYUAqYGBAKuDhACniooApYyMAKiO
jQCyhYMAvoWEALeNjQCrj5AAr5eXALSVlAC9lJMAmbCEAK6RugDBgYAAwoSCAMWDhADChoQAxYeFAM6A
gQDFiIYAxoqIAMqIiQDMi4oAy4yKAMiPjQDPj44A0ISFANKJigDUi4wA04+NANWNjgDKkY8A0JCOANud
iQDWj5AAzJSTAM2XlgDGm5oA1pGSANOUkgDVl5EA1pOUANiVlgDYmJUA2ZeYANKenADbmpsA3pmYANuc
mgDbn5wA1aacAN6gngDqqZoA3Z+gAMyjowDCra0AxqysAMqpqQDboaAA3qKiAN6logDbp6UA3aWkANer
qgDWsbMA0rW0ANe0tADfs7IA4aSiAOGlpQDkp6UA46imAOWopgDsraIA6qimAOGoqADhrqwA6a2rAOqv
rADpsK4A7LGuAOGzswDlsbEA7bKxAO+1sgDotrYA5rm3AO+4twDot7sA6bq5AOu9uwDrv70A8bazAPG2
tADxuLUA9Lm2APC9uwD2vboA9L+9APi+uwD4v7wA8sC+APXAvgD5wL0AkILJAKqXzACsu8cAqr/LALLV
3QDawMIA48XFAOvDwQDswMAA7cTDAO/ExQDgxsgA8cbEAPTGxADwyskA9MvJAPLNzQD21dYA+NjZAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAMEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHCEcBQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAayU9PSYbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdQlBSQiJpAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAM0pSUlJQPRcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnUlJSUlJGFQAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAFJSUlJSUkoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzUlJSWVJZfxAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5XWYqKioqGDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASoqMkpqa
mqAsAAAAAAAAAAAAAAAAAABoNAAAAAAAAACMjJyuvLy2toYHAAAAAAAAAAAAABcOIDouBgAAAAAAc4yc
tsHKysPAriIKAAAAAAAAABYgRk1LTX+DEAAAAABukqXB4ejo4dHPQCIEChcXEwggTXV/k66unKMpAAAA
AG6Srsro6ero0dN/Rk1NRk2Dg4STrsbh4cHAt2sAAAAAbpKuOXPe6ajW15KGg4OGk528yuHo5eHPz882
AAAAAAB4jCkDAxSoMabXt5yjt8ro3ePo5dbT09HTdAAAAAAAAABGcBFoGgFwdtfDwHxi2dpmZcrX09HP
z0MAAAAAAAAAAHh/qWwaOa6cz9PNZGPYsdzbzc3DwLk2AAAAAAAAAAAAAAAvhpKakoyg19HNyKS5wHtb
orZ/cwAAAAAAAAAAAAAAAAAANkaKWVm5zb1gYV6cXVxfNgAAAAAAAAAAAAAAAAAAALGvlTIuP1K5tqCR
l4xfLwAAAAAAAAAAAAAAAAAAsbPBenkAAAAAcCVYjE0scwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////+f///+D////A////wH
///4B///+Af///gH///wB///8Af///AH/+fwA/8D4AH8AeAAAAHgAAAB4AAAA+AAAAfwAAAP8AAAH/wA
AD//AAD//gAD//B4D////////////////////////////ygAAAAYAAAAMAAAAAEACAAAAAAAQAIAAAAA
AAAAAAAAAAEAAAABAAAAAAAAWlJSAHBJSQB1SEgAe1dXAHdYWAB5WlkAel1dAGBiYgB1bGwAfWtrAHh2
dgB9fn4Ag01NAIRXVwCIV1cAhV9eAItbWgCgX14ApV1dAJhgXwCNYGAAnWtqAJhtbQCCdnYAh3x8AI15
eACeensAqGBgAKhoZwCga2oArGpqALNqagCzb28AtG1tALltbQCxb3AApnVzAKlzcwCqdHMApnp6AKd+
fgCpensAq3x7ALZ3dgC8dHQAvH59AMZvcADGcHEAxXN0AMhycwDJdncAynh5AMx5egDNfn8Ajo1wAOek
VgDGgH8A4p53AEZ2+gB8u4AAd8PaAIuEhACOh4cAjo6OAJ+DggCejo4Ao4SEAKSIiACsi4sAqo2MAK6P
jgC+gYAAvoaGAL+KiACskJAAtJeXALWenQC5np4At6iOAKmyjgC9nroAwYSDAMaGhADOhoYAxomHAMiK
iQDJjYwA0oeIANOOjwDUjY0A2ZiPANaPkADGkZEAx5eXAMySkADGnZwA1ZOSANeTlADWl5YA2JSVANGZ
mADan50A3J6dAOCcmwDVoJ8A7K2fAMOtrQDXo6IA3aCgAN+kpADVq6oA3ay3AMu0tADPtrYA3L+/AOCi
oQDhpqUA5KelAOinpgDlq6gA46usAOOvrQDqrqwA7LGuAOayswDjtrQA5re1AOqysQDts7EA57y6AO+8
ugDrvL0A8LOwAPC1sgDwtrQA87q3APS6twD2vboA8b69APi/vAD2wb4A+cC9AJmTzwDHqMMAu8PMAIHf
8QDByNAA7cLCAO3FwwDvxsQA5cjIAOzOzgDwxcQA9cbEAPPP0AD10tIAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BQMJAAAAAAAAAAAAAAAAAAAAAAAAAAAPHBMNAAAAAAAAAAAAAAAAAAAAAAAAABojLy8TAAAAAAAAAAAA
AAAAAAAAAAAAAB0wMDAiPgAAAAAAAAAAAAAAAAAAAAAAQjAwMDAtGAAAAAAAAAAAAAAAAAAAAAAAFzIy
NTU5CgAAAAAAAAAAAAAAAAAAAAAAIjZYWFxcBwAAAAAAAAAAAAAAAAAAAAAANlxtdW11JQAAAAAAAAAA
PgcRDgkAAAAAXG1/lISAZgMAAAAAABkVLC5SVhcAAABNY3WWnJuLfB8UBAcQHkhWaX91dSsAAABNY2BM
mJeCiVJSVl9laX+WloSJgEIAAAAAXAEIC0tGjnR0dJaRk5qNjIyJQwAAAAAAJkNADBtdjIaPO1GSPYuJ
hnVEAAAAAAAAAClISWRcd4xwkGp8UE90VwAAAAAAAAAAAAAAKSQ1NYZ7OjhbPDdGAAAAAAAAAAAAAHNv
YGsAKyJoXFYmRwAAAAAAAAAAAAAAcnIAAAAAAAAATgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP//
/wD///8A////APx//wD4f/8A8H//APA//wDgP/8A4D//AOA//wDgP8EA4B8BAMAAAQDAAAEA4AADAOAA
BwDwAB8A/AA/APCA/wDn9/8A////AP///wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAQAAAAAAAAAA
AAAAAQAAAAEAAAAAAABjZGQAdmRjAHtpaQB/eHgAgU9PAKBaWgCFbm0AlWtqAKptbgCwZ2cAsGhoAKxw
cACteHkAvnJyAMZvcADGcHEAy3l5AMx9fgCFmXQAwIB/ANeUfQDhoX8AlIqJAJWMjACYiIgAoIaGAK2K
igCxh4cAvoGAALKKigC4iYgAuJWVAL2cnACss50AuqKhAL+mpgDLgoIAxImHAMeNjADLkI8AxpWTANCS
kQDYlZUA1J6dANqZmgDdnp4A1J+oAMaiogDOr68AzLKyANi5uADhpaIA4qypAOWtqADrrqsA4bKwAOay
sgDtuLYA57++AOy4uADxtLIA8be0APa9ugDswL4A9sG+ALCcxwC5ncIA06zBALnH0QC2ytQA7sPDAPLS
0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAZBgUAAAAAAAAAAAAAAAAACw8KAAAAAAAAAAAAAAAAGhAQDgAAAAAAAAAAAAAAAAkRESUYAAAA
AAAAAAAAAAAlKy4uBwAAAAAAAAcDAAAAKzlHPCYCAAAYCB0oKgAAAC0wSDs0FB0nLDlAOiwAAAANAQQb
Pi9DRkVBPzUAAAAAJB4cKz5EQjMiNSkAAAAAAAAAHwwRNxYVEyQAAAAAAAAxMgAAACEgAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA4/8AAOP/AADD/wAAwf8AAMH5
AADAwQAAwAEAAMADAADABwAA8A8AAM5/AAD//wAA//8AACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAkAAAAJAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAUAAAAOAEBAVUAAABUAAAANQAAABAAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAkFBSUvGRl5TCkpwlYuLtxDJCTQFw0NmQAA
AEkAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGAwMKE8rK6V6RET2klJR/5ZS
U/+OT0//ZDc38B0QEJoAAAAyAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYDAwYVzAwoopP
T/ygXVz/oFtb/55ZWf+bWFf/k1NT/1UvL9wGAwNcAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AARNKipxhk5O+adkY/+uZWX/tWdo/7VmZ/+qYWH/nltb/3hERPcfERGCAAAAFgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADEZGS1zQ0LXqGdm/7ptbf/Fb3D/x3Bx/8hwcf/BbW7/q2Vl/4hPT/82HR2gAAAAIAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAB1gxMYyYXl3/vXFx/8Zwcf/HcHH/x3Bx/8dwcf/HcHH/uG1t/5NY
V/9EJia2AAAAKQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPB8fNH1MS+K4cnH/x3Fy/8dwcf/HcHH/x3Bx/8dw
cf/HcHH/wHBx/51gX/9PLCzGAAAAMwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
AAMAAAAAAAAAAAAAAAAAAAAALhAQFIZXVs/RjIz/1Y2O/9qYmP/eoaL/46qr/+aysv/ot7f/6rm5/+m4
uf/otbX/5q+v/+uvrf/jqab/wYeF/28/P/QhEhKvAAAAXwAAACgAAAANAAAABQAAAAMAAAACAAAAAwAA
AAUAAAAKAAAAFQAAADAdDg9oSSkptHZHRu2dYmL+t3Z1/758e/+6enn/tnh3/7d5eP+8fn3/w4SD/7Z6
ef9eODfbBgICTgAAAAgAAAAAAAAAAAAAAAAAAAAAPhwcJJVjYuPXkZH/2JOU/92fn//iqqr/57O0/+u8
vP/uwsL/78XG/+/Exf/twMD/67i4/+60sv/wtrP/zZKQ/5taWv9xQED2MRsaxAgEBIcAAABaAAAAQQAA
ADcAAAA2AAAAOwAAAEUEAgJZHA4OfUcnJ7l5SkntqGxr/8CAfv/DgoH/vH59/7p+ff/DiIb/zZGP/9GT
kf/UlJP/1peV/9eZl/+GVlbuGQsLVwAAAAcAAAAAAAAAAAAAAAAAAAAARiIiLZ9rauvZk5P/2peY/+Ck
pP/lsLD/6ru7/+/Fxf/yzMz/9NDQ//PPz//xycr/7sDA//K5tv/1u7j/36Kg/6dmZf+mZWX/j1ZW/WM6
OutDJSXQNBwcvDAaGrQ0HBy1PiIivUwsLMtkPDzfh1VU9a1xcP/EhIP/xIWE/7+Cgf/Ch4b/zZST/9mk
ov/grq3/4a6t/96lo//eoJ7/36Kg/+Cjof+IWVjnGwwMQwAAAAIAAAAAAAAAAAAAAAAAAAAARyQkL6Br
auzZk5P/25qb/+GnqP/ntLT/7cDA//LLy//209T/+NjY//fX1//00ND/8cbG//W9u//4vrz/46ak/7d0
c/+vb27/s3Jy/7d2df+ucXD/pWpp/6Npaf+nbWz/sHVz/7p9fP/EhYT/yImI/8WIhv/DiIb/ypGP/9eg
n//hr63/57q5/+rCwP/rwsD/6bq4/+evrf/nq6n/6q6r/9qgnv9wRkbDBwAAHgAAAAAAAAAAAAAAAAAA
AAAAAAAASCQkLZ1nZuvYkpP/25uc/+Opqv/qtrf/7cHB//TOzv/52Nj/+tzc//na2v/xz9D/8MfH//fA
vv/6wb7/6a6r/8OBgP/DgoD/vX58/7h7ev+8fn3/woOC/8aHhv/HiYj/xoqJ/8aLif/Ijoz/zZST/9eg
nv/hrav/6Lm3/+zCwf/uyMf/78nH/+/Dwf/uvLr/7ba0/+60sf/vtLL/8ri1/7J+fflMKSltAAAABAAA
AAAAAAAAAAAAAAAAAAAAAAAAQyEhI5JcXOPWj5D/3Juc/8qVlf+BZmb/bl5e/4l4eP/AqKj/8tPT//LO
zv+5p6b/w6qq//fBv//7wr//8LWy/86Ojf/Ojoz/0ZGP/9GSkP/OkY//zpOR/9GamP/VoJ//2qel/+Gv
rf/nt7X/6727/+3Dwf/wycf/8czL//LLyf/yxsT/8cC+//G7uf/yubf/87m3//S7uP/4vrv/1J6c/3JH
RrAdCgsWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANRcXEYJNTcvPiIn/15aW/2VNTf85Ojr/Q0VF/0JF
RP9dXFz/n5GR/+S/v/+bh4f/hXp6/+25uP/7wr//9bu4/9qcmv/Zmpj/252b/96gnf/ipKH/5q+s/+u+
vP/vycf/8srI/+3Hxv/wysj/9c7M//TNy//0ysj/9MbE//TBv//1vrz/9r26//e9u//4vrv/+L+8//vB
vv/hqqf/g1ZVzDwcHC4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW4+Ppq/env/05OT/2ZX
V/9rbm7/fX9//3l6ev99f3//cHJy/5F9ff+ff3//XFhY/9eop//8wr//+L+8/+Wppv/ipaP/5qil/96i
pP/Kmaz/1qi1//LGxP/tyMf/qb3J/23E3P9kw9//vMTN//jDwP/3wb//+MC9//i/vf/5v73/+b+8//i/
vP/3vrv/+L68/92mo/+IWlnRRSMjOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFcv
L0mbX1/y15GS/6GAgP9XV1b/iYuL/4CBgf98fX3/cnR0/1dPT/++j4//km9w/9Sfnv/6wL3/+cC9/+6z
sP/ssK3/0Z+u/4OH1P9YffD/QGPs/7KYyv/Ct7z/Ytrz/3Ts//8s2f//cbvU//m+u//4v7z/+L67//e9
uv/1vLn/9Lq3//O5tv/zuLX/0puZ/4RVVctGIyM4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADIXFwdrPDySq2ts/diZmf/ApKT/sKur/4CBgP95enr/iYiI/49zdP/do6P/36Ch/96e
nv/zuLX/+sK///W7uP/1ubT/qZC//2qY+/9tnf//MGT6/56FxP/esK//nMbS/57n8/9+z+T/ybG3//a6
t//zubb/8re0//C1s//utLH/7rKw/+qvrP++iIb9dklJtkMgISoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHIyMSazw8kZ5hYvXNjI3/2aSk/7OMjP+bd3f/sIKC/9KV
lv/cnJz/2peY/9aRkf/koqL/+sG+//nAvf/5v7z/4amw/6qZx/+aouP/qpvP/+mxtv/2urj/6rGv/+S6
u//ptrX/466n/+Ovqf/ssK7/6q6s/+isqv/oq6n/2J2b/6JubfFoPT2NOxoaFwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBoaCFowMFd7SEjAomZm9sWC
gv/XkZL/25SV/9iSk//Wj5D/1IyN/9KHiP/UiIj/8bOx//rCv//3vbv/9ru4//O3s//xuLX/7q6e/+ej
hf/npIn/7bCp/+Otp/+KsX3/ULdm/1WjWv+7oYz/5KWk/9uenP+4gH79glJRzVYuLlQgCAkGAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA8HBwQVy4uS3FBQaCPV1fjsG5v/cmAgf/ShYb/0YKD/85+f//LeXr/2I2M//e8uf/1vLn/7rOx/+2y
sP/lpJX/5qFY/+6xXP/djS3/35h9/86gl/9SwW7/Nd90/0WxXP+vlH//wYSE/49cW+VlOTmBQR4eHAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGk7OhqIWFd8oG5u8J5qav+eX2D/tmts/8Z0df/KdHX/yXJz/92T
k//3vLn/7LGu/+Snpf/dm5L/4Z1q/+61dP/fmmX/15WM/9eYlv/Bm43/r6uR/6uNgP+WYWDtbkBAnUwn
JzQVAQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiFJSBnhC
QgpqNDQJWSUlB08dHQdfKisKfENDFJJWViinbGtRvYOCjtOcm8/pt7X157y6/7eOjfhxRUW7aTk5m4RK
StehWlr6uGdo/8Zwcf/dkpH/8bSx/+OnpP/YmZj/1ZWT/9ealP/Vl5X/0JCP/8eIhv+zdnb/lFtc6nA/
QKRSKio/JQwNBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADTn6AB2qioDMuUlCHBhYU8voCAWcCBgXTEhoaLzZGQqdeensngrKvn47Sz/NOop/+yiIfyi2Bgs2k+
PlZXKysPAAAAAUYlJRxcMTFYcj4+pYpMTeWmXF3+xnl5/9+Zl//dnJr/z46M/8KCgf+vc3L/ll9e831L
S8hlOTl/TigoMy0REQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABzQUIDnmprDriGhifHlpZMzp6eeNCgoZ7On5+2yJqaybuPj9WnfHzVj2RkunVJ
SYNbLy8/PRQUCgAAAAAAAAAAAAAAAAAAAAAAAAAAKRUVBU0pKSphNDRtd0BAsotNTd2ZW1vrkVlY4HtJ
Sb5lOTmCUysrQTsbGxEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWCwsA2Y4OA5xQkImdkhIRHhKSll0R0dibUBAWWI2
NkNUKCgoOhISDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMhkZB0km
Jh5LJiYsRSEhITATFAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAD/+H////8AAP/gH////wAA/8Af////
AAD/gA////8AAP+AD////wAA/wAP////AAD/AA////8AAP4AB////wAA/gAH////AAD8AAf///8AAPwA
B////wAA/AAH////AAD8AAf///8AAPgAB////wAA+AAH//4HAAD4AAP/8AEAAPgAAf/AAQAA8AAA/wAA
AADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAEAAPAAAAAAAQAA8AAAAAADAADwAAAAAAcAAPAA
AAAADwAA+AAAAAAfAAD4AAAAAD8AAPwAAAAAfwAA/gAAAAD/AAD/gAAAA/8AAP/gAAAH/wAAgAAAAB//
AAAAAAAAf/8AAAAD4AP//wAAgB/8H///AAD///////8AAP///////wAA////////AAD///////8AAP//
/////wAA////////AAAoAAAAIAAAAEAAAAABACAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAYAAAAZAAAAGQAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAARCQkYOh8fb0ooKK80HByiCQUFTAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAIhERFmA2Np2ITUz3lVNT/4dLS/5IKCi9AAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAANjODiBllhY+61kZP+vY2P/pV5e/3xHRvEhEhJfAAAAAgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAASSgoN41VVeS6bW3/xW9w/8dwcf+9bG3/klZW/jogIIEAAAAGAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ1RkWcs2xs/8dxcv/HcHH/x3Bx/8Zwcf+iYWH/SSkpmAAA
AAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUC0tMZtgX+fGcnP/x3Bx/8dwcf/HcHH/x3Fy/61q
av9UMTGqAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxRER1tm9v/8hxcv/HcHH/x3Bx/8dw
cf/HcnP/tnRz/185OboAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAACIxXV7TEdHT/yHJz/8l1
dv/Kd3j/ynd4/8p4eP/Bf37/bURDywAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNKysjo2Zm4Mt4
ef/NfH3/z4GC/9GFhf/RhYb/0YWF/82Mi/9+UVHeCAICOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAJAAAACwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAGc+
Pkm1c3P30IGC/9OJiv/XkZL/2ZaW/9mWl//YlJX/2JmY/5hnZfMeEBBrAAAABwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA0FAgItHhAQWzAbG4IqFxeHDQcHWwAAABkAAAAAAAAAAAAA
AAAAAAAAek1MdMN/f//VjI3/2piZ/9+io//hqKn/4qmp/+Clpf/jpqT/wImH/04xMLwAAAA6AAAABQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABEbDg5GRygokW5CQs+MVlbxnGJh/JdfXvxnPz7hHA8PbgAA
AAwAAAAAAAAAAAAAAACMW1qbz4qK/9qXl//gpqb/5rKz/+q6u//rvLz/6La2/+qxr//epKL/j1lZ+DUc
HLACAQFPAAAAHQAAAA8AAAAPAAAAEwAAACIbDg5MVDExnYZUU+SpbWz+uXl4/7x+fP/AgoD/xoeF/72A
f/9fOzu1AAAAHAAAAAAAAAAAAAAABJhkZK/VkZH/3Z+g/+axsf/twMD/8svL//LNzf/vxcX/8Lq4/+6z
sf+1dHP/j1VU+144N9g7IiKqMhwclDcfH5RGKSmiYTw7v4tZWOiydXT+woOC/8aKiP/Ol5X/2aWj/9ui
of/cnpz/2pyb/35TUrgAAAAVAAAAAAAAAAAAAAAFmmVkstaTk//hpaX/7Lm6//TLy//419f/+NnZ//TP
z//1wb//9Lq3/8aGhP+1dHP/s3Rz/6xwb/+pb27+rnNy/7Z7ev/BhIL/yY2L/8+WlP/apqT/5be2/+vB
v//rvrz/6bKw/+uvrf/Um5n/bUVEgAAAAAMAAAAAAAAAAAAAAAOTXV2q1ZGR/9CYmP+dfX7/o4yM/9e8
vP/z0tL/zLOz/+u8u//5v7z/1peV/8uLif/Ki4r/yoyL/86Ukv/TnJv/2qSi/+Gtq//nuLb/7cPB//DJ
x//xxsT/8b+9//G6t//zubf/77az/6d1dM89Hx8lAAAAAAAAAAAAAAAAAAAAAIJOTojNiIn/jGlp/01O
Tv9UVlb/dnNz/7uhof+Pfn7/xJ+e//zCv//lqKb/3J2b/+Chnv/hpaT/7Ly5/+vHxv/MxMn/0MjN//LK
yf/1x8X/9sLA//a/vP/3vrv/+L+8//S7uP+5hoXhYTo5RwAAAAAAAAAAAAAAAAAAAAAAAAAAaTs7RrVz
dPKmfn7/cXJx/4SGhv97fX3/b2Zm/516ev+7kJD/+sG+//C2s//lqqr/rpbA/3aB2/+ql83/tMHK/2jc
9P9OzOz/2r3B//q/vP/3vrv/9ry6//a8uf/ss7D/tYGA32c+Pk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAvEhIHg01Njbp9fvrCn5//nI+P/4R7ev+fgID/2Jyd/9ybnP/ytrT/+b+8/+ewtf+Mld3/ZI36/5eI
zv/Ttrn/sNLc/6/Czv/stLT/8re0/++0sf/tsq//2qCe/6Rxb8phODg+AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABCIB8MeUZGbqRpata8gYH8x4mJ/9eTk//YkpP/04qL/+Cbmv/5wL3/9726/+Sw
t//Zrrn/56qY/+2smf/lr6n/nLWJ/4Gtdf/Pppn/3qGf/7yEg/KJWViYTyoqIAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQh0dGXJAQGOXXl7NtnR1/8V7fP/MfH3/znt8/+il
o//0urj/7LCu/+Whg//rq13/35VX/9Kek/9yvXz/ZbNv/6iCdfqYY2O/aj4+TCUJCgcAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACcamsBjFRVB4FERAh9PT0JjU1ND6VnZx+/hINF0JqZiNOjoty0iIf2hFBQw5lX
V8+wY2P4xXR0/+aioP/oq6j/2pqT/92fif/Vlor/yYqJ/7N8efiVZmPGdERFYkEfHxIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALiFhgXFkJEdx5CQSMqSknbNlZWbz5uaws2cnOXBlJPnqH18r4dc
XFFULy8OSCUlFm07O0+FSUmeoV1d3sF9fPrGhoX/snZ295xkZNiFUlKbbD4+T0UdHxIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc0JDA5FgYRKdbm46onR0Zp9ycnuWampzhFlZVmY6
OikvDAwHAAAAAAAAAAAAAAAAAAAAAB0ODgRULCwhbjo7UXhERGVrPDxHTCYmGxAAAQMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//////////////////////D////gf///wH///4A///+AP///AD///wA///8AP//+AD
///gA//D4AH+AeAA+ADgAAAAwAAAAMAAAADAAAAB4AAAA+AAAAfgAAAP8AAAH/wAAD8AAAD/AAAD/wB4
D//H////////////////////KAAAABgAAAAwAAAAAQAgAAAAAABgCQAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAABMAAAAtAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAgIO1cwMM1qOjrsHhAQmwAA
ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAATCgogfUhI6ahgYP6lXV3+f0hI9wIBAT0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsGBgFPLy6kuW1t/sZv
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
</value>
</data>
</root>

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// Interface to implements in order to make a custom tool for a specific game
/// </summary>
public interface ICustomGameTool:IToolForm
{
}
}

View File

@ -98,19 +98,22 @@ namespace BizHawk.Client.EmuHawk
private void QueryItemBkColor(int index, InputRoll.RollColumn column, ref Color color)
{
var record = Tastudio.CurrentTasMovie[GetBranch(index).Frame];
if (index == CurrentBranch)
color = TAStudio.CurrentFrame_InputLog; // SystemColors.HotTrack;
else if (record.Lagged.HasValue)
TasBranch branch = GetBranch(index);
if (branch != null)
{
if (record.Lagged.Value)
var record = Tastudio.CurrentTasMovie[branch.Frame];
if (index == CurrentBranch)
color = TAStudio.CurrentFrame_InputLog; // SystemColors.HotTrack;
else if (record.Lagged.HasValue)
{
color = TAStudio.LagZone_InputLog;
}
else
{
color = TAStudio.GreenZone_InputLog;
if (record.Lagged.Value)
{
color = TAStudio.LagZone_InputLog;
}
else
{
color = TAStudio.GreenZone_InputLog;
}
}
}
@ -141,12 +144,11 @@ namespace BizHawk.Client.EmuHawk
private void LoadSelectedBranch()
{
int index = BranchView.SelectedRows.First();
//if (CurrentBranch == index) // if the current branch was edited, we should allow loading it. some day there might be a proper check
// return;
if (SelectedBranch != null)
{
int index = BranchView.SelectedRows.First();
//if (CurrentBranch == index) // if the current branch was edited, we should allow loading it. some day there might be a proper check
// return;
CurrentBranch = index;
LoadBranch(SelectedBranch);
BranchView.Refresh();

View File

@ -53,6 +53,8 @@ namespace BizHawk.Client.EmuHawk
this.label8 = new System.Windows.Forms.Label();
this.label9 = new System.Windows.Forms.Label();
this.NumSaveStatesLabel = new System.Windows.Forms.Label();
this.BranchStatesInTasproj = new System.Windows.Forms.CheckBox();
this.EraseBranchStatesFirst = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.MemCapacityNumeric)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.DiskCapacityNumeric)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.SaveCapacityNumeric)).BeginInit();
@ -62,7 +64,7 @@ namespace BizHawk.Client.EmuHawk
//
this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.CancelBtn.Location = new System.Drawing.Point(216, 113);
this.CancelBtn.Location = new System.Drawing.Point(216, 163);
this.CancelBtn.Name = "CancelBtn";
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
this.CancelBtn.TabIndex = 0;
@ -73,7 +75,7 @@ namespace BizHawk.Client.EmuHawk
// OkBtn
//
this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OkBtn.Location = new System.Drawing.Point(150, 113);
this.OkBtn.Location = new System.Drawing.Point(150, 163);
this.OkBtn.Name = "OkBtn";
this.OkBtn.Size = new System.Drawing.Size(60, 23);
this.OkBtn.TabIndex = 1;
@ -116,7 +118,7 @@ namespace BizHawk.Client.EmuHawk
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(12, 9);
this.label2.Location = new System.Drawing.Point(9, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(88, 13);
this.label2.TabIndex = 5;
@ -125,7 +127,7 @@ namespace BizHawk.Client.EmuHawk
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(126, 9);
this.label3.Location = new System.Drawing.Point(147, 9);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(79, 13);
this.label3.TabIndex = 6;
@ -134,7 +136,7 @@ namespace BizHawk.Client.EmuHawk
// SavestateSizeLabel
//
this.SavestateSizeLabel.AutoSize = true;
this.SavestateSizeLabel.Location = new System.Drawing.Point(208, 9);
this.SavestateSizeLabel.Location = new System.Drawing.Point(229, 9);
this.SavestateSizeLabel.Name = "SavestateSizeLabel";
this.SavestateSizeLabel.Size = new System.Drawing.Size(25, 13);
this.SavestateSizeLabel.TabIndex = 7;
@ -188,7 +190,7 @@ namespace BizHawk.Client.EmuHawk
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(12, 49);
this.label6.Location = new System.Drawing.Point(9, 49);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(72, 13);
this.label6.TabIndex = 5;
@ -196,7 +198,7 @@ namespace BizHawk.Client.EmuHawk
//
// SaveCapacityNumeric
//
this.SaveCapacityNumeric.Location = new System.Drawing.Point(158, 66);
this.SaveCapacityNumeric.Location = new System.Drawing.Point(150, 66);
this.SaveCapacityNumeric.Maximum = new decimal(new int[] {
65536,
0,
@ -215,7 +217,7 @@ namespace BizHawk.Client.EmuHawk
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(213, 69);
this.label7.Location = new System.Drawing.Point(205, 69);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(21, 13);
this.label7.TabIndex = 4;
@ -224,7 +226,7 @@ namespace BizHawk.Client.EmuHawk
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(158, 49);
this.label8.Location = new System.Drawing.Point(147, 49);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(112, 13);
this.label8.TabIndex = 5;
@ -233,7 +235,7 @@ namespace BizHawk.Client.EmuHawk
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(155, 89);
this.label9.Location = new System.Drawing.Point(147, 89);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(84, 13);
this.label9.TabIndex = 8;
@ -242,19 +244,45 @@ namespace BizHawk.Client.EmuHawk
// NumSaveStatesLabel
//
this.NumSaveStatesLabel.AutoSize = true;
this.NumSaveStatesLabel.Location = new System.Drawing.Point(242, 89);
this.NumSaveStatesLabel.Location = new System.Drawing.Point(234, 89);
this.NumSaveStatesLabel.Name = "NumSaveStatesLabel";
this.NumSaveStatesLabel.Size = new System.Drawing.Size(25, 13);
this.NumSaveStatesLabel.TabIndex = 9;
this.NumSaveStatesLabel.Text = "1kb";
//
// BranchStatesInTasproj
//
this.BranchStatesInTasproj.AutoSize = true;
this.BranchStatesInTasproj.Location = new System.Drawing.Point(12, 115);
this.BranchStatesInTasproj.Name = "BranchStatesInTasproj";
this.BranchStatesInTasproj.Size = new System.Drawing.Size(158, 17);
this.BranchStatesInTasproj.TabIndex = 10;
this.BranchStatesInTasproj.Text = "Put branch states to .tasproj";
this.BranchStatesInTasproj.UseVisualStyleBackColor = true;
this.BranchStatesInTasproj.CheckedChanged += new System.EventHandler(this.BranchStatesInTasproj_CheckedChanged);
//
// EraseBranchStatesFirst
//
this.EraseBranchStatesFirst.AutoSize = true;
this.EraseBranchStatesFirst.Checked = true;
this.EraseBranchStatesFirst.CheckState = System.Windows.Forms.CheckState.Checked;
this.EraseBranchStatesFirst.Location = new System.Drawing.Point(12, 140);
this.EraseBranchStatesFirst.Name = "EraseBranchStatesFirst";
this.EraseBranchStatesFirst.Size = new System.Drawing.Size(139, 17);
this.EraseBranchStatesFirst.TabIndex = 11;
this.EraseBranchStatesFirst.Text = "Erase branch states first";
this.EraseBranchStatesFirst.UseVisualStyleBackColor = true;
this.EraseBranchStatesFirst.CheckedChanged += new System.EventHandler(this.EraseBranchStatesFIrst_CheckedChanged);
//
// StateHistorySettingsForm
//
this.AcceptButton = this.OkBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CancelBtn;
this.ClientSize = new System.Drawing.Size(288, 148);
this.ClientSize = new System.Drawing.Size(288, 198);
this.Controls.Add(this.EraseBranchStatesFirst);
this.Controls.Add(this.BranchStatesInTasproj);
this.Controls.Add(this.NumSaveStatesLabel);
this.Controls.Add(this.NumStatesLabel);
this.Controls.Add(this.label9);
@ -303,5 +331,7 @@ namespace BizHawk.Client.EmuHawk
private Label label8;
private Label label9;
private Label NumSaveStatesLabel;
private CheckBox BranchStatesInTasproj;
private CheckBox EraseBranchStatesFirst;
}
}

View File

@ -44,6 +44,8 @@ namespace BizHawk.Client.EmuHawk
SavestateSizeLabel.Text = Math.Round(_stateSizeMb, 2).ToString() + " mb";
CapacityNumeric_ValueChanged(null, null);
SaveCapacityNumeric_ValueChanged(null, null);
BranchStatesInTasproj.Checked = Settings.BranchStatesInTasproj;
EraseBranchStatesFirst.Checked = Settings.EraseBranchStatesFirst;
}
private int MaxStatesInCapacity
@ -79,5 +81,15 @@ namespace BizHawk.Client.EmuHawk
{
NumSaveStatesLabel.Text = ((int)Math.Floor(SaveCapacityNumeric.Value / _stateSizeMb)).ToString();
}
private void BranchStatesInTasproj_CheckedChanged(object sender, EventArgs e)
{
Settings.BranchStatesInTasproj = BranchStatesInTasproj.Checked;
}
private void EraseBranchStatesFIrst_CheckedChanged(object sender, EventArgs e)
{
Settings.EraseBranchStatesFirst = EraseBranchStatesFirst.Checked;
}
}
}

View File

@ -271,7 +271,6 @@ namespace BizHawk.Client.EmuHawk
{
CurrentTasMovie.Markers.Add(TasView.LastSelectedIndex.Value, "");
RefreshDialog();
}
else if (columnName != CursorColumnName) // TODO: what about float?
{
@ -315,9 +314,7 @@ namespace BizHawk.Client.EmuHawk
else
index += controllerType.BoolButtons.Count - 1;
AutoPatternBool p = BoolPatterns[index];
// adelikat: I broke it
//Global.AutofireStickyXORAdapter.SetSticky(button, isOn.Value, p);
Global.StickyXORAdapter.SetSticky(button, true);
Global.AutofireStickyXORAdapter.SetSticky(button, isOn.Value, p);
}
else
{
@ -328,9 +325,7 @@ namespace BizHawk.Client.EmuHawk
float? value = null;
if (isOn.Value) value = 0f;
AutoPatternFloat p = FloatPatterns[index];
// adelikat: I broke it
//Global.AutofireStickyXORAdapter.SetFloat(button, value, p);
Global.StickyXORAdapter.SetFloat(button, value);
Global.AutofireStickyXORAdapter.SetFloat(button, value, p);
}
}
@ -543,9 +538,20 @@ namespace BizHawk.Client.EmuHawk
private void TasView_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && !_supressContextMenu)
if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && !_supressContextMenu && TasView.SelectedRows.Any())
{
RightClickMenu.Show(TasView, e.X, e.Y);
if (Global.MovieSession.Movie.FrameCount < TasView.SelectedRows.Max())
{
// trying to be smart here
// if a loaded branch log is shorter than selection, keep selection until you attempt to call context menu
// you might need it when you load again the branch where this frame exists
TasView.DeselectAll();
RefreshTasView();
}
else
{
RightClickMenu.Show(TasView, e.X, e.Y);
}
}
else if (e.Button == MouseButtons.Left)
{

View File

@ -39,7 +39,7 @@ namespace BizHawk.Client.EmuHawk
MaybeFollowCursor();
return;
//return; seriously? well, maybe it's for some insane speedup, but it skipped updating when putting playback to frame zero.
}
else // Emulate to a future frame
{

View File

@ -432,8 +432,12 @@ namespace BizHawk.Client.EmuHawk
if (!HandleMovieLoadStuff(newMovie))
return false;
// clear all selections
TasView.DeselectAll();
BookMarkControl.Restart();
MarkerControl.Restart();
BookMarkControl.UpdateValues();
RefreshDialog();
return true;
}
@ -594,6 +598,9 @@ namespace BizHawk.Client.EmuHawk
if (MarkerControl != null)
MarkerControl.UpdateValues();
if (BookMarkControl != null)
BookMarkControl.UpdateValues();
if (undoForm != null && !undoForm.IsDisposed)
undoForm.UpdateValues();
}

View File

@ -69,7 +69,12 @@ namespace BizHawk.Client.EmuHawk
var newTool = CreateInstance(toolType);
if (newTool is Form)
if (newTool == null)
{
return null;
}
if (newTool is Form)
{
(newTool as Form).Owner = GlobalWin.MainForm;
}
@ -497,16 +502,55 @@ namespace BizHawk.Client.EmuHawk
return CreateInstance(typeof(T));
}
private IToolForm CreateInstance(Type toolType)
{
var tool = (IToolForm)Activator.CreateInstance(toolType);
private IToolForm CreateInstance(Type toolType)
{
IToolForm tool;
// Add to our list of tools
_tools.Add(tool);
return tool;
}
//Specific case for custom tools
if (toolType == typeof(ICustomGameTool))
{
string path = Path.Combine(Global.Config.PathEntries["Global", "GameTools"].Path, string.Format("{0}.dll", Global.Game.Name));
if (File.Exists(path)
&& MessageBox.Show("A custom plugin has been found for the ROM you're loading. Do you want to load it?\r\nAccept ONLY if you trust the source and if you know what you're doing. In any other case, choose no."
, "Answer to life, universe and everything else?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
try
{
// As the object is "remote"(external to the project), the CreateInstanceFrom returns a handle.We need to Unwrap in order to make the casting
tool = System.Activator.CreateInstanceFrom(path, "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IToolForm;
if (tool == null)
{
MessageBox.Show("It seems that the object CustomMainForm does not implement IToolForm. Please review the code.", "Boom!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
}
catch (MissingMethodException)
{
MessageBox.Show("It seems that the object CustomMainForm does not have a public default constructor. Please review the code.", "Boom!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
catch (TypeLoadException)
{
MessageBox.Show("It seems that the object CustomMainForm does not exists. Please review the code.", "Boom!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
}
else
{
return null;
}
}
else
{
tool = (IToolForm)Activator.CreateInstance(toolType);
}
public void UpdateToolsBefore(bool fromLua = false)
// Add to our list of tools
_tools.Add(tool);
return tool;
}
public void UpdateToolsBefore(bool fromLua = false)
{
if (Has<LuaConsole>())
{

View File

@ -14,19 +14,14 @@ namespace BizHawk.Client.EmuHawk
var psx = ((Octoshock)Global.Emulator);
var settings = (Octoshock.SyncSettings)psx.GetSyncSettings();
for (int i = 0; i < settings.Controllers.Length; i++)
var fioConfig = settings.FIOConfig.ToLogical();
for (int i = 0; i < 2; i++)
{
if (settings.Controllers[i].IsConnected)
{
if (settings.Controllers[i].Type == Octoshock.ControllerSetting.ControllerType.Gamepad)
{
yield return GamePadController(i + 1);
}
else
{
yield return DualShockController(i + 1);
}
}
int pnum = i + 1;
if (fioConfig.DevicesPlayer[i] == OctoshockDll.ePeripheralType.DualAnalog || fioConfig.DevicesPlayer[i] == OctoshockDll.ePeripheralType.DualShock)
yield return DualShockController(pnum);
if (fioConfig.DevicesPlayer[i] == OctoshockDll.ePeripheralType.Pad)
yield return GamePadController(pnum);
}
yield return ConsoleButtons(psx);

View File

@ -1024,7 +1024,7 @@ namespace BizHawk.Client.EmuHawk
if (result)
{
MessageLabel.Text = Path.GetFileName(_currentFileName) + " saved";
Global.Config.RecentWatches.Add(watches.CurrentFileName);
Settings.RecentSearches.Add(watches.CurrentFileName);
}
}
}

View File

@ -315,6 +315,7 @@ namespace BizHawk.Emulation.Common
case ".T64":
case ".G64":
case ".CRT":
case ".TAP":
game.System = "C64";
break;

View File

@ -151,6 +151,7 @@
<Compile Include="Computers\Commodore64\C64.IDebuggable.cs">
<DependentUpon>C64.cs</DependentUpon>
</Compile>
<Compile Include="Computers\Commodore64\C64.IDisassemblable.cs" />
<Compile Include="Computers\Commodore64\C64.IDriveLight.cs">
<DependentUpon>C64.cs</DependentUpon>
</Compile>
@ -160,6 +161,7 @@
<Compile Include="Computers\Commodore64\C64.IMemoryDomains.cs">
<DependentUpon>C64.cs</DependentUpon>
</Compile>
<Compile Include="Computers\Commodore64\C64.ISettable.cs" />
<Compile Include="Computers\Commodore64\C64.IStatable.cs">
<DependentUpon>C64.cs</DependentUpon>
</Compile>
@ -176,14 +178,15 @@
<Compile Include="Computers\Commodore64\Cartridge\Mapper0013.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper0020.cs" />
<Compile Include="Computers\Commodore64\CassettePort\CassettePortDevice.cs" />
<Compile Include="Computers\Commodore64\CassettePort\Tape.cs" />
<Compile Include="Computers\Commodore64\InputFileInfo.cs" />
<Compile Include="Computers\Commodore64\Media\PRG.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Cart.cs" />
<Compile Include="Computers\Commodore64\MOS\CartridgePort.cs" />
<Compile Include="Computers\Commodore64\MOS\CassettePort.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip2114.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip23XX.cs" />
<Compile Include="Computers\Commodore64\MOS\Chip4864.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6567R56A.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6510.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6522.cs" />
<Compile Include="Computers\Commodore64\Media\D64.cs" />
@ -193,7 +196,8 @@
<Compile Include="Computers\Commodore64\MOS\MOS6526-2.Interface.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6526-2.PortIO.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6526.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6567.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6567R8.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6572.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6581.cs" />
<Compile Include="Computers\Commodore64\MOS\MOS6569.cs" />
<Compile Include="Computers\Commodore64\MOS\MOSPLA.cs" />
@ -797,8 +801,8 @@
<Compile Include="Consoles\Sony\PSX\Octoshock.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Consoles\Sony\PSX\OctoshockControlConfig.cs" />
<Compile Include="Consoles\Sony\PSX\OctoshockDll.cs" />
<Compile Include="Consoles\Sony\PSX\OctoshockFIOConfig.cs" />
<Compile Include="Consoles\Sony\PSX\PSF.cs" />
<Compile Include="Consoles\WonderSwan\BizSwan.cs" />
<Compile Include="Consoles\WonderSwan\WonderSwan.cs" />

View File

@ -2931,5 +2931,10 @@ namespace BizHawk.Emulation.Cores.Components.M6502
if (!rdy_freeze)
mi++;
} //ExecuteOne
public bool AtInstructionStart()
{
return Microcode[opcode][mi] >= Uop.End;
}
}
}

View File

@ -51,15 +51,110 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
}
}
public IMemoryCallbackSystem MemoryCallbacks
public bool CanStep(StepType type)
{
[FeatureNotImplemented]
get { throw new NotImplementedException(); }
switch (type)
{
case StepType.Into:
case StepType.Over:
case StepType.Out:
return true;
default:
return false;
}
}
[FeatureNotImplemented]
public void Step(StepType type) { throw new NotImplementedException(); }
public bool CanStep(StepType type) { return false; }
public void Step(StepType type)
{
switch (type)
{
case StepType.Into:
StepInto();
break;
case StepType.Out:
StepOut();
break;
case StepType.Over:
StepOver();
break;
}
}
private void StepInto()
{
while (board.cpu.AtInstructionStart())
{
DoCycle();
}
while (!board.cpu.AtInstructionStart())
{
DoCycle();
}
}
private void StepOver()
{
var instruction = board.cpu.Peek(board.cpu.PC);
if (instruction == JSR)
{
var destination = board.cpu.PC + JSRSize;
while (board.cpu.PC != destination)
{
StepInto();
}
}
else
{
StepInto();
}
}
private void StepOut()
{
var instr = board.cpu.Peek(board.cpu.PC);
JSRCount = instr == JSR ? 1 : 0;
var bailOutFrame = Frame + 1;
while (true)
{
StepInto();
instr = board.cpu.Peek(board.cpu.PC);
if (instr == JSR)
{
JSRCount++;
}
else if ((instr == RTS || instr == RTI) && JSRCount <= 0)
{
StepInto();
JSRCount = 0;
break;
}
else if (instr == RTS || instr == RTI)
{
JSRCount--;
}
else //Emergency Bailout Logic
{
if (Frame == bailOutFrame)
{
break;
}
}
}
}
private int JSRCount = 0;
private const byte JSR = 0x20;
private const byte RTI = 0x40;
private const byte RTS = 0x60;
private const byte JSRSize = 3;
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64
{
public partial class C64 : IDisassemblable
{
public string Cpu
{
get { return "6510"; } set { }
}
public string PCRegisterName
{
get { return "PC"; }
}
public IEnumerable<string> AvailableCpus
{
get { yield return "6510"; }
}
public string Disassemble(MemoryDomain m, uint addr, out int length)
{
return Components.M6502.MOS6502X.Disassemble((ushort)addr, out length, (a) => m.PeekByte(a));
}
}
}

View File

@ -0,0 +1,77 @@
using BizHawk.Emulation.Common;
using Newtonsoft.Json;
using System;
using System.ComponentModel;
using System.Drawing;
namespace BizHawk.Emulation.Cores.Computers.Commodore64
{
// adelikat: changing settings to default object untl there are actually settings, as the ui depends on it to know if there are any settings avaialable
public partial class C64 : ISettable<object, C64.C64SyncSettings>
{
public object /*C64Settings*/ GetSettings()
{
//return Settings.Clone();
return null;
}
public C64SyncSettings GetSyncSettings()
{
return SyncSettings.Clone();
}
public bool PutSettings(object /*C64Settings*/ o)
{
//Settings = o;
return false;
}
public bool PutSyncSettings(C64SyncSettings o)
{
SyncSettings = o;
return false;
}
internal C64Settings Settings { get; private set; }
internal C64SyncSettings SyncSettings { get; private set; }
public class C64Settings
{
public C64Settings Clone()
{
return (C64Settings)MemberwiseClone();
}
public C64Settings()
{
BizHawk.Common.SettingsUtil.SetDefaultValues(this);
}
}
public class C64SyncSettings
{
[DisplayName("VIC type")]
[Description("Set the type of video chip to use")]
[DefaultValue(VicType.PAL)]
public VicType vicType { get; set; }
public C64SyncSettings Clone()
{
return (C64SyncSettings)MemberwiseClone();
}
public C64SyncSettings()
{
BizHawk.Common.SettingsUtil.SetDefaultValues(this);
}
}
public enum VicType
{
PAL, NTSC, NTSC_OLD, DREAN
}
}
}

View File

@ -42,25 +42,48 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
private C64 _c64;
public Motherboard(C64 c64, Region initRegion)
public Motherboard(C64 c64, C64.VicType initRegion)
{
// note: roms need to be added on their own externally
_c64 = c64;
int clockNum, clockDen, mainsFrq;
switch (initRegion)
{
case C64.VicType.PAL:
clockNum = 17734475;
clockDen = 18;
mainsFrq = 50;
break;
case C64.VicType.NTSC:
case C64.VicType.NTSC_OLD:
clockNum = 11250000;
clockDen = 11;
mainsFrq = 60;
break;
case C64.VicType.DREAN:
clockNum = 14328225;
clockDen = 14;
mainsFrq = 50;
break;
default:
throw new System.Exception();
}
cartPort = new CartridgePort();
cassPort = new CassettePortDevice();
cia0 = new MOS6526(initRegion);
cia1 = new MOS6526(initRegion);
cia0 = new MOS6526(clockNum, clockDen*mainsFrq);
cia1 = new MOS6526(clockNum, clockDen*mainsFrq);
colorRam = new Chip2114();
cpu = new MOS6510();
pla = new MOSPLA();
ram = new Chip4864();
serPort = new SerialPort();
sid = MOS6581.Create(44100, initRegion);
sid = MOS6581.Create(44100, clockNum, clockDen);
switch (initRegion)
{
case Region.NTSC: vic = MOS6567.Create(); break;
case Region.PAL: vic = MOS6569.Create(); break;
case C64.VicType.NTSC: vic = MOS6567R8.Create(); break;
case C64.VicType.PAL: vic = MOS6569.Create(); break;
case C64.VicType.NTSC_OLD: vic = MOS6567R56A.Create(); break;
case C64.VicType.DREAN: vic = MOS6572.Create(); break;
}
userPort = new UserPortDevice();
}
@ -102,6 +125,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
sid.HardReset();
vic.HardReset();
userPort.HardReset();
cassPort.HardReset();
// because of how mapping works, the cpu needs to be hard reset twice
cpu.HardReset();

View File

@ -4,28 +4,25 @@ using System.IO;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Computers.Commodore64.MOS;
using System.Windows.Forms;
namespace BizHawk.Emulation.Cores.Computers.Commodore64
{
// TODO: use the EMulation.Common Region enum
public enum Region
{
NTSC,
PAL
}
[CoreAttributes(
"C64Hawk",
"SaxxonPIke",
isPorted: false,
isReleased: false
)]
[ServiceNotApplicable(typeof(IRegionable), typeof(ISettable<,>))]
sealed public partial class C64 : IEmulator, IStatable, IInputPollable, IDriveLight, IDebuggable
[ServiceNotApplicable(typeof(ISettable<,>))]
sealed public partial class C64 : IEmulator, IStatable, IInputPollable, IDriveLight, IDebuggable, IDisassemblable, IRegionable, ISettable<object, C64.C64SyncSettings>
{
// framework
public C64(CoreComm comm, GameInfo game, byte[] rom, string romextension)
public C64(CoreComm comm, GameInfo game, byte[] rom, string romextension, object Settings, object SyncSettings)
{
PutSyncSettings((C64SyncSettings)SyncSettings ?? new C64SyncSettings());
PutSettings((C64Settings)Settings ?? new C64Settings());
ServiceProvider = new BasicServiceProvider(this);
InputCallbacks = new InputCallbackSystem();
@ -33,14 +30,37 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
inputFileInfo.Data = rom;
inputFileInfo.Extension = romextension;
CoreComm = comm;
Init(Region.PAL);
Init(this.SyncSettings.vicType);
cyclesPerFrame = board.vic.CyclesPerFrame;
SetupMemoryDomains();
MemoryCallbacks = new MemoryCallbackSystem();
HardReset();
(ServiceProvider as BasicServiceProvider).Register<IVideoProvider>(board.vic);
}
/*private DisplayType queryUserForRegion()
{
Form prompt = new Form() { Width = 160, Height = 120, FormBorderStyle = FormBorderStyle.FixedDialog, Text = "Region selector", StartPosition = FormStartPosition.CenterScreen };
Label textLabel = new Label() { Left = 10, Top = 10, Width = 260, Text = "Please choose a region:" };
RadioButton palButton = new RadioButton() { Left = 10, Top = 30, Width = 70, Text = "PAL", Checked = true };
RadioButton ntscButton = new RadioButton() { Left = 80, Top = 30, Width = 70, Text = "NTSC" };
Button confirmation = new Button() { Text = "Ok", Left = 40, Width = 80, Top = 60, DialogResult = DialogResult.OK };
confirmation.Click += (sender, e) => { prompt.Close(); };
prompt.Controls.Add(textLabel);
prompt.Controls.Add(palButton);
prompt.Controls.Add(ntscButton);
prompt.Controls.Add(confirmation);
prompt.AcceptButton = confirmation;
if (prompt.ShowDialog() != DialogResult.OK || !palButton.Checked && !ntscButton.Checked)
{
throw new Exception("Can't construct new C64 because you didn't choose anything");
}
return palButton.Checked ? DisplayType.PAL : DisplayType.NTSC;
}*/
// internal variables
private int _frame = 0;
private int cyclesPerFrame;
@ -63,6 +83,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
_frame = 0;
_lagcount = 0;
_islag = false;
frameCycles = 0;
}
// audio/video
@ -92,6 +113,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
public IEmulatorServiceProvider ServiceProvider { get; private set; }
public DisplayType Region
{
get;
private set;
}
public void Dispose()
{
if (board.sid != null)
@ -101,76 +128,66 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
}
}
int frameCycles;
// process frame
public void FrameAdvance(bool render, bool rendersound)
{
board.inputRead = false;
board.PollInput();
board.cpu.LagCycles = 0;
for (int count = 0; count < cyclesPerFrame; count++)
do
{
//disk.Execute();
board.Execute();
DoCycle();
}
while (frameCycles != 0);
}
#if false
if (board.cpu.PC == 0xE16F && (board.cpu.ReadPort() & 0x7) == 7)
private void DoCycle()
{
if (frameCycles == 0) {
board.inputRead = false;
board.PollInput();
board.cpu.LagCycles = 0;
}
//disk.Execute();
board.Execute();
frameCycles++;
// load PRG file if needed
if (loadPrg)
{
// check to see if cpu PC is at the BASIC warm start vector
if (board.cpu.PC == ((board.ram.Peek(0x0303) << 8) | board.ram.Peek(0x0302)))
{
// HUGE kernal hack to load files
// the only purpose for this is to be able to run the Lorenz
// test suite!
//board.ram.Poke(0x0302, 0xAE);
//board.ram.Poke(0x0303, 0xA7);
////board.ram.Poke(0x0302, board.ram.Peek(0x0308));
////board.ram.Poke(0x0303, board.ram.Peek(0x0309));
int fileNameLength = board.ram.Peek(0xB7);
int fileNameOffset = board.ram.Peek(0xBB) | ((int)board.ram.Peek(0xBC) << 8);
byte[] fileNameRaw = new byte[fileNameLength];
for (int i = 0; i < fileNameLength; i++)
{
fileNameRaw[i] = board.ram.Peek(fileNameOffset + i);
}
var enc = System.Text.Encoding.ASCII;
string fileName = enc.GetString(fileNameRaw);
string filePath = Path.Combine(@"E:\Programming\Visual Studio 2013\Vice\testprogs\general\Lorenz-2.15\src\", fileName + ".prg");
if (File.Exists(filePath))
{
PRG.Load(board.pla, File.ReadAllBytes(filePath));
}
board.cpu.PC = 0xE1B5;
}
#endif
// load PRG file if needed
if (loadPrg)
{
// check to see if cpu PC is at the BASIC warm start vector
if (board.cpu.PC == ((board.ram.Peek(0x0303) << 8) | board.ram.Peek(0x0302)))
{
//board.ram.Poke(0x0302, 0xAE);
//board.ram.Poke(0x0303, 0xA7);
////board.ram.Poke(0x0302, board.ram.Peek(0x0308));
////board.ram.Poke(0x0303, board.ram.Peek(0x0309));
//if (inputFileInfo.Data.Length >= 6)
//{
// board.ram.Poke(0x0039, inputFileInfo.Data[4]);
// board.ram.Poke(0x003A, inputFileInfo.Data[5]);
//}
PRG.Load(board.pla, inputFileInfo.Data);
loadPrg = false;
}
//if (inputFileInfo.Data.Length >= 6)
//{
// board.ram.Poke(0x0039, inputFileInfo.Data[4]);
// board.ram.Poke(0x003A, inputFileInfo.Data[5]);
//}
PRG.Load(board.pla, inputFileInfo.Data);
loadPrg = false;
}
}
board.Flush();
_islag = !board.inputRead;
if (frameCycles == cyclesPerFrame)
{
board.Flush();
_islag = !board.inputRead;
if (_islag)
_lagcount++;
_frame++;
if (_islag)
_lagcount++;
frameCycles -= cyclesPerFrame;
_frame++;
//Console.WriteLine("CPUPC: " + C64Util.ToHex(board.cpu.PC, 4) + " 1541PC: " + C64Util.ToHex(disk.PC, 4));
//Console.WriteLine("CPUPC: " + C64Util.ToHex(board.cpu.PC, 4) + " 1541PC: " + C64Util.ToHex(disk.PC, 4));
int test = board.cpu.LagCycles;
DriveLightOn = DriveLED;
int test = board.cpu.LagCycles;
DriveLightOn = DriveLED;
}
}
private void HandleFirmwareError(string file)
@ -190,7 +207,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
return result;
}
private void Init(Region initRegion)
private void Init(VicType initRegion)
{
board = new Motherboard(this, initRegion);
InitRoms();
@ -213,6 +230,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
board.cartPort.Connect(cart);
}
break;
case @".TAP":
CassettePort.Tape tape = CassettePort.Tape.Load(inputFileInfo.Data);
if (tape != null)
{
board.cassPort.Connect(tape);
}
break;
case @".PRG":
if (inputFileInfo.Data.Length > 2)
loadPrg = true;

View File

@ -11,24 +11,31 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.CassettePort
{
public Func<bool> ReadDataOutput;
public Func<bool> ReadMotor;
Commodore64.CassettePort.Tape tape;
public void HardReset()
{
if (tape != null) tape.rewind();
}
virtual public bool ReadDataInputBuffer()
{
return true;
return tape != null && !ReadMotor() ? tape.read() : true;
}
virtual public bool ReadSenseBuffer()
{
return true;
return tape == null; // Just assume that "play" is constantly pressed as long as a tape is inserted
}
public void SyncState(Serializer ser)
{
SaveState.SyncObject(ser, this);
}
internal void Connect(Tape tape)
{
this.tape = tape;
}
}
}

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.CassettePort
{
/**
* This class represents a tape. Only TAP-style tapes are supported for now.
*/
class Tape
{
private readonly byte[] tapeData;
private readonly byte version;
private uint pos, cycle;
private readonly uint start, end;
public Tape(byte version, byte[] tapeData, uint start, uint end)
{
this.version = version;
this.tapeData = tapeData;
this.start = start;
this.end = end;
rewind();
}
// Rewinds the tape back to start
public void rewind()
{
pos = start;
cycle = 0;
}
// Reads from tape, this will tell the caller if the flag pin should be raised
public bool read()
{
if (cycle == 0)
{
if (pos >= end)
{
return true;
}
else
{
cycle = ((uint)tapeData[pos++])*8;
if (cycle == 0)
{
if (version == 0)
{
cycle = 256 * 8; // unspecified overflow condition
}
else
{
cycle = BitConverter.ToUInt32(tapeData, (int)pos-1)>>8;
pos += 3;
if (cycle == 0)
{
throw new Exception("Bad tape data");
}
}
}
}
}
// Send a single negative pulse at the end of a cycle
return --cycle != 0;
}
// Try to construct a tape file from file data. Returns null if not a tape file, throws exceptions for bad tape files.
// (Note that some error conditions aren't caught right here.)
static public Tape Load(byte[] tapeFile)
{
Tape result = null;
if (System.Text.Encoding.ASCII.GetString(tapeFile, 0, 12) == "C64-TAPE-RAW")
{
byte version = tapeFile[12];
if (version > 1) throw new Exception("This tape has an unsupported version");
uint size = BitConverter.ToUInt32(tapeFile, 16);
if (size + 20 != tapeFile.Length)
{
throw new Exception("Tape file header specifies a length that doesn't match the file size");
}
result = new Tape(version, tapeFile, 20, (uint)tapeFile.Length);
}
return result;
}
public void SyncState(Serializer ser)
{
ser.BeginSection("tape");
ser.Sync("pos", ref pos);
ser.Sync("cycle", ref cycle);
ser.EndSection();
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
public class CassettePort
{
public Func<bool> ReadDataOutput;
public Func<bool> ReadMotor;
public void HardReset()
{
}
virtual public bool ReadDataInputBuffer()
{
return true;
}
virtual public bool ReadSenseBuffer()
{
return true;
}
public void SyncState(Serializer ser)
{
SaveState.SyncObject(ser, this);
}
}
}

View File

@ -99,9 +99,14 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
}
set
{
lagCycles = value;
}
}
lagCycles = value;
}
}
internal bool AtInstructionStart()
{
return cpu.AtInstructionStart();
}
// ------------------------------------

View File

@ -233,7 +233,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
LatchedPort portA;
LatchedPort portB;
public MOS6526_2(Region region)
public MOS6526_2(Common.DisplayType region)
{
a = new CiaTimer(serialPortA, underFlowA);
b = new CiaTimer(serialPortB, underFlowB);
@ -241,10 +241,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
portB = new LatchedPort();
switch (region)
{
case Region.NTSC:
case Common.DisplayType.NTSC:
tod_period = 14318181 / 140;
break;
case Region.PAL:
case Common.DisplayType.PAL:
tod_period = 17734472 / 180;
break;
}

View File

@ -51,7 +51,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
// ------------------------------------
bool alarmSelect;
Region chipRegion;
bool cntPos;
bool enableIntAlarm;
bool enableIntFlag;
@ -77,16 +76,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
byte[] todAlarm;
bool todAlarmPM;
int todCounter;
int todCounterLatch;
bool todIn;
bool todPM;
bool oldFlag;
// ------------------------------------
public MOS6526(Region region)
int todStepsNum;
int todStepsDen;
// todStepsNum/todStepsDen is the number of clock cycles it takes the external clock source to advance one cycle
// (50 or 60 Hz depending on AC frequency in use).
// By default the CIA assumes 60 Hz and will thus count incorrectly when fed with 50 Hz.
public MOS6526(int todStepsNum, int todStepsDen)
{
chipRegion = region;
enableIntTimer = new bool[2];
this.todStepsNum = todStepsNum;
this.todStepsDen = todStepsDen;
enableIntTimer = new bool[2];
intTimer = new bool[2];
timerDelay = new int[2];
timerInMode = new InMode[2];
@ -96,7 +101,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
timerRunMode = new RunMode[2];
tod = new byte[4];
todAlarm = new byte[4];
SetTodIn(chipRegion);
portA = new LatchedPort();
portB = new LatchedPort();
@ -161,6 +165,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
cntPos = false;
underflow[0] = false;
underflow[1] = false;
bool newFlag = ReadFlag();
intFlag |= oldFlag && !newFlag;
oldFlag = newFlag;
}
}
@ -203,29 +211,14 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
todAlarm[1] = 0;
todAlarm[2] = 0;
todAlarm[3] = 0;
todCounter = todCounterLatch;
todIn = (chipRegion == Region.PAL);
todCounter = 0;
todIn = false;
todPM = false;
pinCnt = false;
pinPC = true;
}
private void SetTodIn(Region region)
{
switch (region)
{
case Region.NTSC:
todCounterLatch = 14318181 / 140;
todIn = false;
break;
case Region.PAL:
todCounterLatch = 17734472 / 180;
todIn = true;
break;
}
}
// ------------------------------------
private byte BCDAdd(byte i, byte j, out bool overflow)
@ -338,9 +331,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
bool todV;
if (todCounter == 0)
if (todCounter <= 0)
{
todCounter = todCounterLatch;
todCounter += todStepsNum*(todIn ? 6 : 5);
tod[0] = BCDAdd(tod[0], 1, out todV);
if (tod[0] >= 10)
{
@ -366,7 +359,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
}
}
}
todCounter--;
todCounter -= todStepsDen;
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
// vic ntsc old
// TODO is everything right? it's mostly a copy from the other NTSC chip with tweaks wherever it was neccessary to fix something
static public class MOS6567R56A
{
static int cycles = 64;
static int scanwidth = cycles * 8;
static int lines = 262;
static int vblankstart = 0x00D % lines;
static int vblankend = 0x018 % lines;
static int hblankoffset = 20;
static int hblankstart = (0x18C + hblankoffset) % scanwidth;
static int hblankend = (0x1F0 + hblankoffset) % scanwidth;
static int[] timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, scanwidth, -1, -1);
static int[] fetch = Vic.TimingBuilder_Fetch(timing, 0x174);
static int[] ba = Vic.TimingBuilder_BA(fetch);
static int[] act = Vic.TimingBuilder_Act(timing, 0x004, 0x14C, hblankstart, hblankend);
static int[][] pipeline = new int[][]
{
timing,
fetch,
ba,
act
};
static public Vic Create()
{
return new Vic(
cycles, lines,
pipeline,
14318181 / 14,
hblankstart, hblankend,
vblankstart, vblankend
);
}
}
}

View File

@ -1,41 +1,41 @@
using System.Drawing;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
// vic ntsc
static public class MOS6567
{
static int cycles = 65;
static int scanwidth = cycles * 8;
static int lines = 263;
static int vblankstart = 0x00D % lines;
static int vblankend = 0x018 % lines;
static int hblankoffset = 20;
static int hblankstart = (0x18C + hblankoffset) % scanwidth;
static int hblankend = (0x1F0 + hblankoffset) % scanwidth;
static int[] timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, scanwidth, 0x18C, 8);
static int[] fetch = Vic.TimingBuilder_Fetch(timing, 0x174);
static int[] ba = Vic.TimingBuilder_BA(fetch);
static int[] act = Vic.TimingBuilder_Act(timing, 0x004, 0x14C, hblankstart, hblankend);
static int[][] pipeline = new int[][]
{
timing,
fetch,
ba,
act
};
static public Vic Create()
{
return new Vic(
cycles, lines,
pipeline,
14318181 / 14,
hblankstart, hblankend,
vblankstart, vblankend
);
}
}
}
using System.Drawing;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
// vic ntsc
static public class MOS6567R8
{
static int cycles = 65;
static int scanwidth = cycles * 8;
static int lines = 263;
static int vblankstart = 0x00D % lines;
static int vblankend = 0x018 % lines;
static int hblankoffset = 20;
static int hblankstart = (0x18C + hblankoffset) % scanwidth - 8; // -8 because the VIC repeats internal pixel cycles around 0x18C
static int hblankend = (0x1F0 + hblankoffset) % scanwidth - 8;
static int[] timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, scanwidth, 0x18C, 8);
static int[] fetch = Vic.TimingBuilder_Fetch(timing, 0x174);
static int[] ba = Vic.TimingBuilder_BA(fetch);
static int[] act = Vic.TimingBuilder_Act(timing, 0x004, 0x14C, hblankstart, hblankend);
static int[][] pipeline = new int[][]
{
timing,
fetch,
ba,
act
};
static public Vic Create()
{
return new Vic(
cycles, lines,
pipeline,
14318181 / 14,
hblankstart, hblankend,
vblankstart, vblankend
);
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
// pal n / drean - TODO correct?
class MOS6572
{
static int cycles = 65;
static int scanwidth = cycles * 8;
static int lines = 312;
static int vblankstart = 0x12C % lines;
static int vblankend = 0x00F % lines;
static int hblankoffset = 20;
static int hblankstart = (0x18C + hblankoffset) % scanwidth - 8; // -8 because the VIC repeats internal pixel cycles around 0x18C
static int hblankend = (0x1F0 + hblankoffset) % scanwidth - 8;
static int[] timing = Vic.TimingBuilder_XRaster(0x19C, 0x200, scanwidth, 0x18C, 8);
static int[] fetch = Vic.TimingBuilder_Fetch(timing, 0x174);
static int[] ba = Vic.TimingBuilder_BA(fetch);
static int[] act = Vic.TimingBuilder_Act(timing, 0x004, 0x14C, hblankstart, hblankend);
static int[][] pipeline = new int[][]
{
timing,
fetch,
ba,
act
};
static public Vic Create()
{
return new Vic(
cycles, lines,
pipeline,
14328225 / 14,
hblankstart, hblankend,
vblankstart, vblankend
);
}
}
}

View File

@ -4119,9 +4119,9 @@
}
};
static public Sid Create(int newSampleRate, Region newRegion)
static public Sid Create(int newSampleRate, int clockFrqNum, int clockFrqDen)
{
return new Sid(waveTable, newSampleRate, newRegion);
return new Sid(waveTable, (uint)newSampleRate, (uint)clockFrqNum, (uint)clockFrqDen);
}
}
}

View File

@ -42,20 +42,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
public Func<byte> ReadPotX;
public Func<byte> ReadPotY;
public Sid(int[][] newWaveformTable, int newSampleRate, Region newRegion)
public Sid(int[][] newWaveformTable, uint sampleRate, uint cyclesNum, uint cyclesDen)
{
uint cyclesPerSec = 0;
uint cyclesNum;
uint cyclesDen;
uint sampleRate = 44100;
switch (newRegion)
{
case Region.NTSC: cyclesNum = 14318181; cyclesDen = 14; break;
case Region.PAL: cyclesNum = 17734472; cyclesDen = 18; break;
default: return;
}
waveformTable = newWaveformTable;
envelopes = new Envelope[3];

View File

@ -145,8 +145,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
}
else if (parseba == 0x1000)
{
pinBA = !badline;
}
pinBA = !badline;
}
else
{
parsecycleBAsprite0 = (parseba & 0x000F);

View File

@ -75,6 +75,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
}
// display enable compare
if (rasterLine == 0)
badlineEnable = false;
if (rasterLine == 0x030)
badlineEnable |= displayEnable;

View File

@ -10,7 +10,7 @@ using System.ComponentModel;
namespace BizHawk.Emulation.Cores.Nintendo.GBA
{
[CoreAttributes("mGBA", "endrift", true, false, "NOT DONE", "NOT DONE", false)]
[CoreAttributes("mGBA", "endrift", true, true, "0.2.0", "https://mgba.io/", false)]
[ServiceNotApplicable(typeof(IDriveLight), typeof(IRegionable))]
public class MGBAHawk : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable, ISaveRam, IStatable, IInputPollable, ISettable<object, MGBAHawk.SyncSettings>
{

View File

@ -39,47 +39,49 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
private void SetControllerButtons()
{
ControllerDefinition = new ControllerDefinition();
ControllerDefinition.Name = _SyncSettings.Controllers.All(c => c.Type == ControllerSetting.ControllerType.Gamepad)
? "PSX Gamepad Controller"
: "PSX DualShock Controller"; // Meh, more nuanced logic doesn't really work with a simple property
ControllerDefinition.Name = "PSX DualShock Controller"; // <-- for compatibility
//ControllerDefinition.Name = "PSX FrontIO"; // TODO - later rename to this, I guess, so it's less misleading. don't want to wreck keybindings yet.
ControllerDefinition.BoolButtons.Clear();
ControllerDefinition.FloatControls.Clear();
for (int i = 0; i < _SyncSettings.Controllers.Length; i++)
var cfg = _SyncSettings.FIOConfig.ToLogical();
for (int i = 0; i < cfg.NumPlayers; i++)
{
if (_SyncSettings.Controllers[i].IsConnected)
{
int pnum = i + 1;
ControllerDefinition.BoolButtons.AddRange(new[]
{
"P" + (i + 1) + " Up",
"P" + (i + 1) + " Down",
"P" + (i + 1) + " Left",
"P" + (i + 1) + " Right",
"P" + (i + 1) + " Select",
"P" + (i + 1) + " Start",
"P" + (i + 1) + " Square",
"P" + (i + 1) + " Triangle",
"P" + (i + 1) + " Circle",
"P" + (i + 1) + " Cross",
"P" + (i + 1) + " L1",
"P" + (i + 1) + " R1",
"P" + (i + 1) + " L2",
"P" + (i + 1) + " R2",
"P" + pnum + " Up",
"P" + pnum + " Down",
"P" + pnum + " Left",
"P" + pnum + " Right",
"P" + pnum + " Select",
"P" + pnum + " Start",
"P" + pnum + " Square",
"P" + pnum + " Triangle",
"P" + pnum + " Circle",
"P" + pnum + " Cross",
"P" + pnum + " L1",
"P" + pnum + " R1",
"P" + pnum + " L2",
"P" + pnum + " R2",
});
if (_SyncSettings.Controllers[i].Type != ControllerSetting.ControllerType.Gamepad)
var type = cfg.DevicesPlayer[i];
if (type == OctoshockDll.ePeripheralType.DualShock || type == OctoshockDll.ePeripheralType.DualAnalog)
{
ControllerDefinition.BoolButtons.Add("P" + (i + 1) + " L3");
ControllerDefinition.BoolButtons.Add("P" + (i + 1) + " R3");
ControllerDefinition.BoolButtons.Add("P" + (i + 1) + " MODE");
ControllerDefinition.BoolButtons.Add("P" + pnum + " L3");
ControllerDefinition.BoolButtons.Add("P" + pnum + " R3");
ControllerDefinition.BoolButtons.Add("P" + pnum + " MODE");
ControllerDefinition.FloatControls.AddRange(new[]
{
"P" + (i + 1) + " LStick X",
"P" + (i + 1) + " LStick Y",
"P" + (i + 1) + " RStick X",
"P" + (i + 1) + " RStick Y"
"P" + pnum + " LStick X",
"P" + pnum + " LStick Y",
"P" + pnum + " RStick X",
"P" + pnum + " RStick Y"
});
ControllerDefinition.FloatRanges.Add(new[] { 0.0f, 128.0f, 255.0f });
@ -88,7 +90,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
ControllerDefinition.FloatRanges.Add(new[] { 255.0f, 128.0f, 0.0f });
}
}
}
ControllerDefinition.BoolButtons.AddRange(new[]
{
@ -374,21 +375,18 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
//setup the controller based on sync settings
SetControllerButtons();
var lookup = new Dictionary<ControllerSetting.ControllerType, OctoshockDll.ePeripheralType> {
{ ControllerSetting.ControllerType.Gamepad, OctoshockDll.ePeripheralType.Pad },
{ ControllerSetting.ControllerType.DualAnalog, OctoshockDll.ePeripheralType.DualAnalog },
{ ControllerSetting.ControllerType.DualShock, OctoshockDll.ePeripheralType.DualShock },
var fioCfg = _SyncSettings.FIOConfig;
if(fioCfg.Devices8[0] != OctoshockDll.ePeripheralType.None)
OctoshockDll.shock_Peripheral_Connect(psx, 0x01, fioCfg.Devices8[0]);
if (fioCfg.Devices8[4] != OctoshockDll.ePeripheralType.None)
OctoshockDll.shock_Peripheral_Connect(psx, 0x02, fioCfg.Devices8[4]);
var memcardTransaction = new OctoshockDll.ShockMemcardTransaction()
{
transaction = OctoshockDll.eShockMemcardTransaction.Connect
};
if (_SyncSettings.Controllers[0].IsConnected)
{
OctoshockDll.shock_Peripheral_Connect(psx, 0x01, lookup[_SyncSettings.Controllers[0].Type]);
}
if (_SyncSettings.Controllers[1].IsConnected)
{
OctoshockDll.shock_Peripheral_Connect(psx, 0x02, lookup[_SyncSettings.Controllers[1].Type]);
}
if (fioCfg.Memcards[0]) OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref memcardTransaction);
if (fioCfg.Memcards[1]) OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x02, ref memcardTransaction);
//do this after framebuffers and peripherals and whatever crap are setup. kind of lame, but thats how it is for now
StudySaveBufferSize();
@ -423,65 +421,48 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
void SetInput()
{
uint buttons = 0;
var fioCfg = _SyncSettings.FIOConfig.ToLogical();
if (_SyncSettings.Controllers[0].IsConnected)
int portNum = 0x01;
foreach (int slot in new[] { 0, 4 })
{
//dualshock style
if (Controller["P1 Select"]) buttons |= 1;
if (Controller["P1 L3"]) buttons |= 2;
if (Controller["P1 R3"]) buttons |= 4;
if (Controller["P1 Start"]) buttons |= 8;
if (Controller["P1 Up"]) buttons |= 16;
if (Controller["P1 Right"]) buttons |= 32;
if (Controller["P1 Down"]) buttons |= 64;
if (Controller["P1 Left"]) buttons |= 128;
if (Controller["P1 L2"]) buttons |= 256;
if (Controller["P1 R2"]) buttons |= 512;
if (Controller["P1 L1"]) buttons |= 1024;
if (Controller["P1 R1"]) buttons |= 2048;
if (Controller["P1 Triangle"]) buttons |= 4096;
if (Controller["P1 Circle"]) buttons |= 8192;
if (Controller["P1 Cross"]) buttons |= 16384;
if (Controller["P1 Square"]) buttons |= 32768;
if (Controller["P1 MODE"]) buttons |= 65536;
//no input to set
if (fioCfg.Devices8[slot] == OctoshockDll.ePeripheralType.None)
continue;
byte left_x = (byte)Controller.GetFloat("P1 LStick X");
byte left_y = (byte)Controller.GetFloat("P1 LStick Y");
byte right_x = (byte)Controller.GetFloat("P1 RStick X");
byte right_y = (byte)Controller.GetFloat("P1 RStick Y");
uint buttons = 0;
string pstring = "P" + fioCfg.PlayerAssignments[slot] + " ";
OctoshockDll.shock_Peripheral_SetPadInput(psx, 0x01, buttons, left_x, left_y, right_x, right_y);
}
if (Controller[pstring + "Select"]) buttons |= 1;
if (Controller[pstring + "Start"]) buttons |= 8;
if (Controller[pstring + "Up"]) buttons |= 16;
if (Controller[pstring + "Right"]) buttons |= 32;
if (Controller[pstring + "Down"]) buttons |= 64;
if (Controller[pstring + "Left"]) buttons |= 128;
if (Controller[pstring + "L2"]) buttons |= 256;
if (Controller[pstring + "R2"]) buttons |= 512;
if (Controller[pstring + "L1"]) buttons |= 1024;
if (Controller[pstring + "R1"]) buttons |= 2048;
if (Controller[pstring + "Triangle"]) buttons |= 4096;
if (Controller[pstring + "Circle"]) buttons |= 8192;
if (Controller[pstring + "Cross"]) buttons |= 16384;
if (Controller[pstring + "Square"]) buttons |= 32768;
if (_SyncSettings.Controllers[1].IsConnected)
{
//dualshock style
buttons = 0;
if (Controller["P2 Select"]) buttons |= 1;
if (Controller["P2 L3"]) buttons |= 2;
if (Controller["P2 R3"]) buttons |= 4;
if (Controller["P2 Start"]) buttons |= 8;
if (Controller["P2 Up"]) buttons |= 16;
if (Controller["P2 Right"]) buttons |= 32;
if (Controller["P2 Down"]) buttons |= 64;
if (Controller["P2 Left"]) buttons |= 128;
if (Controller["P2 L2"]) buttons |= 256;
if (Controller["P2 R2"]) buttons |= 512;
if (Controller["P2 L1"]) buttons |= 1024;
if (Controller["P2 R1"]) buttons |= 2048;
if (Controller["P2 Triangle"]) buttons |= 4096;
if (Controller["P2 Circle"]) buttons |= 8192;
if (Controller["P2 Cross"]) buttons |= 16384;
if (Controller["P2 Square"]) buttons |= 32768;
if (Controller["P2 MODE"]) buttons |= 65536;
byte left_x = 0, left_y = 0, right_x = 0, right_y = 0;
if (fioCfg.Devices8[slot] == OctoshockDll.ePeripheralType.DualShock || fioCfg.Devices8[slot] == OctoshockDll.ePeripheralType.DualAnalog)
{
if (Controller[pstring + "L3"]) buttons |= 2;
if (Controller[pstring + "R3"]) buttons |= 4;
if (Controller[pstring + "MODE"]) buttons |= 65536;
byte left_x = (byte)Controller.GetFloat("P2 LStick X");
byte left_y = (byte)Controller.GetFloat("P2 LStick Y");
byte right_x = (byte)Controller.GetFloat("P2 RStick X");
byte right_y = (byte)Controller.GetFloat("P2 RStick Y");
left_x = (byte)Controller.GetFloat(pstring + "LStick X");
left_y = (byte)Controller.GetFloat(pstring + "LStick Y");
right_x = (byte)Controller.GetFloat(pstring + "RStick X");
right_y = (byte)Controller.GetFloat(pstring + "RStick Y");
}
OctoshockDll.shock_Peripheral_SetPadInput(psx, 0x02, buttons, left_x, left_y, right_x, right_y);
OctoshockDll.shock_Peripheral_SetPadInput(psx, portNum, buttons, left_x, left_y, right_x, right_y);
portNum <<= 1;
}
}
@ -858,25 +839,42 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
public byte[] CloneSaveRam()
{
var buf = new byte[128 * 1024];
fixed (byte* pbuf = buf)
var cfg = _SyncSettings.FIOConfig.ToLogical();
int nMemcards = cfg.NumMemcards;
var buf = new byte[128 * 1024 * nMemcards];
for (int i = 0, idx = 0, addr=0x01; i < 2; i++, addr<<=1)
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.buffer128k = pbuf;
transaction.transaction = OctoshockDll.eShockMemcardTransaction.Read;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref transaction);
if (cfg.Memcards[i])
{
fixed (byte* pbuf = buf)
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.buffer128k = pbuf + idx * 128 * 1024;
transaction.transaction = OctoshockDll.eShockMemcardTransaction.Read;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, addr, ref transaction);
idx++;
}
}
}
return buf;
}
public void StoreSaveRam(byte[] data)
{
fixed (byte* pbuf = data)
var cfg = _SyncSettings.FIOConfig.ToLogical();
for (int i = 0, idx = 0, addr = 0x01; i < 2; i++, addr <<= 1)
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.buffer128k = pbuf;
transaction.transaction = OctoshockDll.eShockMemcardTransaction.Write;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref transaction);
if (cfg.Memcards[i])
{
fixed (byte* pbuf = data)
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.buffer128k = pbuf + idx * 128 * 1024;
transaction.transaction = OctoshockDll.eShockMemcardTransaction.Write;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, addr, ref transaction);
idx++;
}
}
}
}
@ -884,9 +882,20 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
{
get
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.transaction = OctoshockDll.eShockMemcardTransaction.CheckDirty;
return OctoshockDll.shock_Peripheral_MemcardTransact(psx, 0x01, ref transaction) == OctoshockDll.SHOCK_TRUE;
var cfg = _SyncSettings.FIOConfig.ToLogical();
for (int i = 0, addr = 0x01; i < 2; i++, addr <<= 1)
{
if (cfg.Memcards[i])
{
var transaction = new OctoshockDll.ShockMemcardTransaction();
transaction.transaction = OctoshockDll.eShockMemcardTransaction.CheckDirty;
OctoshockDll.shock_Peripheral_MemcardTransact(psx, addr, ref transaction);
if (OctoshockDll.shock_Peripheral_MemcardTransact(psx, addr, ref transaction) == OctoshockDll.SHOCK_TRUE)
return true;
}
}
return false;
}
}
@ -1055,49 +1064,23 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
{
public SyncSettings Clone()
{
var ret = (SyncSettings)MemberwiseClone();
ret.Controllers = Controllers.Select(x => x.Clone()).ToArray();
return ret;
return JsonConvert.DeserializeObject<SyncSettings>(JsonConvert.SerializeObject(this));
}
public bool EnableLEC;
public ControllerSetting[] Controllers =
public SyncSettings()
{
new ControllerSetting
{
IsConnected = true,
Type = ControllerSetting.ControllerType.DualShock
},
new ControllerSetting
{
IsConnected = false,
Type = ControllerSetting.ControllerType.DualShock
}
};
}
public class ControllerSetting
{
public ControllerSetting Clone()
{
return (ControllerSetting)this.MemberwiseClone();
//initialize with historical default settings
var user = new OctoshockFIOConfigUser();
user.Memcards[0] = user.Memcards[1] = true;
user.Multitaps[0] = user.Multitaps[0] = false;
user.Devices8[0] = OctoshockDll.ePeripheralType.DualShock;
user.Devices8[4] = OctoshockDll.ePeripheralType.DualShock;
FIOConfig = user;
}
public bool IsConnected { get; set; }
public ControllerType Type { get; set; }
public enum ControllerType
{
Gamepad,
[Description("Dual Analog")]
DualAnalog,
[Description("Dual Shock")]
DualShock
}
public OctoshockFIOConfigUser FIOConfig;
}
public enum eHorizontalClipping
@ -1200,12 +1183,15 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
public bool PutSyncSettings(SyncSettings o)
{
//check for reboot-required options (well, none right now)
bool reboot = false;
//currently LEC and pad settings changes both require reboot
bool reboot = true;
//we could do it this way roughly if we need to
//if(JsonConvert.SerializeObject(o.FIOConfig) != JsonConvert.SerializeObject(_SyncSettings.FIOConfig)
_SyncSettings = o;
//TODO - store settings into core? or we can just keep doing it before frameadvance
return reboot;
}

View File

@ -3,28 +3,57 @@ using System.Collections.Generic;
namespace BizHawk.Emulation.Cores.Sony.PSX
{
public class OctoshockControlUserConfig
/// <summary>
/// Represents a user's view of what equipment is plugged into the PSX FIO
/// </summary>
public class OctoshockFIOConfigUser
{
public bool[] Multitaps = new bool[2];
public bool[] Memcards = new bool[2];
public OctoshockDll.ePeripheralType[] Devices8 = new OctoshockDll.ePeripheralType[8];
public OctoshockControlLogicalConfig ToLogicalConfig()
public OctoshockFIOConfigLogical ToLogical()
{
var lc = new OctoshockControlLogicalConfig();
var lc = new OctoshockFIOConfigLogical();
lc.PopulateFrom(this);
return lc;
}
}
public class OctoshockControlLogicalConfig
/// <summary>
/// Represents a baked-down view of what's plugged into the PSX FIO.
/// But really, users are interested in it too (its what produces the player number assignments)
/// </summary>
public class OctoshockFIOConfigLogical
{
public int[] PlayerAssignments = new int[8];
public bool[] Multitaps;
public bool[] Memcards;
public OctoshockDll.ePeripheralType[] Devices8;
internal void PopulateFrom(OctoshockControlUserConfig userConfig)
/// <summary>
/// Total number of players defined
/// </summary>
public int NumPlayers;
/// <summary>
/// The player number on each of the input slots
/// </summary>
public int[] PlayerAssignments = new int[8];
/// <summary>
/// The device type associated with each player
/// </summary>
public OctoshockDll.ePeripheralType[] DevicesPlayer = new OctoshockDll.ePeripheralType[8];
/// <summary>
/// Total number of connected memcards
/// </summary>
public int NumMemcards { get { return (Memcards[0] ? 1 : 0) + (Memcards[1] ? 1 : 0); } }
internal void PopulateFrom(OctoshockFIOConfigUser userConfig)
{
Multitaps = (bool[])userConfig.Multitaps.Clone();
Memcards = (bool[])userConfig.Memcards.Clone();
Devices8 = (OctoshockDll.ePeripheralType[])userConfig.Devices8.Clone();
int id = 1;
@ -38,6 +67,18 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
if (userConfig.Devices8[5] == OctoshockDll.ePeripheralType.None || !userConfig.Multitaps[1]) PlayerAssignments[5] = -1; else PlayerAssignments[5] = id++;
if (userConfig.Devices8[6] == OctoshockDll.ePeripheralType.None || !userConfig.Multitaps[1]) PlayerAssignments[6] = -1; else PlayerAssignments[6] = id++;
if (userConfig.Devices8[7] == OctoshockDll.ePeripheralType.None || !userConfig.Multitaps[1]) PlayerAssignments[7] = -1; else PlayerAssignments[7] = id++;
NumPlayers = id - 1;
for (int i = 0; i < 8; i++)
{
int pnum = i+1;
for (int j = 0; j < 8; j++)
{
if(PlayerAssignments[j] == pnum)
DevicesPlayer[i] = userConfig.Devices8[j];
}
}
}
}

View File

@ -1,6 +1,8 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Version", "Version\Version.csproj", "{0CE8B337-08E3-4602-BF10-C4D4C75D2F13}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.Common", "BizHawk.Client.Common\BizHawk.Client.Common.csproj", "{24A0AA3C-B25F-4197-B23D-476D6462DBA0}"
@ -96,24 +98,28 @@ Global
{866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|Win32.ActiveCfg = Release|x86
{866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x86.ActiveCfg = Release|x86
{866F8D13-0678-4FF9-80A4-A3993FD4D8A3}.Release|x86.Build.0 = Release|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Win32.ActiveCfg = Debug|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Mixed Platforms.Build.0 = Debug|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Win32.ActiveCfg = Debug|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|Win32.Build.0 = Debug|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x86.ActiveCfg = Debug|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Debug|x86.Build.0 = Debug|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Win32.ActiveCfg = Release|Any CPU
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.ActiveCfg = Release|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Mixed Platforms.Build.0 = Release|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Win32.ActiveCfg = Release|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|Win32.Build.0 = Release|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|x86.ActiveCfg = Release|x86
{DD448B37-BA3F-4544-9754-5406E8094723}.Release|x86.Build.0 = Release|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Win32.ActiveCfg = Debug|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Mixed Platforms.Build.0 = Debug|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Win32.ActiveCfg = Debug|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|Win32.Build.0 = Debug|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x86.ActiveCfg = Debug|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Debug|x86.Build.0 = Debug|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Win32.ActiveCfg = Release|Any CPU
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.ActiveCfg = Release|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Mixed Platforms.Build.0 = Release|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Win32.ActiveCfg = Release|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|Win32.Build.0 = Release|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x86.ActiveCfg = Release|x86
{C4366030-6D03-424B-AE53-F4F43BB217C3}.Release|x86.Build.0 = Release|x86
{F51946EA-827F-4D82-B841-1F2F6D060312}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
@ -166,14 +172,16 @@ Global
{5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|Win32.ActiveCfg = Release|x86
{5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x86.ActiveCfg = Release|x86
{5160CFB1-5389-47C1-B7F6-8A0DC97641EE}.Release|x86.Build.0 = Release|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Mixed Platforms.Build.0 = Debug|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Win32.ActiveCfg = Debug|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|Win32.Build.0 = Debug|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x86.ActiveCfg = Debug|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Debug|x86.Build.0 = Debug|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Win32.ActiveCfg = Release|Any CPU
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Mixed Platforms.ActiveCfg = Release|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Mixed Platforms.Build.0 = Release|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Win32.ActiveCfg = Release|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|Win32.Build.0 = Release|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x86.ActiveCfg = Release|x86
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9}.Release|x86.Build.0 = Release|x86
{337CA23E-65E7-44E1-9411-97EE08BB8116}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
@ -211,18 +219,18 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{24A0AA3C-B25F-4197-B23D-476D6462DBA0} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{DD448B37-BA3F-4544-9754-5406E8094723} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{C4366030-6D03-424B-AE53-F4F43BB217C3} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{24A0AA3C-B25F-4197-B23D-476D6462DBA0} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{E1A23168-B571-411C-B360-2229E7225E0E} = {3627C08B-3E43-4224-9DA4-40BD69495FBC}
{F51946EA-827F-4D82-B841-1F2F6D060312} = {3627C08B-3E43-4224-9DA4-40BD69495FBC}
{E1A23168-B571-411C-B360-2229E7225E0E} = {3627C08B-3E43-4224-9DA4-40BD69495FBC}
{197D4314-8A9F-49BA-977D-54ACEFAEB6BA} = {3627C08B-3E43-4224-9DA4-40BD69495FBC}
{9F84A0B2-861E-4EF4-B89B-5E2A3F38A465} = {0540A9A6-977E-466D-8BD3-1D8590BD5282}
{5160CFB1-5389-47C1-B7F6-8A0DC97641EE} = {0540A9A6-977E-466D-8BD3-1D8590BD5282}
{2D2890A8-C338-4439-AD8B-CB9EE85A94F9} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
{337CA23E-65E7-44E1-9411-97EE08BB8116} = {0540A9A6-977E-466D-8BD3-1D8590BD5282}
{E6B436B1-A3CD-4C9A-8F76-5D7154726884} = {0540A9A6-977E-466D-8BD3-1D8590BD5282}
{B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = BizHawk.Client.EmuHawk\BizHawk.Client.EmuHawk.csproj

View File

@ -13,6 +13,7 @@
**Sequentially number screenshots taken in the same second
**Finetune hotkey config dialog
**Leniency fixes to cue loading
**Make on-screen watches position editable
**Fix #461 - Repair autofire patterns
**Fix #477 - Support key input over IPC for automation
**Fix #490 - Ampersands in hex editor flakeout
@ -38,6 +39,7 @@
**Add movie.startsfromsavestate() and movie.startsfromsaveram(), movie.getheader(), movie.getcomments(), and movie.getsubtitles()
**Add memorysavestate library
**Fix bizstring.split()
**Fix crashes removing callbacks
**Fix #469 - forms.newform() : add an onclosed callback optional parameter
**Fix #463 - memory.readbyterange off-by-one
**Fix #498 - fix quicknes lua rendering being offset incorrectly sometimes
@ -49,8 +51,9 @@
**Issue #481 - keep scroll bar position when resetting the current rom as opposed to changing to a new one
*PSXHawk
**Update to mednafen 0.9.38.6
**Fix loading of some .psf filess
**Update to mednafen 0.9.38.7
**Support 0-2 pads/shocks and 0-2 memcards
**Fix loading of some .psf files
**Add overscan clipping and deinterlacer options
**Fix resolution management and PAR stuff for some PAL modes
**Support .xml disc bundling tool as alternative to .m3u

View File

@ -1,12 +1,12 @@
static class VersionInfo
{
public const string MAINVERSION = "1.10.0"; // Use numbers only or the new version notification won't work
public static readonly string RELEASEDATE = "June 15, 2015";
public const string MAINVERSION = "1.11.2"; // Use numbers only or the new version notification won't work
public static readonly string RELEASEDATE = "October 9, 2015";
public static readonly bool DeveloperBuild = true;
public static readonly string HomePage = "http://tasvideos.org/BizHawk.html";
public static string GetEmuVersion()
{
return DeveloperBuild ? "SVN " + SubWCRev.SVN_REV : ("Version " + MAINVERSION);
return DeveloperBuild ? ("GIT " + SubWCRev.GIT_BRANCH + "#" + SubWCRev.GIT_SHORTHASH) : ("Version " + MAINVERSION);
}
}
}

Binary file not shown.

View File

@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# Visual Studio 2015
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "octoshock", "octoshock.vcxproj", "{5F35CAFC-6208-4FBE-AD17-0E69BA3F70EC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniclient", "..\test\miniclient\miniclient.vcxproj", "{5A0DAC84-1170-4B1A-B9A9-F566A1D97790}"

View File

@ -80,4 +80,12 @@
[OK] psx/gpu : change to comments
[OK] psx/memcard : change to debug output
0.9.38.4 -> 0.9.38.6
[OK] psx/gpu & gpu_sprite : Fixed GPU emulation timing bugs that caused graphical glitches in "Mr. Driller G".
[OK] psx/gpu & gpu_sprite : Fixed GPU emulation timing bugs that caused graphical glitches in "Mr. Driller G".
0.9.38.5 -> 0.9.38.7
[OK] psx/cpu : Revisions to exception handling
[OK] psx/cpu : Many revisions and cleanups to branch and exception handling in opcode implementations
[OK] psx/dis : Just some basic disassembly changes
[OK] psx/gte : Cleanup
[OK] psx/psx : Cleanup
[OK] psx/timer : Major functional changes
[NO] psx/timer : Added loadstate sanity checks

File diff suppressed because it is too large Load Diff

View File

@ -1,263 +1,262 @@
#ifndef __MDFN_PSX_CPU_H
#define __MDFN_PSX_CPU_H
/*
Load delay notes:
// Takes 1 less
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"nop\n\t"
"or %0, %1, %1\n\t"
// cycle than this:
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"or %0, %1, %1\n\t"
"nop\n\t"
// Both of these
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"nop\n\t"
"or %1, %0, %0\n\t"
// take same...(which is kind of odd).
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"or %1, %0, %0\n\t"
"nop\n\t"
*/
#include "gte.h"
namespace MDFN_IEN_PSX
{
#define PS_CPU_EMULATE_ICACHE 1
class PS_CPU
{
public:
PS_CPU() MDFN_COLD;
~PS_CPU() MDFN_COLD;
template<bool isReader>void SyncState(EW::NewState *ns);
// FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes
// will always be multiples of 4.
enum { FAST_MAP_SHIFT = 16 };
enum { FAST_MAP_PSIZE = 1 << FAST_MAP_SHIFT };
void SetFastMap(void *region_mem, uint32 region_address, uint32 region_size);
INLINE void SetEventNT(const pscpu_timestamp_t next_event_ts_arg)
{
next_event_ts = next_event_ts_arg;
}
pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode);
void Power(void) MDFN_COLD;
// which ranges 0-5, inclusive
void AssertIRQ(unsigned which, bool asserted);
void SetHalt(bool status);
// TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed.
void SetBIU(uint32 val);
uint32 GetBIU(void);
private:
uint32 GPR[32 + 1]; // GPR[32] Used as dummy in load delay simulation(indexing past the end of real GPR)
uint32 LO;
uint32 HI;
uint32 BACKED_PC;
uint32 BACKED_new_PC;
uint32 BACKED_new_PC_mask;
uint32 IPCache;
void RecalcIPCache(void);
bool Halted;
uint32 BACKED_LDWhich;
uint32 BACKED_LDValue;
uint32 LDAbsorb;
pscpu_timestamp_t next_event_ts;
pscpu_timestamp_t gte_ts_done;
pscpu_timestamp_t muldiv_ts_done;
uint32 BIU;
struct __ICache
{
uint32 TV;
uint32 Data;
};
union
{
__ICache ICache[1024];
uint32 ICache_Bulk[2048];
};
enum
{
CP0REG_BPC = 3, // PC breakpoint address.
CP0REG_BDA = 5, // Data load/store breakpoint address.
CP0REG_TAR = 6, // Target address(???)
CP0REG_DCIC = 7, // Cache control
CP0REG_BDAM = 9, // Data load/store address mask.
CP0REG_BPCM = 11, // PC breakpoint address mask.
CP0REG_SR = 12,
CP0REG_CAUSE = 13,
CP0REG_EPC = 14,
CP0REG_PRID = 15, // Product ID
CP0REG_ERREG = 16
};
struct
{
union
{
uint32 Regs[32];
struct
{
uint32 Unused00;
uint32 Unused01;
uint32 Unused02;
uint32 BPC; // RW
uint32 Unused04;
uint32 BDA; // RW
uint32 TAR;
uint32 DCIC; // RW
uint32 Unused08;
uint32 BDAM; // R/W
uint32 Unused0A;
uint32 BPCM; // R/W
uint32 SR; // R/W
uint32 CAUSE; // R/W(partial)
uint32 EPC; // R
uint32 PRID; // R
uint32 ERREG; // ?(may not exist, test)
};
};
} CP0;
#if 1
//uint32 WrAbsorb;
//uint8 WrAbsorbShift;
// On read:
//WrAbsorb = 0;
//WrAbsorbShift = 0;
// On write:
//WrAbsorb >>= (WrAbsorbShift >> 2) & 8;
//WrAbsorbShift -= (WrAbsorbShift >> 2) & 8;
//WrAbsorb |= (timestamp - pre_write_timestamp) << WrAbsorbShift;
//WrAbsorbShift += 8;
#endif
uint8 ReadAbsorb[0x20 + 1];
uint8 ReadAbsorbWhich;
uint8 ReadFudge;
//uint32 WriteAbsorb;
//uint8 WriteAbsorbCount;
//uint8 WriteAbsorbMonkey;
uint8 MULT_Tab24[24];
MultiAccessSizeMem<1024, false> ScratchRAM;
//PS_GTE GTE;
uint8 *FastMap[1 << (32 - FAST_MAP_SHIFT)];
uint8 DummyPage[FAST_MAP_PSIZE];
enum
{
EXCEPTION_INT = 0,
EXCEPTION_MOD = 1,
EXCEPTION_TLBL = 2,
EXCEPTION_TLBS = 3,
EXCEPTION_ADEL = 4, // Address error on load
EXCEPTION_ADES = 5, // Address error on store
EXCEPTION_IBE = 6, // Instruction bus error
EXCEPTION_DBE = 7, // Data bus error
EXCEPTION_SYSCALL = 8, // System call
EXCEPTION_BP = 9, // Breakpoint
EXCEPTION_RI = 10, // Reserved instruction
EXCEPTION_COPU = 11, // Coprocessor unusable
EXCEPTION_OV = 12 // Arithmetic overflow
};
uint32 Exception(uint32 code, uint32 PC, const uint32 NPM) MDFN_WARN_UNUSED_RESULT;
template<bool DebugMode, bool BIOSPrintMode, bool ILHMode> pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE;
template<typename T> T PeekMemory(uint32 address) MDFN_COLD;
template<typename T> void PokeMemory(uint32 address, T value) MDFN_COLD;
template<typename T> T ReadMemory(pscpu_timestamp_t &timestamp, uint32 address, bool DS24 = false, bool LWC_timing = false);
template<typename T> void WriteMemory(pscpu_timestamp_t &timestamp, uint32 address, uint32 value, bool DS24 = false);
//
// Mednafen debugger stuff follows:
//
public:
void SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32 pc), void (*addbt)(uint32 from, uint32 to, bool exception));
void CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr);
void* debug_GetScratchRAMPtr() { return ScratchRAM.data8; }
void* debug_GetGPRPtr() { return GPR; }
enum
{
GSREG_GPR = 0,
GSREG_PC = 32,
GSREG_PC_NEXT,
GSREG_IN_BD_SLOT,
GSREG_LO,
GSREG_HI,
GSREG_SR,
GSREG_CAUSE,
GSREG_EPC,
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
bool PeekCheckICache(uint32 PC, uint32 *iw);
uint8 PeekMem8(uint32 A);
uint16 PeekMem16(uint32 A);
uint32 PeekMem32(uint32 A);
void PokeMem8(uint32 A, uint8 V);
void PokeMem16(uint32 A, uint16 V);
void PokeMem32(uint32 A, uint32 V);
private:
void (*CPUHook)(const pscpu_timestamp_t timestamp, uint32 pc);
void (*ADDBT)(uint32 from, uint32 to, bool exception);
};
}
#endif
#ifndef __MDFN_PSX_CPU_H
#define __MDFN_PSX_CPU_H
/*
Load delay notes:
// Takes 1 less
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"nop\n\t"
"or %0, %1, %1\n\t"
// cycle than this:
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"or %0, %1, %1\n\t"
"nop\n\t"
// Both of these
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"nop\n\t"
"or %1, %0, %0\n\t"
// take same...(which is kind of odd).
".set noreorder\n\t"
".set nomacro\n\t"
"lw %0, 0(%2)\n\t"
"nop\n\t"
"or %1, %0, %0\n\t"
"nop\n\t"
*/
#include "gte.h"
namespace MDFN_IEN_PSX
{
#define PS_CPU_EMULATE_ICACHE 1
class PS_CPU
{
public:
PS_CPU() MDFN_COLD;
~PS_CPU() MDFN_COLD;
template<bool isReader>void SyncState(EW::NewState *ns);
// FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes
// will always be multiples of 4.
enum { FAST_MAP_SHIFT = 16 };
enum { FAST_MAP_PSIZE = 1 << FAST_MAP_SHIFT };
void SetFastMap(void *region_mem, uint32 region_address, uint32 region_size);
INLINE void SetEventNT(const pscpu_timestamp_t next_event_ts_arg)
{
next_event_ts = next_event_ts_arg;
}
pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode);
void Power(void) MDFN_COLD;
// which ranges 0-5, inclusive
void AssertIRQ(unsigned which, bool asserted);
void SetHalt(bool status);
// TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed.
void SetBIU(uint32 val);
uint32 GetBIU(void);
private:
uint32 GPR[32 + 1]; // GPR[32] Used as dummy in load delay simulation(indexing past the end of real GPR)
uint32 LO;
uint32 HI;
uint32 BACKED_PC;
uint32 BACKED_new_PC;
uint32 BACKED_new_PC_mask;
uint32 IPCache;
void RecalcIPCache(void);
bool Halted;
uint32 BACKED_LDWhich;
uint32 BACKED_LDValue;
uint32 LDAbsorb;
pscpu_timestamp_t next_event_ts;
pscpu_timestamp_t gte_ts_done;
pscpu_timestamp_t muldiv_ts_done;
uint32 BIU;
struct __ICache
{
uint32 TV;
uint32 Data;
};
union
{
__ICache ICache[1024];
uint32 ICache_Bulk[2048];
};
enum
{
CP0REG_BPC = 3, // PC breakpoint address.
CP0REG_BDA = 5, // Data load/store breakpoint address.
CP0REG_TAR = 6, // Target address(???)
CP0REG_DCIC = 7, // Cache control
CP0REG_BADVA = 8,
CP0REG_BDAM = 9, // Data load/store address mask.
CP0REG_BPCM = 11, // PC breakpoint address mask.
CP0REG_SR = 12,
CP0REG_CAUSE = 13,
CP0REG_EPC = 14,
CP0REG_PRID = 15 // Product ID
};
struct
{
union
{
uint32 Regs[32];
struct
{
uint32 Unused00;
uint32 Unused01;
uint32 Unused02;
uint32 BPC; // RW
uint32 Unused04;
uint32 BDA; // RW
uint32 TAR; // R
uint32 DCIC; // RW
uint32 BADVA; // R
uint32 BDAM; // R/W
uint32 Unused0A;
uint32 BPCM; // R/W
uint32 SR; // R/W
uint32 CAUSE; // R/W(partial)
uint32 EPC; // R
uint32 PRID; // R
};
};
} CP0;
#if 1
//uint32 WrAbsorb;
//uint8 WrAbsorbShift;
// On read:
//WrAbsorb = 0;
//WrAbsorbShift = 0;
// On write:
//WrAbsorb >>= (WrAbsorbShift >> 2) & 8;
//WrAbsorbShift -= (WrAbsorbShift >> 2) & 8;
//WrAbsorb |= (timestamp - pre_write_timestamp) << WrAbsorbShift;
//WrAbsorbShift += 8;
#endif
uint8 ReadAbsorb[0x20 + 1];
uint8 ReadAbsorbWhich;
uint8 ReadFudge;
//uint32 WriteAbsorb;
//uint8 WriteAbsorbCount;
//uint8 WriteAbsorbMonkey;
uint8 MULT_Tab24[24];
MultiAccessSizeMem<1024, false> ScratchRAM;
//PS_GTE GTE;
uint8 *FastMap[1 << (32 - FAST_MAP_SHIFT)];
uint8 DummyPage[FAST_MAP_PSIZE];
enum
{
EXCEPTION_INT = 0,
EXCEPTION_MOD = 1,
EXCEPTION_TLBL = 2,
EXCEPTION_TLBS = 3,
EXCEPTION_ADEL = 4, // Address error on load
EXCEPTION_ADES = 5, // Address error on store
EXCEPTION_IBE = 6, // Instruction bus error
EXCEPTION_DBE = 7, // Data bus error
EXCEPTION_SYSCALL = 8, // System call
EXCEPTION_BP = 9, // Breakpoint
EXCEPTION_RI = 10, // Reserved instruction
EXCEPTION_COPU = 11, // Coprocessor unusable
EXCEPTION_OV = 12 // Arithmetic overflow
};
uint32 Exception(uint32 code, uint32 PC, const uint32 NP, const uint32 NPM, const uint32 instr) MDFN_WARN_UNUSED_RESULT;
template<bool DebugMode, bool BIOSPrintMode, bool ILHMode> pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE;
template<typename T> T PeekMemory(uint32 address) MDFN_COLD;
template<typename T> void PokeMemory(uint32 address, T value) MDFN_COLD;
template<typename T> T ReadMemory(pscpu_timestamp_t &timestamp, uint32 address, bool DS24 = false, bool LWC_timing = false);
template<typename T> void WriteMemory(pscpu_timestamp_t &timestamp, uint32 address, uint32 value, bool DS24 = false);
//
// Mednafen debugger stuff follows:
//
public:
void SetCPUHook(void(*cpuh)(const pscpu_timestamp_t timestamp, uint32 pc), void(*addbt)(uint32 from, uint32 to, bool exception));
void CheckBreakpoints(void(*callback)(bool write, uint32 address, unsigned int len), uint32 instr);
void* debug_GetScratchRAMPtr() { return ScratchRAM.data8; }
void* debug_GetGPRPtr() { return GPR; }
enum
{
GSREG_GPR = 0,
GSREG_PC = 32,
GSREG_PC_NEXT,
GSREG_IN_BD_SLOT,
GSREG_LO,
GSREG_HI,
GSREG_SR,
GSREG_CAUSE,
GSREG_EPC,
};
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
void SetRegister(unsigned int which, uint32 value);
bool PeekCheckICache(uint32 PC, uint32 *iw);
uint8 PeekMem8(uint32 A);
uint16 PeekMem16(uint32 A);
uint32 PeekMem32(uint32 A);
void PokeMem8(uint32 A, uint8 V);
void PokeMem16(uint32 A, uint16 V);
void PokeMem32(uint32 A, uint32 V);
private:
void(*CPUHook)(const pscpu_timestamp_t timestamp, uint32 pc);
void(*ADDBT)(uint32 from, uint32 to, bool exception);
};
}
#endif

View File

@ -128,13 +128,15 @@ struct OpEntry
#define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, ((unsigned)op << 26) | func, mnemonic, format }
#define MK_OP_REGIMM(mnemonic, regop) { MASK_OP | MASK_RT, (0x01U << 26) | (regop << 16), mnemonic, "s, p" }
#define MK_OP_REGIMM(mnemonic, regop_mask, regop) { MASK_OP | (regop_mask << 16), (0x01U << 26) | (regop << 16), mnemonic, "s, p" }
#define MK_COPZ(z) { MASK_OP | (0x1U << 25), (0x1U << 25) | ((0x10U | z) << 26), "cop" #z, "F" }
#define MK_COP0_FUNC(mnemonic, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x10U << 26) | (0x1U << 25) | func, mnemonic, "" }
#define MK_COPZ_XFER(z, mnemonic, format, xf) { MASK_OP | (0x1FU << 21), ((0x10U | z) << 26) | (xf << 21), mnemonic, format }
#define MK_COPZ_BCzx(z, x) { MASK_OP | (0x1BU << 21) | (0x01 << 16), ((0x10U | z) << 26) | (0x08 << 21) | (x << 16), (x ? "bc" #z "t" : "bc" #z "f"), "p" }
#define MK_COPZ_BC(z) MK_COPZ_BCzx(z, 0), MK_COPZ_BCzx(z, 1)
#define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x1U << 25) | (0x12U << 26) | func, mnemonic, format }
@ -180,10 +182,12 @@ static OpEntry ops[] =
MK_OP("slt", "d, s, t", 0, 42, 0),
MK_OP("sltu", "d, s, t", 0, 43, 0),
MK_OP_REGIMM("bgez", 0x01),
MK_OP_REGIMM("bgezal", 0x11),
MK_OP_REGIMM("bltz", 0x00),
MK_OP_REGIMM("bltzal", 0x10),
// keep *al before the non-linking versions, due to mask setup.
MK_OP_REGIMM("bgezal", 0x1F, 0x11),
MK_OP_REGIMM("bltzal", 0x1F, 0x10),
MK_OP_REGIMM("bgez", 0x01, 0x01),
MK_OP_REGIMM("bltz", 0x00, 0x00),
MK_OP("j", "P", 2, 0, 0),
@ -225,6 +229,11 @@ static OpEntry ops[] =
MK_COPZ_XFER(2, "ctc2", "t, G", 0x06),
MK_COPZ_XFER(3, "ctc3", "t, ?", 0x06),
MK_COPZ_BC(0),
MK_COPZ_BC(1),
MK_COPZ_BC(2),
MK_COPZ_BC(3),
// COP0 stuff here
MK_COP0_FUNC("rfe", 0x10),
@ -316,8 +325,8 @@ EW_EXPORT s32 shock_Util_DisassembleMIPS(u32 PC, u32 instr, void* outbuf, s32 bu
static const char *cop0_names[32] =
{
"CPR0", "CPR1", "CPR2", "BPC", "CPR4", "BDA", "TAR", "DCIC", "CPR8", "BDAM", "CPR10", "BPCM", "SR", "CAUSE", "EPC", "PRID",
"ERREG", "CPR17", "CPR18", "CPR19", "CPR20", "CPR21", "CPR22", "CPR23", "CPR24", "CPR25", "CPR26", "CPR27", "CPR28", "CPR29", "CPR30", "CPR31"
"CPR0", "CPR1", "CPR2", "BPC", "CPR4", "BDA", "TAR", "DCIC", "BADVA", "BDAM", "CPR10", "BPCM", "SR", "CAUSE", "EPC", "PRID",
"CPR16", "CPR17", "CPR18", "CPR19", "CPR20", "CPR21", "CPR22", "CPR23", "CPR24", "CPR25", "CPR26", "CPR27", "CPR28", "CPR29", "CPR30", "CPR31"
};
static const char *gte_cr_names[32] =

View File

@ -136,10 +136,6 @@ FrontIO::FrontIO()
PortData[i] = NULL;
MCPorts[i] = new InputDevice();
}
//always add one memory device for now
delete MCPorts[0];
MCPorts[0] = Device_Memcard_Create();
}

View File

@ -26,6 +26,8 @@ class InputDevice
virtual void Update(const pscpu_timestamp_t timestamp); // Partially-implemented, don't rely on for timing any more fine-grained than a video frame for now.
virtual void ResetTS(void);
virtual const char* GetName() const { return "InputDevice"; }
//
//

View File

@ -796,22 +796,6 @@ static INLINE int32 Lm_G(unsigned int which, int32 value)
// limit to 4096, not 4095
static INLINE int32 Lm_H(int32 value)
{
#if 0
if(FLAGS & (1 << 15))
{
value = 0;
FLAGS |= 1 << 12;
return value;
}
if(FLAGS & (1 << 16))
{
value = 4096;
FLAGS |= 1 << 12;
return value;
}
#endif
if(value < 0)
{
value = 0;

View File

@ -40,6 +40,8 @@ class InputDevice_Memcard : public InputDevice
InputDevice_Memcard();
virtual ~InputDevice_Memcard();
virtual const char* GetName() const { return "InputDevice_Memcard"; }
virtual void Power(void);
virtual void SyncState(bool isReader, EW::NewState *ns);
//

View File

@ -32,6 +32,8 @@
#include "input/dualshock.h"
#include "input/dualanalog.h"
#include "input/gamepad.h"
#include "input/memcard.h"
#include <stdarg.h>
#include <ctype.h>
@ -272,7 +274,6 @@ static void RebaseTS(const pscpu_timestamp_t timestamp)
void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp)
{
assert(type > PSX_EVENT__SYNFIRST && type < PSX_EVENT__SYNLAST);
event_list_entry *e = &events[type];
if(next_timestamp < e->event_time)
@ -1198,8 +1199,15 @@ struct {
//TODO - once we get flexible here, do some extra condition checks.. whether memcards exist, etc. much like devices.
switch(transaction->transaction)
{
case eShockMemcardTransaction_Connect: return SHOCK_ERROR; //not supported yet
case eShockMemcardTransaction_Disconnect: return SHOCK_ERROR; //not supported yet
case eShockMemcardTransaction_Connect:
//cant connect when a memcard is already connected
if(!strcmp(FIO->MCPorts[portnum]->GetName(),"InputDevice_Memcard"))
return SHOCK_NOCANDO;
delete FIO->MCPorts[portnum]; //delete dummy
FIO->MCPorts[portnum] = Device_Memcard_Create();
case eShockMemcardTransaction_Disconnect:
return SHOCK_ERROR; //not supported yet
case eShockMemcardTransaction_Write:
FIO->MCPorts[portnum]->WriteNV((uint8*)transaction->buffer128k,0,128*1024);

View File

@ -18,433 +18,441 @@
#include <assert.h>
#include "psx.h"
#include "timer.h"
/*
Notes(some of it may be incomplete or wrong in subtle ways)
Control bits:
Lower 3 bits of mode, for timer1(when mode is | 0x100):
0x1 = don't count while in vblank(except that the first count while in vblank does go through)
0x3 = vblank going inactive triggers timer reset, then some interesting behavior where counting again is delayed...
0x5 = vblank going inactive triggers timer reset, and only count within vblank.
0x7 = Wait until vblank goes active then inactive, then start counting?
For timer2:
0x1 = timer stopped(TODO: confirm on real system)
Target mode enabled 0x008
IRQ enable 0x010
--?Affects 0x400 status flag?-- 0x020
IRQ evaluation auto-reset 0x040
--unknown-- 0x080
Clock selection 0x100
Divide by 8(timer 2 only?) 0x200
Counter:
Reset to 0 on writes to the mode/status register.
Status flags:
Unknown flag 0x0400
Compare flag 0x0800
Cleared on mode/status read.
Set when: //ever Counter == 0(proooobably, need to investigate lower 3 bits in relation to this).
Overflow/Carry flag 0x1000
Cleared on mode/status read.
Set when counter overflows from 0xFFFF->0.
Hidden flags:
IRQ done
Cleared on writes to the mode/status register, on writes to the count register, and apparently automatically when the counter
increments if (Mode & 0x40) [Note: If target mode is enabled, and target is 0, IRQ done flag won't be automatically reset]
There seems to be a brief period(edge condition?) where, if count to target is enabled, you can (sometimes?) read the target value in the count
register before it's reset to 0. I doubt any games rely on this, but who knows. Maybe a PSX equivalent of the PC Engine "Battle Royale"? ;)
When the counter == 0, the compare flag is set. An IRQ will be generated if (Mode & 0x10), and the hidden IRQ done flag will be set.
*/
/*
Dec. 26, 2011 Note
Due to problems I've had with my GPU timing test program, timer2 appears to be unreliable(clocks are skipped?) when target mode is enabled and the full
33MHz clock is used(rather than 33MHz / 8). TODO: Investigate further and confirm(or not).
Jan. 15, 2013 Note:
Counters using GPU clock sources(hretrace,dot clock) reportedly will with a low probability return wrong count values on an actual PS1, so keep this in mind
when writing test programs(IE keep reading the count value until two consecutive reads return the same value).
*/
/*
FIXME: Clock appropriately(and update events) when using SetRegister() via the debugger.
TODO: If we ever return randomish values to "simulate" open bus, remember to change the return type and such of the TIMER_Read() function to full 32-bit too.
*/
namespace MDFN_IEN_PSX
{
struct Timer
{
uint32 Mode;
int32 Counter; // Only 16-bit, but 32-bit here for detecting counting past target.
int32 Target;
int32 Div8Counter;
bool IRQDone;
int32 DoZeCounting;
};
static bool vblank;
static bool hretrace;
static Timer Timers[3];
static pscpu_timestamp_t lastts;
static int32 CalcNextEvent(int32 next_event)
{
for(int i = 0; i < 3; i++)
{
int32 target;
int32 count_delta;
if((i == 0 || i == 1) && (Timers[i].Mode & 0x100)) // If clocked by GPU, abort for this timer(will result in poor granularity for pixel-clock-derived timer IRQs, but whatever).
continue;
if(!(Timers[i].Mode & 0x10)) // If IRQ is disabled, abort for this timer.
continue;
if((Timers[i].Mode & 0x8) && (Timers[i].Counter == 0) && (Timers[i].Target == 0) && !Timers[i].IRQDone)
{
next_event = 1;
continue;
}
target = ((Timers[i].Mode & 0x8) && (Timers[i].Counter < Timers[i].Target)) ? Timers[i].Target : 0x10000;
count_delta = target - Timers[i].Counter;
if(count_delta <= 0)
{
PSX_DBG(PSX_DBG_ERROR, "timer %d count_delta <= 0!!! %d %d\n", i, target, Timers[i].Counter);
continue;
}
{
int32 tmp_clocks;
if(Timers[i].DoZeCounting <= 0)
continue;
if((i == 0x2) && (Timers[i].Mode & 0x1))
continue;
if((i == 0x2) && (Timers[i].Mode & 0x200))
{
assert(Timers[i].Div8Counter >= 0 && Timers[i].Div8Counter < 8);
tmp_clocks = ((count_delta - 1) * 8) + (8 - Timers[i].Div8Counter);
}
else
tmp_clocks = count_delta;
assert(tmp_clocks > 0);
if(next_event > tmp_clocks)
next_event = tmp_clocks;
}
}
return(next_event);
}
static void ClockTimer(int i, uint32 clocks)
{
int32 before = Timers[i].Counter;
int32 target = 0x10000;
bool zero_tm = false;
if(Timers[i].DoZeCounting <= 0)
clocks = 0;
if(i == 0x2)
{
uint32 d8_clocks;
Timers[i].Div8Counter += clocks;
d8_clocks = Timers[i].Div8Counter >> 3;
Timers[i].Div8Counter -= d8_clocks << 3;
if(Timers[i].Mode & 0x200) // Divide by 8, at least for timer 0x2
clocks = d8_clocks;
if(Timers[i].Mode & 1)
clocks = 0;
}
if(Timers[i].Mode & 0x008)
target = Timers[i].Target;
if(target == 0 && Timers[i].Counter == 0)
zero_tm = true;
else
Timers[i].Counter += clocks;
if(clocks && (Timers[i].Mode & 0x40))
Timers[i].IRQDone = false;
if((before < target && Timers[i].Counter >= target) || zero_tm || Timers[i].Counter > 0xFFFF)
{
#if 1
if(Timers[i].Mode & 0x10)
{
if((Timers[i].Counter - target) > 3)
PSX_WARNING("Timer %d IRQ trigger error: %d", i, Timers[i].Counter - target);
}
#endif
Timers[i].Mode |= 0x0800;
if(Timers[i].Counter > 0xFFFF)
{
Timers[i].Counter -= 0x10000;
if(target == 0x10000)
Timers[i].Mode |= 0x1000;
if(!target)
Timers[i].Counter = 0;
}
if(target)
Timers[i].Counter -= (Timers[i].Counter / target) * target;
if((Timers[i].Mode & 0x10) && !Timers[i].IRQDone)
{
Timers[i].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + i, true);
IRQ_Assert(IRQ_TIMER_0 + i, false);
}
if(Timers[i].Counter && (Timers[i].Mode & 0x40))
Timers[i].IRQDone = false;
}
}
void TIMER_SetVBlank(bool status)
{
switch(Timers[1].Mode & 0x7)
{
case 0x1:
Timers[1].DoZeCounting = !status;
break;
case 0x3:
if(vblank && !status)
Timers[1].Counter = 0;
break;
case 0x5:
Timers[1].DoZeCounting = status;
if(vblank && !status)
Timers[1].Counter = 0;
break;
case 0x7:
if(Timers[1].DoZeCounting == -1)
{
if(!vblank && status)
Timers[1].DoZeCounting = 0;
}
else if(Timers[1].DoZeCounting == 0)
{
if(vblank && !status)
Timers[1].DoZeCounting = 1;
}
break;
}
vblank = status;
}
void TIMER_SetHRetrace(bool status)
{
if(hretrace && !status)
{
if((Timers[0].Mode & 0x7) == 0x3)
Timers[0].Counter = 0;
}
hretrace = status;
}
void TIMER_AddDotClocks(uint32 count)
{
if(Timers[0].Mode & 0x100)
ClockTimer(0, count);
}
void TIMER_ClockHRetrace(void)
{
if(Timers[1].Mode & 0x100)
ClockTimer(1, 1);
}
pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t timestamp)
{
int32 cpu_clocks = timestamp - lastts;
for(int i = 0; i < 3; i++)
{
uint32 timer_clocks = cpu_clocks;
if(Timers[i].Mode & 0x100)
continue;
ClockTimer(i, timer_clocks);
}
lastts = timestamp;
return(timestamp + CalcNextEvent(1024));
}
static void CalcCountingStart(unsigned which)
{
Timers[which].DoZeCounting = true;
switch(which)
{
case 1:
switch(Timers[which].Mode & 0x07)
{
case 0x1:
Timers[which].DoZeCounting = !vblank;
break;
case 0x5:
Timers[which].DoZeCounting = vblank;
break;
case 0x7:
Timers[which].DoZeCounting = -1;
break;
}
break;
}
}
void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
{
TIMER_Update(timestamp);
int which = (A >> 4) & 0x3;
V <<= (A & 3) * 8;
PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V);
if(which >= 3)
return;
// TODO: See if the "Timers[which].Counter" part of the IRQ if() statements below is what a real PSX does.
switch(A & 0xC)
{
case 0x0: Timers[which].IRQDone = false;
#if 1
if(Timers[which].Counter && (V & 0xFFFF) == 0)
{
Timers[which].Mode |= 0x0800;
if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone)
{
Timers[which].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + which, true);
IRQ_Assert(IRQ_TIMER_0 + which, false);
}
}
#endif
Timers[which].Counter = V & 0xFFFF;
break;
case 0x4: Timers[which].Mode = (V & 0x3FF) | (Timers[which].Mode & 0x1C00);
Timers[which].IRQDone = false;
#if 1
if(Timers[which].Counter)
{
Timers[which].Mode |= 0x0800;
if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone)
{
Timers[which].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + which, true);
IRQ_Assert(IRQ_TIMER_0 + which, false);
}
}
Timers[which].Counter = 0;
#endif
CalcCountingStart(which); // Call after setting .Mode
break;
case 0x8: Timers[which].Target = V & 0xFFFF;
break;
case 0xC: // Open bus
break;
}
// TIMER_Update(timestamp);
PSX_SetEventNT(PSX_EVENT_TIMER, timestamp + CalcNextEvent(1024));
}
uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
uint16 ret = 0;
int which = (A >> 4) & 0x3;
if(which >= 3)
{
PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
return(ret >> ((A & 3) * 8));
}
TIMER_Update(timestamp);
switch(A & 0xC)
{
case 0x0: ret = Timers[which].Counter;
break;
case 0x4: ret = Timers[which].Mode;
Timers[which].Mode &= ~0x1800;
break;
case 0x8: ret = Timers[which].Target;
break;
case 0xC: PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
break;
}
return(ret >> ((A & 3) * 8));
}
void TIMER_ResetTS(void)
{
lastts = 0;
}
void TIMER_Power(void)
{
lastts = 0;
hretrace = false;
vblank = false;
memset(Timers, 0, sizeof(Timers));
/*
Notes(some of it may be incomplete or wrong in subtle ways)
Control bits:
Lower 3 bits of mode, for timer1(when mode is | 0x100):
0x1 = don't count while in vblank(except that the first count while in vblank does go through)
0x3 = vblank going inactive triggers timer reset, then some interesting behavior where counting again is delayed...
0x5 = vblank going inactive triggers timer reset, and only count within vblank.
0x7 = Wait until vblank goes active then inactive, then start counting?
For timer2:
0x1 = timer stopped(TODO: confirm on real system)
Target match counter reset enable 0x008
Target match IRQ enable 0x010
Overflow IRQ enable 0x020
IRQ evaluation auto-reset 0x040
--unknown-- 0x080
Clock selection 0x100
Divide by 8(timer 2 only?) 0x200
Counter:
Reset to 0 on writes to the mode/status register.
Status flags:
Current IRQ line status? 0x0400
Compare flag 0x0800
Cleared on mode/status read.
Set repeatedly while counter == target.
Overflow/Carry flag 0x1000
Cleared on mode/status read.
Set when counter overflows from 0xFFFF->0.
Hidden flags:
IRQ done
Cleared on writes to the mode/status register, on writes to the count register, and apparently automatically when the counter
increments if (Mode & 0x40) [Note: If target mode is enabled, and target is 0, IRQ done flag won't be automatically reset]
There seems to be a brief period(edge condition?) where, if target match reset mode is enabled, you can (sometimes?) read the target value in the count
register before it's reset to 0. Currently not emulated; I doubt any games rely on this, but who knows. Maybe a PSX equivalent
of the PC Engine "Battle Royale"? ;)
A timer is somewhat unreliable when target match reset mode is enabled and the 33MHz clock is used. Average 2.4 counts seem to be
skipped for that timer every target match reset, but oddly subtracting only 2 from the desired target match value seems to effectively
negate the loss...wonder if my test program is faulty in some way. Currently not emulated.
Counters using GPU clock sources(hretrace,dot clock) reportedly will with a low probability return wrong count values on an actual PS1,
so keep this in mind when writing test programs(IE keep reading the count value until two consecutive reads return the same value).
Currently not emulated.
*/
/*
FIXME: Clock appropriately(and update events) when using SetRegister() via the debugger.
TODO: If we ever return randomish values to "simulate" open bus, remember to change the return type and such of the TIMER_Read() function to full 32-bit too.
*/
namespace MDFN_IEN_PSX
{
struct Timer
{
uint32 Mode;
uint32 Counter; // Only 16-bit, but 32-bit here for detecting counting past target.
uint32 Target;
uint32 Div8Counter;
bool IRQDone;
int32 DoZeCounting;
};
static bool vblank;
static bool hretrace;
static Timer Timers[3];
static pscpu_timestamp_t lastts;
static uint32 CalcNextEvent(void)
{
uint32 next_event = 1024; //
for(unsigned i = 0; i < 3; i++)
{
if(!(Timers[i].Mode & 0x30)) // If IRQ is disabled, abort for this timer(don't look at IRQDone for this test, or things will break since its resetting is deferred!).
continue;
if((Timers[i].Mode & 0x8) && (Timers[i].Counter == 0) && (Timers[i].Target == 0) && !Timers[i].IRQDone)
{
next_event = 1;
continue;
}
//
//
if((i == 0 || i == 1) && (Timers[i].Mode & 0x100)) // If clocked by GPU, abort for this timer(will result in poor granularity for pixel-clock-derived timer IRQs, but whatever).
continue;
if(Timers[i].DoZeCounting <= 0)
continue;
if((i == 0x2) && (Timers[i].Mode & 0x1))
continue;
//
//
//
const uint32 target = ((Timers[i].Mode & 0x18) && (Timers[i].Counter < Timers[i].Target)) ? Timers[i].Target : 0x10000;
const uint32 count_delta = target - Timers[i].Counter;
uint32 tmp_clocks;
if((i == 0x2) && (Timers[i].Mode & 0x200))
tmp_clocks = (count_delta * 8) - Timers[i].Div8Counter;
else
tmp_clocks = count_delta;
if(next_event > tmp_clocks)
next_event = tmp_clocks;
}
return(next_event);
}
static bool TimerMatch(unsigned i)
{
bool irq_exact = false;
Timers[i].Mode |= 0x0800;
if(Timers[i].Mode & 0x008)
Timers[i].Counter %= std::max<uint32>(1, Timers[i].Target);
if((Timers[i].Mode & 0x10) && !Timers[i].IRQDone)
{
if(Timers[i].Counter == 0 || Timers[i].Counter == Timers[i].Target)
irq_exact = true;
#if 1
{
const uint16 lateness = (Timers[i].Mode & 0x008) ? Timers[i].Counter : (Timers[i].Counter - Timers[i].Target);
if(lateness > ((i == 1 && (Timers[i].Mode & 0x100)) ? 0 : 3))
PSX_DBG(PSX_DBG_WARNING, "[TIMER] Timer %d match IRQ trigger late: %u\n", i, lateness);
}
#endif
Timers[i].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + i, true);
IRQ_Assert(IRQ_TIMER_0 + i, false);
}
return irq_exact;
}
static bool TimerOverflow(unsigned i)
{
bool irq_exact = false;
Timers[i].Mode |= 0x1000;
Timers[i].Counter &= 0xFFFF;
if((Timers[i].Mode & 0x20) && !Timers[i].IRQDone)
{
if(Timers[i].Counter == 0)
irq_exact = true;
#if 1
if(Timers[i].Counter > ((i == 1 && (Timers[i].Mode & 0x100)) ? 0 : 3))
PSX_DBG(PSX_DBG_WARNING, "[TIMER] Timer %d overflow IRQ trigger late: %u\n", i, Timers[i].Counter);
#endif
Timers[i].IRQDone = true;
IRQ_Assert(IRQ_TIMER_0 + i, true);
IRQ_Assert(IRQ_TIMER_0 + i, false);
}
return irq_exact;
}
static void ClockTimer(int i, uint32 clocks)
{
if(Timers[i].DoZeCounting <= 0)
clocks = 0;
if(i == 0x2)
{
uint32 d8_clocks;
Timers[i].Div8Counter += clocks;
d8_clocks = Timers[i].Div8Counter >> 3;
Timers[i].Div8Counter &= 0x7;
if(Timers[i].Mode & 0x200) // Divide by 8, at least for timer 0x2
clocks = d8_clocks;
if(Timers[i].Mode & 1)
clocks = 0;
}
if((Timers[i].Mode & 0x008) && Timers[i].Target == 0 && Timers[i].Counter == 0)
TimerMatch(i);
else if(clocks)
{
uint32 before = Timers[i].Counter;
Timers[i].Counter += clocks;
if(Timers[i].Mode & 0x40)
Timers[i].IRQDone = false;
bool irq_exact = false;
//
// Target match handling
//
if((before < Timers[i].Target && Timers[i].Counter >= Timers[i].Target) || (Timers[i].Counter >= Timers[i].Target + 0x10000))
irq_exact |= TimerMatch(i);
//
// Overflow handling
//
if(Timers[i].Counter >= 0x10000)
irq_exact |= TimerOverflow(i);
//
if((Timers[i].Mode & 0x40) && !irq_exact)
Timers[i].IRQDone = false;
}
}
void TIMER_SetVBlank(bool status)
{
switch(Timers[1].Mode & 0x7)
{
case 0x1:
Timers[1].DoZeCounting = !status;
break;
case 0x3:
if(vblank && !status)
{
Timers[1].Counter = 0;
if(Timers[1].Counter == Timers[1].Target)
TimerMatch(1);
}
break;
case 0x5:
Timers[1].DoZeCounting = status;
if(vblank && !status)
{
Timers[1].Counter = 0;
if(Timers[1].Counter == Timers[1].Target)
TimerMatch(1);
}
break;
case 0x7:
if(Timers[1].DoZeCounting == -1)
{
if(!vblank && status)
Timers[1].DoZeCounting = 0;
}
else if(Timers[1].DoZeCounting == 0)
{
if(vblank && !status)
Timers[1].DoZeCounting = 1;
}
break;
}
vblank = status;
}
void TIMER_SetHRetrace(bool status)
{
if(hretrace && !status)
{
if((Timers[0].Mode & 0x7) == 0x3)
{
Timers[0].Counter = 0;
if(Timers[0].Counter == Timers[0].Target)
TimerMatch(0);
}
}
hretrace = status;
}
void TIMER_AddDotClocks(uint32 count)
{
if(Timers[0].Mode & 0x100)
ClockTimer(0, count);
}
void TIMER_ClockHRetrace(void)
{
if(Timers[1].Mode & 0x100)
ClockTimer(1, 1);
}
pscpu_timestamp_t TIMER_Update(const pscpu_timestamp_t timestamp)
{
int32 cpu_clocks = timestamp - lastts;
for(int i = 0; i < 3; i++)
{
uint32 timer_clocks = cpu_clocks;
if(Timers[i].Mode & 0x100)
continue;
ClockTimer(i, timer_clocks);
}
lastts = timestamp;
return(timestamp + CalcNextEvent());
}
static void CalcCountingStart(unsigned which)
{
Timers[which].DoZeCounting = true;
switch(which)
{
case 1:
switch(Timers[which].Mode & 0x07)
{
case 0x1:
Timers[which].DoZeCounting = !vblank;
break;
case 0x5:
Timers[which].DoZeCounting = vblank;
break;
case 0x7:
Timers[which].DoZeCounting = -1;
break;
}
break;
}
}
void TIMER_Write(const pscpu_timestamp_t timestamp, uint32 A, uint16 V)
{
TIMER_Update(timestamp);
int which = (A >> 4) & 0x3;
V <<= (A & 3) * 8;
PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V);
if(which >= 3)
return;
switch(A & 0xC)
{
case 0x0: Timers[which].IRQDone = false;
Timers[which].Counter = V & 0xFFFF;
break;
case 0x4: Timers[which].Mode = (V & 0x3FF) | (Timers[which].Mode & 0x1C00);
Timers[which].IRQDone = false;
Timers[which].Counter = 0;
CalcCountingStart(which); // Call after setting .Mode
break;
case 0x8: Timers[which].Target = V & 0xFFFF;
break;
case 0xC: // Open bus
break;
}
if(Timers[which].Counter == Timers[which].Target)
TimerMatch(which);
PSX_SetEventNT(PSX_EVENT_TIMER, timestamp + CalcNextEvent());
}
uint16 TIMER_Read(const pscpu_timestamp_t timestamp, uint32 A)
{
uint16 ret = 0;
int which = (A >> 4) & 0x3;
if(which >= 3)
{
PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
return(ret >> ((A & 3) * 8));
}
TIMER_Update(timestamp);
switch(A & 0xC)
{
case 0x0: ret = Timers[which].Counter;
break;
case 0x4: ret = Timers[which].Mode;
Timers[which].Mode &= ~0x1000;
if(Timers[which].Counter != Timers[which].Target)
Timers[which].Mode &= ~0x0800;
break;
case 0x8: ret = Timers[which].Target;
break;
case 0xC: PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
break;
}
return(ret >> ((A & 3) * 8));
}
void TIMER_ResetTS(void)
{
lastts = 0;
}
void TIMER_Power(void)
{
lastts = 0;
hretrace = false;
vblank = false;
memset(Timers, 0, sizeof(Timers));
}
void TIMER_SyncState(bool isReader, EW::NewState *ns)
@ -496,6 +504,9 @@ void TIMER_SetRegister(unsigned int which, uint32 value)
break;
}
if (Timers[tw].Counter == Timers[tw].Target)
TimerMatch(tw);
}