Merge pull request #1150 from TASVideos/ZXSpectrum
New system let's go!
This commit is contained in:
commit
981a31d32b
|
@ -461,6 +461,79 @@
|
|||
"Key Cursor Up/Down": "DownArrow",
|
||||
"Key Cursor Left/Right": "RightArrow",
|
||||
"Key Space": "Space"
|
||||
},
|
||||
"ZXSpectrum Controller": {
|
||||
"P1 Up": "NumberPad8, J1 POV1U, X1 DpadUp, X1 LStickUp",
|
||||
"P1 Down": "NumberPad2, J1 POV1D, X1 DpadDown, X1 LStickDown",
|
||||
"P1 Left": "NumberPad4, J1 POV1L, X1 DpadLeft, X1 LStickLeft",
|
||||
"P1 Right": "NumberPad6, J1 POV1R, X1 DpadRight, X1 LStickRight",
|
||||
"P1 Button": "NumberPad1, J1 B1, X1 X",
|
||||
"Key True Video": "",
|
||||
"Key Inv Video": "",
|
||||
"Key 1": "D1",
|
||||
"Key 2": "D2",
|
||||
"Key 3": "D3",
|
||||
"Key 4": "D4",
|
||||
"Key 5": "D5",
|
||||
"Key 6": "D6",
|
||||
"Key 7": "D7",
|
||||
"Key 8": "D8",
|
||||
"Key 9": "D9",
|
||||
"Key 0": "D0",
|
||||
"Key Break": "Delete",
|
||||
"Key Delete": "Backspace",
|
||||
"Key Graph": "",
|
||||
"Key Q": "Q",
|
||||
"Key W": "W",
|
||||
"Key E": "E",
|
||||
"Key R": "R",
|
||||
"Key T": "T",
|
||||
"Key Y": "Y",
|
||||
"Key U": "U",
|
||||
"Key I": "I",
|
||||
"Key O": "O",
|
||||
"Key P": "P",
|
||||
"Key Extend Mode": "",
|
||||
"Key Edit": "",
|
||||
"Key A": "A",
|
||||
"Key S": "S",
|
||||
"Key D": "D",
|
||||
"Key F": "F",
|
||||
"Key G": "G",
|
||||
"Key H": "H",
|
||||
"Key J": "J",
|
||||
"Key K": "K",
|
||||
"Key L": "L",
|
||||
"Key Return": "Return",
|
||||
"Key Caps Shift": "LeftShift, RightShift",
|
||||
"Key Caps Lock": "",
|
||||
"Key Z": "Z",
|
||||
"Key X": "X",
|
||||
"Key C": "C",
|
||||
"Key V": "V",
|
||||
"Key B": "B",
|
||||
"Key N": "N",
|
||||
"Key M": "M",
|
||||
"Key Period": "Period",
|
||||
"Key Symbol Shift": "LeftControl, RightControl",
|
||||
"Key Semi-Colon": "Semicolon",
|
||||
"Key Inverted-Comma": "",
|
||||
"Key Left Cursor": "LeftArrow",
|
||||
"Key Right Cursor": "RightArrow",
|
||||
"Key Space": "Space",
|
||||
"Key Up Cursor": "UpArrow",
|
||||
"Key Down Cursor": "DownArrow",
|
||||
"Key Comma": "Comma",
|
||||
"Play Tape": "F1",
|
||||
"Stop Tape": "F2",
|
||||
"RTZ Tape": "F3",
|
||||
"Record Tape": "",
|
||||
"Key Quote": "Shift+D2",
|
||||
"Insert Next Tape": "F6",
|
||||
"Insert Previous Tape": "F5",
|
||||
"Next Tape Block": "F8",
|
||||
"Prev Tape Block": "F7",
|
||||
"Get Tape Status": "F10"
|
||||
},
|
||||
"Intellivision Controller": {
|
||||
"P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp",
|
||||
|
|
|
@ -96,6 +96,9 @@ namespace BizHawk.Client.ApiHawk
|
|||
case "WSWAN":
|
||||
return CoreSystem.WonderSwan;
|
||||
|
||||
case "ZXSpectrum":
|
||||
return CoreSystem.ZXSpectrum;
|
||||
|
||||
case "VB":
|
||||
case "NGP":
|
||||
case "DNGP":
|
||||
|
@ -205,6 +208,9 @@ namespace BizHawk.Client.ApiHawk
|
|||
case CoreSystem.WonderSwan:
|
||||
return "WSWAN";
|
||||
|
||||
case CoreSystem.ZXSpectrum:
|
||||
return "ZXSpectrum";
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value.ToString()));
|
||||
}
|
||||
|
|
|
@ -427,11 +427,11 @@ namespace BizHawk.Client.ApiHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
return SystemInfo.DualGB;
|
||||
return SystemInfo.DualGB;
|
||||
}
|
||||
|
||||
default:
|
||||
return SystemInfo.FindByCoreSystem(SystemIdConverter.Convert(Global.Emulator.SystemId));
|
||||
return SystemInfo.FindByCoreSystem(SystemIdConverter.Convert(Global.Emulator.SystemId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
WonderSwan,
|
||||
Libretro,
|
||||
VirtualBoy,
|
||||
NeoGeoPocket
|
||||
NeoGeoPocket,
|
||||
ZXSpectrum
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,6 +149,8 @@ namespace BizHawk.Client.Common
|
|||
return SystemInfo.VirtualBoy;
|
||||
case "NGP":
|
||||
return SystemInfo.NeoGeoPocket;
|
||||
case "ZXSpectrum":
|
||||
return SystemInfo.ZXSpectrum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ using BizHawk.Emulation.Cores.PCEngine;
|
|||
using BizHawk.Emulation.Cores.Sega.Saturn;
|
||||
using BizHawk.Emulation.Cores.Sony.PSP;
|
||||
using BizHawk.Emulation.Cores.Sony.PSX;
|
||||
using BizHawk.Emulation.Cores.Computers.SinclairSpectrum;
|
||||
using BizHawk.Emulation.DiscSystem;
|
||||
|
||||
using GPGX64 = BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
|
@ -657,6 +658,21 @@ namespace BizHawk.Client.Common
|
|||
(C64.C64Settings)GetCoreSettings<C64>(),
|
||||
(C64.C64SyncSettings)GetCoreSyncSettings<C64>());
|
||||
break;
|
||||
case "ZXSpectrum":
|
||||
|
||||
List<GameInfo> zxGI = new List<GameInfo>();
|
||||
foreach (var a in xmlGame.Assets)
|
||||
{
|
||||
zxGI.Add(new GameInfo { Name = Path.GetFileNameWithoutExtension(a.Key) });
|
||||
}
|
||||
|
||||
nextEmulator = new ZXSpectrum(
|
||||
nextComm,
|
||||
xmlGame.Assets.Select(a => a.Value), //.First(),
|
||||
zxGI, // GameInfo.NullInstance,
|
||||
(ZXSpectrum.ZXSpectrumSettings)GetCoreSettings<ZXSpectrum>(),
|
||||
(ZXSpectrum.ZXSpectrumSyncSettings)GetCoreSyncSettings<ZXSpectrum>());
|
||||
break;
|
||||
case "PSX":
|
||||
var entries = xmlGame.AssetFullPaths;
|
||||
var discs = new List<Disc>();
|
||||
|
@ -990,6 +1006,10 @@ namespace BizHawk.Client.Common
|
|||
var c64 = new C64(nextComm, Enumerable.Repeat(rom.FileData, 1), rom.GameInfo, GetCoreSettings<C64>(), GetCoreSyncSettings<C64>());
|
||||
nextEmulator = c64;
|
||||
break;
|
||||
case "ZXSpectrum":
|
||||
var zx = new ZXSpectrum(nextComm, Enumerable.Repeat(rom.RomData, 1), Enumerable.Repeat(rom.GameInfo, 1).ToList(), GetCoreSettings<ZXSpectrum>(), GetCoreSyncSettings<ZXSpectrum>());
|
||||
nextEmulator = zx;
|
||||
break;
|
||||
case "GBA":
|
||||
if (Global.Config.GBA_UsemGBA)
|
||||
{
|
||||
|
|
|
@ -188,6 +188,11 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public static SystemInfo NeoGeoPocket { get; } = new SystemInfo("Neo-Geo Pocket", CoreSystem.NeoGeoPocket, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="SystemInfo"/> instance for ZXSpectrum
|
||||
/// </summary>
|
||||
public static SystemInfo ZXSpectrum { get; } = new SystemInfo("ZX Spectrum", CoreSystem.ZXSpectrum, 2);
|
||||
|
||||
#endregion Get SystemInfo
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -292,7 +292,13 @@ namespace BizHawk.Client.Common
|
|||
new PathEntry { System = "C64", SystemDisplayName = "Commodore 64", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
|
||||
new PathEntry { System = "C64", SystemDisplayName = "Commodore 64", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
|
||||
|
||||
new PathEntry { System = "PSX", SystemDisplayName = "Playstation", Type = "Base", Path = Path.Combine(".", "PSX"), Ordinal = 0 },
|
||||
new PathEntry { System = "ZXSpectrum", SystemDisplayName = "Sinclair ZX Spectrum", Type = "Base", Path = Path.Combine(".", "ZXSpectrum"), Ordinal = 0 },
|
||||
new PathEntry { System = "ZXSpectrum", SystemDisplayName = "Sinclair ZX Spectrum", Type = "ROM", Path = ".", Ordinal = 1 },
|
||||
new PathEntry { System = "ZXSpectrum", SystemDisplayName = "Sinclair ZX Spectrum", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
|
||||
new PathEntry { System = "ZXSpectrum", SystemDisplayName = "Sinclair ZX Spectrum", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
|
||||
new PathEntry { System = "ZXSpectrum", SystemDisplayName = "Sinclair ZX Spectrum", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
|
||||
|
||||
new PathEntry { System = "PSX", SystemDisplayName = "Playstation", Type = "Base", Path = Path.Combine(".", "PSX"), Ordinal = 0 },
|
||||
new PathEntry { System = "PSX", SystemDisplayName = "Playstation", Type = "ROM", Path = ".", Ordinal = 1 },
|
||||
new PathEntry { System = "PSX", SystemDisplayName = "Playstation", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
|
||||
new PathEntry { System = "PSX", SystemDisplayName = "Playstation", Type = "Save RAM", Path = Path.Combine(".", "SaveRAM"), Ordinal = 3 },
|
||||
|
|
|
@ -503,6 +503,24 @@
|
|||
<Compile Include="config\TI83\TI83PaletteConfig.Designer.cs">
|
||||
<DependentUpon>TI83PaletteConfig.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="config\ZXSpectrum\ZXSpectrumNonSyncSettings.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="config\ZXSpectrum\ZXSpectrumNonSyncSettings.Designer.cs">
|
||||
<DependentUpon>ZXSpectrumNonSyncSettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="config\ZXSpectrum\ZXSpectrumCoreEmulationSettings.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="config\ZXSpectrum\ZXSpectrumCoreEmulationSettings.Designer.cs">
|
||||
<DependentUpon>ZXSpectrumCoreEmulationSettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="config\ZXSpectrum\ZXSpectrumJoystickSettings.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="config\ZXSpectrum\ZXSpectrumJoystickSettings.Designer.cs">
|
||||
<DependentUpon>ZXSpectrumJoystickSettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CoreFeatureAnalysis.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -1206,6 +1224,7 @@
|
|||
<Compile Include="tools\VirtualPads\schema\SnesSchema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\VirtualBoySchema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\WonderSwanSchema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\ZXSpectrumSchema.cs" />
|
||||
<Compile Include="tools\VirtualPads\VirtualPad.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
@ -1403,6 +1422,15 @@
|
|||
<EmbeddedResource Include="config\TI83\TI83PaletteConfig.resx">
|
||||
<DependentUpon>TI83PaletteConfig.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="config\ZXSpectrum\ZXSpectrumNonSyncSettings.resx">
|
||||
<DependentUpon>ZXSpectrumNonSyncSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="config\ZXSpectrum\ZXSpectrumCoreEmulationSettings.resx">
|
||||
<DependentUpon>ZXSpectrumCoreEmulationSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="config\ZXSpectrum\ZXSpectrumJoystickSettings.resx">
|
||||
<DependentUpon>ZXSpectrumJoystickSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="CoreFeatureAnalysis.resx">
|
||||
<DependentUpon>CoreFeatureAnalysis.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
@ -1794,6 +1822,7 @@
|
|||
<None Include="config\ControllerImages\GENController.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\ZXSpectrumKeyboard.bmp" />
|
||||
<None Include="images\WSW.png" />
|
||||
<None Include="images\WNW.png" />
|
||||
<None Include="images\SW.png" />
|
||||
|
@ -2118,6 +2147,7 @@
|
|||
<None Include="images\ENE.png" />
|
||||
<None Include="images\ESE.png" />
|
||||
<None Include="images\ControllerImages\NGPController.png" />
|
||||
<Content Include="config\ControllerImages\ZXSpectrumKeyboards.png" />
|
||||
<Content Include="images\logo.ico" />
|
||||
<None Include="images\Paste.png" />
|
||||
<None Include="images\reboot.png" />
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
return new[]
|
||||
{
|
||||
".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF",
|
||||
".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS"
|
||||
".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
this.LoadCurrentSlotMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SaveRAMSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.FlushSaveRAMMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.MovieSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ReadonlyMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator15 = new System.Windows.Forms.ToolStripSeparator();
|
||||
|
@ -192,14 +192,13 @@
|
|||
this.GbaCoreSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.VbaNextCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MgbaCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SGBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SgbBsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SgbBsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SgbSameBoyMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGambatteMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGBHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGambatteMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGBHawkMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem16 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.allowGameDBCoreOverridesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
|
||||
|
@ -239,9 +238,8 @@
|
|||
this.coreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.quickNESToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.nesHawkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator34 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripSeparator35 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.NESPPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator34 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.NESPPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.NESNametableViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.NESGameGenieCodesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.musicRipperToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -280,6 +278,12 @@
|
|||
this.SMSdisplayNtscToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSdisplayPalToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSdisplayAutoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerStandardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerPaddleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerLightPhaserToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerSportsPadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerKeyboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMStoolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.SMSenableBIOSToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSEnableFMChipMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -304,14 +308,14 @@
|
|||
this.AtariSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.A7800SubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.A7800ControllerSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.A7800FilterSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.A7800FilterSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBcoreSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.LoadGBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator28 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.GBGPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBPrinterViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGameGenieMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGameGenieMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBPrinterViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBASubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBACoreSelectionSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBAmGBAMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -333,6 +337,7 @@
|
|||
this.SnesOptionsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ColecoSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ColecoControllerSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator35 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ColecoSkipBiosMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ColecoUseSGMMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.N64SubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -376,6 +381,11 @@
|
|||
this.ForumsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.FeaturesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.AboutMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.zXSpectrumToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ZXSpectrumCoreEmulationSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ZXSpectrumControllerConfigurationMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ZXSpectrumNonSyncSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MainStatusBar = new StatusStripEx();
|
||||
this.DumpStatusButton = new System.Windows.Forms.ToolStripDropDownButton();
|
||||
this.EmuStatus = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
|
@ -447,13 +457,7 @@
|
|||
this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.timerMouseIdle = new System.Windows.Forms.Timer(this.components);
|
||||
this.SMSControllerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerStandardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerPaddleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerLightPhaserToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerSportsPadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.SMSControllerKeyboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MainformMenu.SuspendLayout();
|
||||
this.MainformMenu.SuspendLayout();
|
||||
this.MainStatusBar.SuspendLayout();
|
||||
this.MainFormContextMenu.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
|
@ -490,7 +494,8 @@
|
|||
this.pCFXToolStripMenuItem,
|
||||
this.virtualBoyToolStripMenuItem,
|
||||
this.neoGeoPocketToolStripMenuItem,
|
||||
this.HelpSubMenu});
|
||||
this.HelpSubMenu,
|
||||
this.zXSpectrumToolStripMenuItem});
|
||||
this.MainformMenu.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.Flow;
|
||||
this.MainformMenu.Location = new System.Drawing.Point(0, 0);
|
||||
this.MainformMenu.Name = "MainformMenu";
|
||||
|
@ -912,26 +917,26 @@
|
|||
this.LoadCurrentSlotMenuItem.Size = new System.Drawing.Size(178, 22);
|
||||
this.LoadCurrentSlotMenuItem.Text = "Load Current Slot";
|
||||
this.LoadCurrentSlotMenuItem.Click += new System.EventHandler(this.LoadCurrentSlotMenuItem_Click);
|
||||
|
||||
//
|
||||
// SaveRAMSubMenu
|
||||
//
|
||||
this.SaveRAMSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.FlushSaveRAMMenuItem});
|
||||
this.SaveRAMSubMenu.Name = "SaveRAMSubMenu";
|
||||
this.SaveRAMSubMenu.Size = new System.Drawing.Size(159, 22);
|
||||
this.SaveRAMSubMenu.Text = "Save &RAM";
|
||||
this.SaveRAMSubMenu.DropDownOpened += new System.EventHandler(this.SaveRAMSubMenu_DropDownOpened);
|
||||
//
|
||||
// FlushSaveRAMMenuItem
|
||||
//
|
||||
this.FlushSaveRAMMenuItem.Name = "FlushSaveRAMMenuItem";
|
||||
this.FlushSaveRAMMenuItem.Size = new System.Drawing.Size(156, 22);
|
||||
this.FlushSaveRAMMenuItem.Text = "&Flush Save Ram";
|
||||
this.FlushSaveRAMMenuItem.Click += new System.EventHandler(this.FlushSaveRAMMenuItem_Click);
|
||||
// toolStripMenuItem2
|
||||
//
|
||||
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
|
||||
//
|
||||
// SaveRAMSubMenu
|
||||
//
|
||||
this.SaveRAMSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.FlushSaveRAMMenuItem});
|
||||
this.SaveRAMSubMenu.Name = "SaveRAMSubMenu";
|
||||
this.SaveRAMSubMenu.Size = new System.Drawing.Size(159, 22);
|
||||
this.SaveRAMSubMenu.Text = "Save &RAM";
|
||||
this.SaveRAMSubMenu.DropDownOpened += new System.EventHandler(this.SaveRAMSubMenu_DropDownOpened);
|
||||
//
|
||||
// FlushSaveRAMMenuItem
|
||||
//
|
||||
this.FlushSaveRAMMenuItem.Name = "FlushSaveRAMMenuItem";
|
||||
this.FlushSaveRAMMenuItem.Size = new System.Drawing.Size(156, 22);
|
||||
this.FlushSaveRAMMenuItem.Text = "&Flush Save Ram";
|
||||
this.FlushSaveRAMMenuItem.Click += new System.EventHandler(this.FlushSaveRAMMenuItem_Click);
|
||||
//
|
||||
// toolStripMenuItem2
|
||||
//
|
||||
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
|
||||
this.toolStripMenuItem2.Size = new System.Drawing.Size(156, 6);
|
||||
//
|
||||
// MovieSubMenu
|
||||
|
@ -1126,7 +1131,7 @@
|
|||
//
|
||||
this.RecordAVMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.RecordHS;
|
||||
this.RecordAVMenuItem.Name = "RecordAVMenuItem";
|
||||
this.RecordAVMenuItem.Size = new System.Drawing.Size(223, 22);
|
||||
this.RecordAVMenuItem.Size = new System.Drawing.Size(225, 22);
|
||||
this.RecordAVMenuItem.Text = "&Record AVI/WAV";
|
||||
this.RecordAVMenuItem.Click += new System.EventHandler(this.RecordAVMenuItem_Click);
|
||||
//
|
||||
|
@ -1134,7 +1139,7 @@
|
|||
//
|
||||
this.ConfigAndRecordAVMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.AVI;
|
||||
this.ConfigAndRecordAVMenuItem.Name = "ConfigAndRecordAVMenuItem";
|
||||
this.ConfigAndRecordAVMenuItem.Size = new System.Drawing.Size(223, 22);
|
||||
this.ConfigAndRecordAVMenuItem.Size = new System.Drawing.Size(225, 22);
|
||||
this.ConfigAndRecordAVMenuItem.Text = "Config and Record AVI/WAV";
|
||||
this.ConfigAndRecordAVMenuItem.Click += new System.EventHandler(this.ConfigAndRecordAVMenuItem_Click);
|
||||
//
|
||||
|
@ -1142,26 +1147,26 @@
|
|||
//
|
||||
this.StopAVIMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.Stop;
|
||||
this.StopAVIMenuItem.Name = "StopAVIMenuItem";
|
||||
this.StopAVIMenuItem.Size = new System.Drawing.Size(223, 22);
|
||||
this.StopAVIMenuItem.Size = new System.Drawing.Size(225, 22);
|
||||
this.StopAVIMenuItem.Text = "&Stop AVI/WAV";
|
||||
this.StopAVIMenuItem.Click += new System.EventHandler(this.StopAVMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator19
|
||||
//
|
||||
this.toolStripSeparator19.Name = "toolStripSeparator19";
|
||||
this.toolStripSeparator19.Size = new System.Drawing.Size(220, 6);
|
||||
this.toolStripSeparator19.Size = new System.Drawing.Size(222, 6);
|
||||
//
|
||||
// CaptureOSDMenuItem
|
||||
//
|
||||
this.CaptureOSDMenuItem.Name = "CaptureOSDMenuItem";
|
||||
this.CaptureOSDMenuItem.Size = new System.Drawing.Size(223, 22);
|
||||
this.CaptureOSDMenuItem.Size = new System.Drawing.Size(225, 22);
|
||||
this.CaptureOSDMenuItem.Text = "Capture OSD";
|
||||
this.CaptureOSDMenuItem.Click += new System.EventHandler(this.CaptureOSDMenuItem_Click);
|
||||
//
|
||||
// SynclessRecordingMenuItem
|
||||
//
|
||||
this.SynclessRecordingMenuItem.Name = "SynclessRecordingMenuItem";
|
||||
this.SynclessRecordingMenuItem.Size = new System.Drawing.Size(223, 22);
|
||||
this.SynclessRecordingMenuItem.Size = new System.Drawing.Size(225, 22);
|
||||
this.SynclessRecordingMenuItem.Text = "S&yncless Recording Tools";
|
||||
this.SynclessRecordingMenuItem.Click += new System.EventHandler(this.SynclessRecordingMenuItem_Click);
|
||||
//
|
||||
|
@ -1816,8 +1821,8 @@
|
|||
this.CoreSNESSubMenu,
|
||||
this.GbaCoreSubMenu,
|
||||
this.SGBCoreSubmenu,
|
||||
this.GBCoreSubmenu,
|
||||
this.GBInSGBMenuItem,
|
||||
this.GBCoreSubmenu,
|
||||
this.GBInSGBMenuItem,
|
||||
this.toolStripMenuItem16,
|
||||
this.allowGameDBCoreOverridesToolStripMenuItem,
|
||||
this.toolStripSeparator8,
|
||||
|
@ -1900,12 +1905,6 @@
|
|||
this.MgbaCoreMenuItem.Text = "mGBA";
|
||||
this.MgbaCoreMenuItem.Click += new System.EventHandler(this.GbaCorePick_Click);
|
||||
//
|
||||
// Atari7800HawkCoreMenuItem
|
||||
//
|
||||
this.Atari7800HawkCoreMenuItem.Name = "Atari7800HawkCoreMenuItem";
|
||||
this.Atari7800HawkCoreMenuItem.Size = new System.Drawing.Size(153, 22);
|
||||
this.Atari7800HawkCoreMenuItem.Text = "Atari7800Hawk";
|
||||
//
|
||||
// SGBCoreSubmenu
|
||||
//
|
||||
this.SGBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
|
@ -1915,48 +1914,48 @@
|
|||
this.SGBCoreSubmenu.Size = new System.Drawing.Size(239, 22);
|
||||
this.SGBCoreSubmenu.Text = "SGB";
|
||||
this.SGBCoreSubmenu.DropDownOpened += new System.EventHandler(this.SGBCoreSubmenu_DropDownOpened);
|
||||
//
|
||||
// GBCoreSubmenu
|
||||
//
|
||||
this.GBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.GBGambatteMenuItem,
|
||||
this.GBGBHawkMenuItem});
|
||||
this.GBCoreSubmenu.Name = "GBCoreSubmenu";
|
||||
this.GBCoreSubmenu.Size = new System.Drawing.Size(239, 22);
|
||||
this.GBCoreSubmenu.Text = "GB";
|
||||
this.GBCoreSubmenu.DropDownOpened += new System.EventHandler(this.GBCoreSubmenu_DropDownOpened);
|
||||
//
|
||||
// SgbBsnesMenuItem
|
||||
//
|
||||
this.SgbBsnesMenuItem.Name = "SgbBsnesMenuItem";
|
||||
this.SgbBsnesMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
//
|
||||
// SgbBsnesMenuItem
|
||||
//
|
||||
this.SgbBsnesMenuItem.Name = "SgbBsnesMenuItem";
|
||||
this.SgbBsnesMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.SgbBsnesMenuItem.Text = "BSNES";
|
||||
this.SgbBsnesMenuItem.Click += new System.EventHandler(this.SgbCorePick_Click);
|
||||
//
|
||||
// SgbSameBoyMenuItem
|
||||
//
|
||||
this.SgbSameBoyMenuItem.Name = "SgbSameBoyMenuItem";
|
||||
this.SgbSameBoyMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.SgbSameBoyMenuItem.Size = new System.Drawing.Size(123, 22);
|
||||
this.SgbSameBoyMenuItem.Text = "SameBoy";
|
||||
this.SgbSameBoyMenuItem.Click += new System.EventHandler(this.SgbCorePick_Click);
|
||||
//
|
||||
// GBGambatteMenuItem
|
||||
//
|
||||
this.GBGambatteMenuItem.Name = "GBGambatteMenuItem";
|
||||
this.GBGambatteMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.GBGambatteMenuItem.Text = "Gambatte";
|
||||
this.GBGambatteMenuItem.Click += new System.EventHandler(this.GBCorePick_Click);
|
||||
//
|
||||
// GBGBHawkMenuItem
|
||||
//
|
||||
this.GBGBHawkMenuItem.Name = "GBGBHawkMenuItem";
|
||||
this.GBGBHawkMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.GBGBHawkMenuItem.Text = "GBHawk";
|
||||
this.GBGBHawkMenuItem.Click += new System.EventHandler(this.GBCorePick_Click);
|
||||
//
|
||||
// GBInSGBMenuItem
|
||||
//
|
||||
this.GBInSGBMenuItem.Name = "GBInSGBMenuItem";
|
||||
//
|
||||
// GBCoreSubmenu
|
||||
//
|
||||
this.GBCoreSubmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.GBGambatteMenuItem,
|
||||
this.GBGBHawkMenuItem});
|
||||
this.GBCoreSubmenu.Name = "GBCoreSubmenu";
|
||||
this.GBCoreSubmenu.Size = new System.Drawing.Size(239, 22);
|
||||
this.GBCoreSubmenu.Text = "GB";
|
||||
this.GBCoreSubmenu.DropDownOpened += new System.EventHandler(this.GBCoreSubmenu_DropDownOpened);
|
||||
//
|
||||
// GBGambatteMenuItem
|
||||
//
|
||||
this.GBGambatteMenuItem.Name = "GBGambatteMenuItem";
|
||||
this.GBGambatteMenuItem.Size = new System.Drawing.Size(126, 22);
|
||||
this.GBGambatteMenuItem.Text = "Gambatte";
|
||||
this.GBGambatteMenuItem.Click += new System.EventHandler(this.GBCorePick_Click);
|
||||
//
|
||||
// GBGBHawkMenuItem
|
||||
//
|
||||
this.GBGBHawkMenuItem.Name = "GBGBHawkMenuItem";
|
||||
this.GBGBHawkMenuItem.Size = new System.Drawing.Size(126, 22);
|
||||
this.GBGBHawkMenuItem.Text = "GBHawk";
|
||||
this.GBGBHawkMenuItem.Click += new System.EventHandler(this.GBCorePick_Click);
|
||||
//
|
||||
// GBInSGBMenuItem
|
||||
//
|
||||
this.GBInSGBMenuItem.Name = "GBInSGBMenuItem";
|
||||
this.GBInSGBMenuItem.Size = new System.Drawing.Size(239, 22);
|
||||
this.GBInSGBMenuItem.Text = "GB in SGB";
|
||||
this.GBInSGBMenuItem.Click += new System.EventHandler(this.GbInSgbMenuItem_Click);
|
||||
|
@ -2053,7 +2052,7 @@
|
|||
this.batchRunnerToolStripMenuItem,
|
||||
this.ExperimentalToolsSubMenu});
|
||||
this.ToolsSubMenu.Name = "ToolsSubMenu";
|
||||
this.ToolsSubMenu.Size = new System.Drawing.Size(47, 19);
|
||||
this.ToolsSubMenu.Size = new System.Drawing.Size(48, 19);
|
||||
this.ToolsSubMenu.Text = "&Tools";
|
||||
this.ToolsSubMenu.DropDownOpened += new System.EventHandler(this.ToolsSubMenu_DropDownOpened);
|
||||
//
|
||||
|
@ -2442,7 +2441,7 @@
|
|||
//
|
||||
this.PceControllerSettingsMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.GameController;
|
||||
this.PceControllerSettingsMenuItem.Name = "PceControllerSettingsMenuItem";
|
||||
this.PceControllerSettingsMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PceControllerSettingsMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PceControllerSettingsMenuItem.Text = "Controller Settings";
|
||||
this.PceControllerSettingsMenuItem.Click += new System.EventHandler(this.PceControllerSettingsMenuItem_Click);
|
||||
//
|
||||
|
@ -2450,59 +2449,59 @@
|
|||
//
|
||||
this.PCEGraphicsSettingsMenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.tvIcon;
|
||||
this.PCEGraphicsSettingsMenuItem.Name = "PCEGraphicsSettingsMenuItem";
|
||||
this.PCEGraphicsSettingsMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PCEGraphicsSettingsMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PCEGraphicsSettingsMenuItem.Text = "Graphics Settings";
|
||||
this.PCEGraphicsSettingsMenuItem.Click += new System.EventHandler(this.PceGraphicsSettingsMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator32
|
||||
//
|
||||
this.toolStripSeparator32.Name = "toolStripSeparator32";
|
||||
this.toolStripSeparator32.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator32.Size = new System.Drawing.Size(256, 6);
|
||||
//
|
||||
// PCEBGViewerMenuItem
|
||||
//
|
||||
this.PCEBGViewerMenuItem.Name = "PCEBGViewerMenuItem";
|
||||
this.PCEBGViewerMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PCEBGViewerMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PCEBGViewerMenuItem.Text = "&BG Viewer";
|
||||
this.PCEBGViewerMenuItem.Click += new System.EventHandler(this.PceBgViewerMenuItem_Click);
|
||||
//
|
||||
// PCEtileViewerToolStripMenuItem
|
||||
//
|
||||
this.PCEtileViewerToolStripMenuItem.Name = "PCEtileViewerToolStripMenuItem";
|
||||
this.PCEtileViewerToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PCEtileViewerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PCEtileViewerToolStripMenuItem.Text = "&Tile Viewer";
|
||||
this.PCEtileViewerToolStripMenuItem.Click += new System.EventHandler(this.PceTileViewerMenuItem_Click);
|
||||
//
|
||||
// PceSoundDebuggerToolStripMenuItem
|
||||
//
|
||||
this.PceSoundDebuggerToolStripMenuItem.Name = "PceSoundDebuggerToolStripMenuItem";
|
||||
this.PceSoundDebuggerToolStripMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PceSoundDebuggerToolStripMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PceSoundDebuggerToolStripMenuItem.Text = "&Sound Debugger";
|
||||
this.PceSoundDebuggerToolStripMenuItem.Click += new System.EventHandler(this.PceSoundDebuggerMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator25
|
||||
//
|
||||
this.toolStripSeparator25.Name = "toolStripSeparator25";
|
||||
this.toolStripSeparator25.Size = new System.Drawing.Size(255, 6);
|
||||
this.toolStripSeparator25.Size = new System.Drawing.Size(256, 6);
|
||||
//
|
||||
// PCEAlwaysPerformSpriteLimitMenuItem
|
||||
//
|
||||
this.PCEAlwaysPerformSpriteLimitMenuItem.Name = "PCEAlwaysPerformSpriteLimitMenuItem";
|
||||
this.PCEAlwaysPerformSpriteLimitMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PCEAlwaysPerformSpriteLimitMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PCEAlwaysPerformSpriteLimitMenuItem.Text = "Always Perform Sprite Limit";
|
||||
this.PCEAlwaysPerformSpriteLimitMenuItem.Click += new System.EventHandler(this.PCEAlwaysPerformSpriteLimitMenuItem_Click);
|
||||
//
|
||||
// PCEAlwaysEqualizeVolumesMenuItem
|
||||
//
|
||||
this.PCEAlwaysEqualizeVolumesMenuItem.Name = "PCEAlwaysEqualizeVolumesMenuItem";
|
||||
this.PCEAlwaysEqualizeVolumesMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PCEAlwaysEqualizeVolumesMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PCEAlwaysEqualizeVolumesMenuItem.Text = "Always Equalize Volumes (PCE-CD)";
|
||||
this.PCEAlwaysEqualizeVolumesMenuItem.Click += new System.EventHandler(this.PCEAlwaysEqualizeVolumesMenuItem_Click);
|
||||
//
|
||||
// PCEArcadeCardRewindEnableMenuItem
|
||||
//
|
||||
this.PCEArcadeCardRewindEnableMenuItem.Name = "PCEArcadeCardRewindEnableMenuItem";
|
||||
this.PCEArcadeCardRewindEnableMenuItem.Size = new System.Drawing.Size(258, 22);
|
||||
this.PCEArcadeCardRewindEnableMenuItem.Size = new System.Drawing.Size(259, 22);
|
||||
this.PCEArcadeCardRewindEnableMenuItem.Text = "Arcade Card Rewind-Enable Hack";
|
||||
this.PCEArcadeCardRewindEnableMenuItem.Click += new System.EventHandler(this.PCEArcadeCardRewindEnableMenuItem_Click);
|
||||
//
|
||||
|
@ -2512,7 +2511,7 @@
|
|||
this.SMSregionToolStripMenuItem,
|
||||
this.SMSdisplayToolStripMenuItem,
|
||||
this.SMSControllerToolStripMenuItem,
|
||||
this.SMStoolStripMenuItem2,
|
||||
this.SMStoolStripMenuItem2,
|
||||
this.SMSenableBIOSToolStripMenuItem,
|
||||
this.SMSEnableFMChipMenuItem,
|
||||
this.SMSOverclockMenuItem,
|
||||
|
@ -2539,7 +2538,7 @@
|
|||
this.SMSregionKoreaToolStripMenuItem,
|
||||
this.SMSregionAutoToolStripMenuItem});
|
||||
this.SMSregionToolStripMenuItem.Name = "SMSregionToolStripMenuItem";
|
||||
this.SMSregionToolStripMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSregionToolStripMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSregionToolStripMenuItem.Text = "Region";
|
||||
//
|
||||
// SMSregionExportToolStripMenuItem
|
||||
|
@ -2577,7 +2576,7 @@
|
|||
this.SMSdisplayPalToolStripMenuItem,
|
||||
this.SMSdisplayAutoToolStripMenuItem});
|
||||
this.SMSdisplayToolStripMenuItem.Name = "SMSdisplayToolStripMenuItem";
|
||||
this.SMSdisplayToolStripMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSdisplayToolStripMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSdisplayToolStripMenuItem.Text = "Display Type";
|
||||
//
|
||||
// SMSdisplayNtscToolStripMenuItem
|
||||
|
@ -2587,51 +2586,9 @@
|
|||
this.SMSdisplayNtscToolStripMenuItem.Text = "NTSC";
|
||||
this.SMSdisplayNtscToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayNTSC_Click);
|
||||
//
|
||||
// SMSControllerToolStripMenuItem
|
||||
// SMSdisplayPalToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerToolStripMenuItem.Name = "SMSControllerToolStripMenuItem";
|
||||
this.SMSControllerToolStripMenuItem.Text = "&Controller Type";
|
||||
this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.SMSControllerStandardToolStripMenuItem,
|
||||
this.SMSControllerPaddleToolStripMenuItem,
|
||||
this.SMSControllerLightPhaserToolStripMenuItem,
|
||||
this.SMSControllerSportsPadToolStripMenuItem,
|
||||
this.SMSControllerKeyboardToolStripMenuItem});
|
||||
//
|
||||
// SMSControllerStandardToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerStandardToolStripMenuItem.Name = "SMSControllerStandardToolStripMenuItem";
|
||||
this.SMSControllerStandardToolStripMenuItem.Text = "Standard";
|
||||
this.SMSControllerStandardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerStandardToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerPaddleToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerPaddleToolStripMenuItem.Name = "SMSControllerPaddleToolStripMenuItem";
|
||||
this.SMSControllerPaddleToolStripMenuItem.Text = "Paddle";
|
||||
this.SMSControllerPaddleToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerPaddleToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerLightPhaserToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Name = "SMSControllerLightPhaserToolStripMenuItem";
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Text = "Light Phaser";
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerLightPhaserToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerSportsPadToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Name = "SMSControllerSportsPadToolStripMenuItem";
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Text = "Sports Pad";
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerSportsPadToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerKeyboardToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Name = "SMSControllerKeyboardToolStripMenuItem";
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Text = "Keyboard";
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerKeyboardToolStripMenuItem_Click);
|
||||
|
||||
//
|
||||
// SMSdisplayPalToolStripMenuItem
|
||||
//
|
||||
this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem";
|
||||
this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem";
|
||||
this.SMSdisplayPalToolStripMenuItem.Size = new System.Drawing.Size(104, 22);
|
||||
this.SMSdisplayPalToolStripMenuItem.Text = "PAL";
|
||||
this.SMSdisplayPalToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayPAL_Click);
|
||||
|
@ -2643,97 +2600,144 @@
|
|||
this.SMSdisplayAutoToolStripMenuItem.Text = "Auto";
|
||||
this.SMSdisplayAutoToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayAuto_Click);
|
||||
//
|
||||
// SMSControllerToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.SMSControllerStandardToolStripMenuItem,
|
||||
this.SMSControllerPaddleToolStripMenuItem,
|
||||
this.SMSControllerLightPhaserToolStripMenuItem,
|
||||
this.SMSControllerSportsPadToolStripMenuItem,
|
||||
this.SMSControllerKeyboardToolStripMenuItem});
|
||||
this.SMSControllerToolStripMenuItem.Name = "SMSControllerToolStripMenuItem";
|
||||
this.SMSControllerToolStripMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSControllerToolStripMenuItem.Text = "&Controller Type";
|
||||
//
|
||||
// SMSControllerStandardToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerStandardToolStripMenuItem.Name = "SMSControllerStandardToolStripMenuItem";
|
||||
this.SMSControllerStandardToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
|
||||
this.SMSControllerStandardToolStripMenuItem.Text = "Standard";
|
||||
this.SMSControllerStandardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerStandardToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerPaddleToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerPaddleToolStripMenuItem.Name = "SMSControllerPaddleToolStripMenuItem";
|
||||
this.SMSControllerPaddleToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
|
||||
this.SMSControllerPaddleToolStripMenuItem.Text = "Paddle";
|
||||
this.SMSControllerPaddleToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerPaddleToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerLightPhaserToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Name = "SMSControllerLightPhaserToolStripMenuItem";
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Text = "Light Phaser";
|
||||
this.SMSControllerLightPhaserToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerLightPhaserToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerSportsPadToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Name = "SMSControllerSportsPadToolStripMenuItem";
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Text = "Sports Pad";
|
||||
this.SMSControllerSportsPadToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerSportsPadToolStripMenuItem_Click);
|
||||
//
|
||||
// SMSControllerKeyboardToolStripMenuItem
|
||||
//
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Name = "SMSControllerKeyboardToolStripMenuItem";
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Text = "Keyboard";
|
||||
this.SMSControllerKeyboardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerKeyboardToolStripMenuItem_Click);
|
||||
//
|
||||
// SMStoolStripMenuItem2
|
||||
//
|
||||
this.SMStoolStripMenuItem2.Name = "SMStoolStripMenuItem2";
|
||||
this.SMStoolStripMenuItem2.Size = new System.Drawing.Size(274, 6);
|
||||
this.SMStoolStripMenuItem2.Size = new System.Drawing.Size(275, 6);
|
||||
//
|
||||
// SMSenableBIOSToolStripMenuItem
|
||||
//
|
||||
this.SMSenableBIOSToolStripMenuItem.Name = "SMSenableBIOSToolStripMenuItem";
|
||||
this.SMSenableBIOSToolStripMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSenableBIOSToolStripMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSenableBIOSToolStripMenuItem.Text = "Enable BIOS (Must be Enabled for TAS)";
|
||||
this.SMSenableBIOSToolStripMenuItem.Click += new System.EventHandler(this.SmsBiosMenuItem_Click);
|
||||
//
|
||||
// SMSEnableFMChipMenuItem
|
||||
//
|
||||
this.SMSEnableFMChipMenuItem.Name = "SMSEnableFMChipMenuItem";
|
||||
this.SMSEnableFMChipMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSEnableFMChipMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSEnableFMChipMenuItem.Text = "&Enable FM Chip";
|
||||
this.SMSEnableFMChipMenuItem.Click += new System.EventHandler(this.SmsEnableFmChipMenuItem_Click);
|
||||
//
|
||||
// SMSOverclockMenuItem
|
||||
//
|
||||
this.SMSOverclockMenuItem.Name = "SMSOverclockMenuItem";
|
||||
this.SMSOverclockMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSOverclockMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSOverclockMenuItem.Text = "&Overclock when Known Safe";
|
||||
this.SMSOverclockMenuItem.Click += new System.EventHandler(this.SMSOverclockMenuItem_Click);
|
||||
//
|
||||
// SMSForceStereoMenuItem
|
||||
//
|
||||
this.SMSForceStereoMenuItem.Name = "SMSForceStereoMenuItem";
|
||||
this.SMSForceStereoMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSForceStereoMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSForceStereoMenuItem.Text = "&Force Stereo Separation";
|
||||
this.SMSForceStereoMenuItem.Click += new System.EventHandler(this.SMSForceStereoMenuItem_Click);
|
||||
//
|
||||
// SMSSpriteLimitMenuItem
|
||||
//
|
||||
this.SMSSpriteLimitMenuItem.Name = "SMSSpriteLimitMenuItem";
|
||||
this.SMSSpriteLimitMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSSpriteLimitMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSSpriteLimitMenuItem.Text = "Sprite &Limit";
|
||||
this.SMSSpriteLimitMenuItem.Click += new System.EventHandler(this.SMSSpriteLimitMenuItem_Click);
|
||||
//
|
||||
// SMSDisplayOverscanMenuItem
|
||||
//
|
||||
this.SMSDisplayOverscanMenuItem.Name = "SMSDisplayOverscanMenuItem";
|
||||
this.SMSDisplayOverscanMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSDisplayOverscanMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSDisplayOverscanMenuItem.Text = "Display Overscan";
|
||||
this.SMSDisplayOverscanMenuItem.Click += new System.EventHandler(this.SMSDisplayOverscanMenuItem_Click);
|
||||
//
|
||||
// SMSFix3DGameDisplayToolStripMenuItem
|
||||
//
|
||||
this.SMSFix3DGameDisplayToolStripMenuItem.Name = "SMSFix3DGameDisplayToolStripMenuItem";
|
||||
this.SMSFix3DGameDisplayToolStripMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSFix3DGameDisplayToolStripMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSFix3DGameDisplayToolStripMenuItem.Text = "Fix 3D Game Display";
|
||||
this.SMSFix3DGameDisplayToolStripMenuItem.Click += new System.EventHandler(this.SMSFix3DDisplayMenuItem_Click);
|
||||
//
|
||||
// ShowClippedRegionsMenuItem
|
||||
//
|
||||
this.ShowClippedRegionsMenuItem.Name = "ShowClippedRegionsMenuItem";
|
||||
this.ShowClippedRegionsMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.ShowClippedRegionsMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.ShowClippedRegionsMenuItem.Text = "&Show Clipped Regions";
|
||||
this.ShowClippedRegionsMenuItem.Click += new System.EventHandler(this.ShowClippedRegionsMenuItem_Click);
|
||||
//
|
||||
// HighlightActiveDisplayRegionMenuItem
|
||||
//
|
||||
this.HighlightActiveDisplayRegionMenuItem.Name = "HighlightActiveDisplayRegionMenuItem";
|
||||
this.HighlightActiveDisplayRegionMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.HighlightActiveDisplayRegionMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.HighlightActiveDisplayRegionMenuItem.Text = "&Highlight Active Display Region";
|
||||
this.HighlightActiveDisplayRegionMenuItem.Click += new System.EventHandler(this.HighlightActiveDisplayRegionMenuItem_Click);
|
||||
//
|
||||
// SMSGraphicsSettingsMenuItem
|
||||
//
|
||||
this.SMSGraphicsSettingsMenuItem.Name = "SMSGraphicsSettingsMenuItem";
|
||||
this.SMSGraphicsSettingsMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSGraphicsSettingsMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSGraphicsSettingsMenuItem.Text = "&Graphics Settings...";
|
||||
this.SMSGraphicsSettingsMenuItem.Click += new System.EventHandler(this.SMSGraphicsSettingsMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator24
|
||||
//
|
||||
this.toolStripSeparator24.Name = "toolStripSeparator24";
|
||||
this.toolStripSeparator24.Size = new System.Drawing.Size(274, 6);
|
||||
this.toolStripSeparator24.Size = new System.Drawing.Size(275, 6);
|
||||
//
|
||||
// SMSVDPViewerToolStripMenuItem
|
||||
//
|
||||
this.SMSVDPViewerToolStripMenuItem.Name = "SMSVDPViewerToolStripMenuItem";
|
||||
this.SMSVDPViewerToolStripMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.SMSVDPViewerToolStripMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.SMSVDPViewerToolStripMenuItem.Text = "&VDP Viewer";
|
||||
this.SMSVDPViewerToolStripMenuItem.Click += new System.EventHandler(this.SmsVdpViewerMenuItem_Click);
|
||||
//
|
||||
// GGGameGenieMenuItem
|
||||
//
|
||||
this.GGGameGenieMenuItem.Name = "GGGameGenieMenuItem";
|
||||
this.GGGameGenieMenuItem.Size = new System.Drawing.Size(277, 22);
|
||||
this.GGGameGenieMenuItem.Size = new System.Drawing.Size(278, 22);
|
||||
this.GGGameGenieMenuItem.Text = "&Game Genie Encoder/Decoder";
|
||||
this.GGGameGenieMenuItem.Click += new System.EventHandler(this.GGGameGenieMenuItem_Click);
|
||||
//
|
||||
|
@ -2805,7 +2809,7 @@
|
|||
//
|
||||
this.A7800SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.A7800ControllerSettingsMenuItem,
|
||||
this.A7800FilterSettingsMenuItem});
|
||||
this.A7800FilterSettingsMenuItem});
|
||||
this.A7800SubMenu.Name = "A7800SubMenu";
|
||||
this.A7800SubMenu.Size = new System.Drawing.Size(51, 19);
|
||||
this.A7800SubMenu.Text = "&A7800";
|
||||
|
@ -2814,26 +2818,26 @@
|
|||
// A7800ControllerSettingsMenuItem
|
||||
//
|
||||
this.A7800ControllerSettingsMenuItem.Name = "A7800ControllerSettingsMenuItem";
|
||||
this.A7800ControllerSettingsMenuItem.Size = new System.Drawing.Size(125, 22);
|
||||
this.A7800ControllerSettingsMenuItem.Size = new System.Drawing.Size(172, 22);
|
||||
this.A7800ControllerSettingsMenuItem.Text = "Controller Settings";
|
||||
this.A7800ControllerSettingsMenuItem.Click += new System.EventHandler(this.A7800ControllerSettingsToolStripMenuItem_Click);
|
||||
//
|
||||
// A7800FilterSettingsMenuItem
|
||||
//
|
||||
this.A7800FilterSettingsMenuItem.Name = "A7800FilterSettingsMenuItem";
|
||||
this.A7800FilterSettingsMenuItem.Size = new System.Drawing.Size(125, 22);
|
||||
this.A7800FilterSettingsMenuItem.Text = "Filter Settings";
|
||||
this.A7800FilterSettingsMenuItem.Click += new System.EventHandler(this.A7800FilterSettingsToolStripMenuItem_Click);
|
||||
//
|
||||
// GBSubMenu
|
||||
//
|
||||
this.GBSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
//
|
||||
// A7800FilterSettingsMenuItem
|
||||
//
|
||||
this.A7800FilterSettingsMenuItem.Name = "A7800FilterSettingsMenuItem";
|
||||
this.A7800FilterSettingsMenuItem.Size = new System.Drawing.Size(172, 22);
|
||||
this.A7800FilterSettingsMenuItem.Text = "Filter Settings";
|
||||
this.A7800FilterSettingsMenuItem.Click += new System.EventHandler(this.A7800FilterSettingsToolStripMenuItem_Click);
|
||||
//
|
||||
// GBSubMenu
|
||||
//
|
||||
this.GBSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.GBcoreSettingsToolStripMenuItem,
|
||||
this.LoadGBInSGBMenuItem,
|
||||
this.toolStripSeparator28,
|
||||
this.GBGPUViewerMenuItem,
|
||||
this.GBGameGenieMenuItem,
|
||||
this.GBPrinterViewerMenuItem});
|
||||
this.GBPrinterViewerMenuItem});
|
||||
this.GBSubMenu.Name = "GBSubMenu";
|
||||
this.GBSubMenu.Size = new System.Drawing.Size(34, 19);
|
||||
this.GBSubMenu.Text = "&GB";
|
||||
|
@ -2871,17 +2875,17 @@
|
|||
this.GBGameGenieMenuItem.Size = new System.Drawing.Size(233, 22);
|
||||
this.GBGameGenieMenuItem.Text = "&Game Genie Encoder/Decoder";
|
||||
this.GBGameGenieMenuItem.Click += new System.EventHandler(this.GBGameGenieMenuItem_Click);
|
||||
//
|
||||
// GBPrinterViewerMenuItem
|
||||
//
|
||||
this.GBPrinterViewerMenuItem.Name = "GBPrinterViewerMenuItem";
|
||||
this.GBPrinterViewerMenuItem.Size = new System.Drawing.Size(233, 22);
|
||||
this.GBPrinterViewerMenuItem.Text = "&Printer Viewer";
|
||||
this.GBPrinterViewerMenuItem.Click += new System.EventHandler(this.GBPrinterViewerMenuItem_Click);
|
||||
//
|
||||
// GBASubMenu
|
||||
//
|
||||
this.GBASubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
//
|
||||
// GBPrinterViewerMenuItem
|
||||
//
|
||||
this.GBPrinterViewerMenuItem.Name = "GBPrinterViewerMenuItem";
|
||||
this.GBPrinterViewerMenuItem.Size = new System.Drawing.Size(233, 22);
|
||||
this.GBPrinterViewerMenuItem.Text = "&Printer Viewer";
|
||||
this.GBPrinterViewerMenuItem.Click += new System.EventHandler(this.GBPrinterViewerMenuItem_Click);
|
||||
//
|
||||
// GBASubMenu
|
||||
//
|
||||
this.GBASubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.GBACoreSelectionSubMenu,
|
||||
this.GBAcoresettingsToolStripMenuItem1,
|
||||
this.toolStripSeparator33,
|
||||
|
@ -3390,6 +3394,44 @@
|
|||
this.AboutMenuItem.Text = "&About";
|
||||
this.AboutMenuItem.Click += new System.EventHandler(this.AboutMenuItem_Click);
|
||||
//
|
||||
// zXSpectrumToolStripMenuItem
|
||||
//
|
||||
this.zXSpectrumToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ZXSpectrumCoreEmulationSettingsMenuItem,
|
||||
this.ZXSpectrumControllerConfigurationMenuItem,
|
||||
this.ZXSpectrumNonSyncSettingsMenuItem});
|
||||
this.zXSpectrumToolStripMenuItem.Name = "zXSpectrumToolStripMenuItem";
|
||||
this.zXSpectrumToolStripMenuItem.Size = new System.Drawing.Size(87, 19);
|
||||
this.zXSpectrumToolStripMenuItem.Text = "ZX Spectrum";
|
||||
this.zXSpectrumToolStripMenuItem.DropDownOpened += new System.EventHandler(this.zXSpectrumToolStripMenuItem_DropDownOpened);
|
||||
//
|
||||
// ZXSpectrumCoreEmulationSettingsMenuItem
|
||||
//
|
||||
this.ZXSpectrumCoreEmulationSettingsMenuItem.Name = "ZXSpectrumCoreEmulationSettingsMenuItem";
|
||||
this.ZXSpectrumCoreEmulationSettingsMenuItem.Size = new System.Drawing.Size(201, 22);
|
||||
this.ZXSpectrumCoreEmulationSettingsMenuItem.Text = "Core Emulation Settings";
|
||||
this.ZXSpectrumCoreEmulationSettingsMenuItem.Click += new System.EventHandler(this.ZXSpectrumCoreEmulationSettingsMenuItem_Click);
|
||||
//
|
||||
// ZXSpectrumControllerConfigurationMenuItem
|
||||
//
|
||||
this.ZXSpectrumControllerConfigurationMenuItem.Name = "ZXSpectrumControllerConfigurationMenuItem";
|
||||
this.ZXSpectrumControllerConfigurationMenuItem.Size = new System.Drawing.Size(201, 22);
|
||||
this.ZXSpectrumControllerConfigurationMenuItem.Text = "Joystick Configuration";
|
||||
this.ZXSpectrumControllerConfigurationMenuItem.Click += new System.EventHandler(this.ZXSpectrumControllerConfigurationMenuItem_Click);
|
||||
//
|
||||
// ZXSpectrumNonSyncSettingsMenuItem
|
||||
//
|
||||
this.ZXSpectrumNonSyncSettingsMenuItem.Name = "ZXSpectrumNonSyncSettingsMenuItem";
|
||||
this.ZXSpectrumNonSyncSettingsMenuItem.Size = new System.Drawing.Size(201, 22);
|
||||
this.ZXSpectrumNonSyncSettingsMenuItem.Text = "Non-Sync Settings";
|
||||
this.ZXSpectrumNonSyncSettingsMenuItem.Click += new System.EventHandler(this.ZXSpectrumNonSyncSettingsMenuItem_Click);
|
||||
//
|
||||
// Atari7800HawkCoreMenuItem
|
||||
//
|
||||
this.Atari7800HawkCoreMenuItem.Name = "Atari7800HawkCoreMenuItem";
|
||||
this.Atari7800HawkCoreMenuItem.Size = new System.Drawing.Size(153, 22);
|
||||
this.Atari7800HawkCoreMenuItem.Text = "Atari7800Hawk";
|
||||
//
|
||||
// MainStatusBar
|
||||
//
|
||||
this.MainStatusBar.ClickThrough = true;
|
||||
|
@ -4474,5 +4516,9 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerSportsPadToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerKeyboardToolStripMenuItem;
|
||||
}
|
||||
private System.Windows.Forms.ToolStripMenuItem zXSpectrumToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ZXSpectrumControllerConfigurationMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ZXSpectrumCoreEmulationSettingsMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ZXSpectrumNonSyncSettingsMenuItem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2451,11 +2451,42 @@ namespace BizHawk.Client.EmuHawk
|
|||
new IntvControllerSettings().ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Help
|
||||
#region ZXSpectrum
|
||||
|
||||
private void HelpSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
private void zXSpectrumToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void preferencesToolStripMenuItem4_Click(object sender, EventArgs e)
|
||||
{
|
||||
GenericCoreConfig.DoDialog(this, "ZXSpectrum Settings");
|
||||
}
|
||||
|
||||
|
||||
private void ZXSpectrumControllerConfigurationMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new ZXSpectrumJoystickSettings().ShowDialog();
|
||||
}
|
||||
|
||||
private void ZXSpectrumCoreEmulationSettingsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new ZXSpectrumCoreEmulationSettings().ShowDialog();
|
||||
}
|
||||
|
||||
private void ZXSpectrumNonSyncSettingsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new ZXSpectrumNonSyncSettings().ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Help
|
||||
|
||||
private void HelpSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
FeaturesMenuItem.Visible = VersionInfo.DeveloperBuild;
|
||||
}
|
||||
|
|
|
@ -1719,6 +1719,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
sNESToolStripMenuItem.Visible = false;
|
||||
neoGeoPocketToolStripMenuItem.Visible = false;
|
||||
pCFXToolStripMenuItem.Visible = false;
|
||||
zXSpectrumToolStripMenuItem.Visible = false;
|
||||
|
||||
switch (system)
|
||||
{
|
||||
|
@ -1816,6 +1817,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
case "PCFX":
|
||||
pCFXToolStripMenuItem.Visible = true;
|
||||
break;
|
||||
case "ZXSpectrum":
|
||||
zXSpectrumToolStripMenuItem.Visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2077,7 +2081,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;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;%ARCH%",
|
||||
"Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;*.tzx;%ARCH%",
|
||||
"Music Files", "*.psf;*.minipsf;*.sid;*.nsf",
|
||||
"Disc Images", "*.cue;*.ccd;*.mds;*.m3u",
|
||||
"NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%",
|
||||
|
@ -2105,6 +2109,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
"Apple II", "*.dsk;*.do;*.po;%ARCH%",
|
||||
"Virtual Boy", "*.vb;%ARCH%",
|
||||
"Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%",
|
||||
"Sinclair ZX Spectrum", "*.tzx;*.tap;%ARCH%",
|
||||
"All Files", "*.*");
|
||||
}
|
||||
|
||||
|
@ -4294,7 +4299,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
GenericCoreConfig.DoDialog(this, "PC-FX Settings");
|
||||
}
|
||||
|
||||
private bool Rewind(ref bool runFrame, long currentTimestamp, out bool returnToRecording)
|
||||
private bool Rewind(ref bool runFrame, long currentTimestamp, out bool returnToRecording)
|
||||
{
|
||||
var isRewinding = false;
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ namespace BizHawk.Client.EmuHawk.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
@ -3438,5 +3438,15 @@ namespace BizHawk.Client.EmuHawk.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ZXSpectrumKeyboards {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ZXSpectrumKeyboards", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1557,4 +1557,7 @@
|
|||
<data name="NGPController" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\images\ControllerImages\NGPController.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ZXSpectrumKeyboards" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\config\controllerimages\zxspectrumkeyboards.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -172,15 +172,24 @@ namespace BizHawk.Client.EmuHawk
|
|||
string tabname = cat.Key;
|
||||
tt.TabPages.Add(tabname);
|
||||
tt.TabPages[pageidx].Controls.Add(createpanel(settings, cat.Value, tt.Size));
|
||||
}
|
||||
|
||||
// zxhawk hack - it uses multiple categoryLabels
|
||||
if (Global.Emulator.SystemId == "ZXSpectrum")
|
||||
pageidx++;
|
||||
|
||||
}
|
||||
|
||||
if (buckets[0].Count > 0)
|
||||
{
|
||||
string tabname = Global.Emulator.SystemId == "C64" ? "Keyboard" : "Console"; // hack
|
||||
tt.TabPages.Add(tabname);
|
||||
tt.TabPages[pageidx].Controls.Add(createpanel(settings, buckets[0], tt.Size));
|
||||
}
|
||||
}
|
||||
// ZXHawk needs to skip this bit
|
||||
if (Global.Emulator.SystemId == "ZXSpectrum")
|
||||
return;
|
||||
|
||||
string tabname = (Global.Emulator.SystemId == "C64") ? "Keyboard" : "Console"; // hack
|
||||
tt.TabPages.Add(tabname);
|
||||
tt.TabPages[pageidx].Controls.Add(createpanel(settings, buckets[0], tt.Size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ControllerConfig(ControllerDefinition def)
|
||||
|
@ -256,6 +265,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
pictureBox2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
|
||||
}
|
||||
|
||||
if (controlName == "ZXSpectrum Controller")
|
||||
{
|
||||
pictureBox1.Image = Properties.Resources.ZXSpectrumKeyboards;
|
||||
pictureBox1.Size = Properties.Resources.ZXSpectrumKeyboards.Size;
|
||||
tableLayoutPanel1.ColumnStyles[1].Width = Properties.Resources.ZXSpectrumKeyboards.Width;
|
||||
}
|
||||
}
|
||||
|
||||
// lazy methods, but they're not called often and actually
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 425 KiB |
|
@ -52,6 +52,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{ "GBC", "Game Boy Color" },
|
||||
{ "PCFX", "PC-FX" },
|
||||
{ "32X", "32X" },
|
||||
{ "ZXSpectrum", "ZX Spectrum" }
|
||||
};
|
||||
|
||||
public string TargetSystem = null;
|
||||
|
|
187
BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumCoreEmulationSettings.Designer.cs
generated
Normal file
187
BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumCoreEmulationSettings.Designer.cs
generated
Normal file
|
@ -0,0 +1,187 @@
|
|||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
partial class ZXSpectrumCoreEmulationSettings
|
||||
{
|
||||
/// <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(ZXSpectrumCoreEmulationSettings));
|
||||
this.OkBtn = new System.Windows.Forms.Button();
|
||||
this.CancelBtn = new System.Windows.Forms.Button();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.MachineSelectionComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.lblMachineNotes = new System.Windows.Forms.Label();
|
||||
this.determEmucheckBox1 = new System.Windows.Forms.CheckBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.borderTypecomboBox1 = new System.Windows.Forms.ComboBox();
|
||||
this.lblBorderInfo = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// 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(247, 393);
|
||||
this.OkBtn.Name = "OkBtn";
|
||||
this.OkBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.OkBtn.TabIndex = 3;
|
||||
this.OkBtn.Text = "&OK";
|
||||
this.OkBtn.UseVisualStyleBackColor = true;
|
||||
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
|
||||
//
|
||||
// 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(313, 393);
|
||||
this.CancelBtn.Name = "CancelBtn";
|
||||
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.CancelBtn.TabIndex = 4;
|
||||
this.CancelBtn.Text = "&Cancel";
|
||||
this.CancelBtn.UseVisualStyleBackColor = true;
|
||||
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(12, 46);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(98, 13);
|
||||
this.label4.TabIndex = 15;
|
||||
this.label4.Text = "Emulated Machine:";
|
||||
//
|
||||
// MachineSelectionComboBox
|
||||
//
|
||||
this.MachineSelectionComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.MachineSelectionComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.MachineSelectionComboBox.FormattingEnabled = true;
|
||||
this.MachineSelectionComboBox.Location = new System.Drawing.Point(12, 62);
|
||||
this.MachineSelectionComboBox.Name = "MachineSelectionComboBox";
|
||||
this.MachineSelectionComboBox.Size = new System.Drawing.Size(361, 21);
|
||||
this.MachineSelectionComboBox.TabIndex = 13;
|
||||
this.MachineSelectionComboBox.SelectionChangeCommitted += new System.EventHandler(this.MachineSelectionComboBox_SelectionChangeCommitted);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(12, 14);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(159, 13);
|
||||
this.label1.TabIndex = 17;
|
||||
this.label1.Text = "ZX Spectrum Emulation Settings";
|
||||
//
|
||||
// lblMachineNotes
|
||||
//
|
||||
this.lblMachineNotes.Font = new System.Drawing.Font("Lucida Console", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblMachineNotes.Location = new System.Drawing.Point(15, 95);
|
||||
this.lblMachineNotes.Name = "lblMachineNotes";
|
||||
this.lblMachineNotes.Size = new System.Drawing.Size(358, 204);
|
||||
this.lblMachineNotes.TabIndex = 20;
|
||||
this.lblMachineNotes.Text = "null\r\n";
|
||||
//
|
||||
// determEmucheckBox1
|
||||
//
|
||||
this.determEmucheckBox1.AutoSize = true;
|
||||
this.determEmucheckBox1.Location = new System.Drawing.Point(15, 302);
|
||||
this.determEmucheckBox1.Name = "determEmucheckBox1";
|
||||
this.determEmucheckBox1.Size = new System.Drawing.Size(135, 17);
|
||||
this.determEmucheckBox1.TabIndex = 21;
|
||||
this.determEmucheckBox1.Text = "Deterministic Emulation";
|
||||
this.determEmucheckBox1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(12, 335);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(118, 13);
|
||||
this.label2.TabIndex = 23;
|
||||
this.label2.Text = "Rendered Border Type:";
|
||||
//
|
||||
// borderTypecomboBox1
|
||||
//
|
||||
this.borderTypecomboBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.borderTypecomboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.borderTypecomboBox1.FormattingEnabled = true;
|
||||
this.borderTypecomboBox1.Location = new System.Drawing.Point(12, 351);
|
||||
this.borderTypecomboBox1.Name = "borderTypecomboBox1";
|
||||
this.borderTypecomboBox1.Size = new System.Drawing.Size(157, 21);
|
||||
this.borderTypecomboBox1.TabIndex = 22;
|
||||
this.borderTypecomboBox1.SelectedIndexChanged += new System.EventHandler(this.borderTypecomboBox1_SelectedIndexChanged);
|
||||
//
|
||||
// lblBorderInfo
|
||||
//
|
||||
this.lblBorderInfo.Font = new System.Drawing.Font("Lucida Console", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblBorderInfo.Location = new System.Drawing.Point(175, 351);
|
||||
this.lblBorderInfo.Name = "lblBorderInfo";
|
||||
this.lblBorderInfo.Size = new System.Drawing.Size(196, 21);
|
||||
this.lblBorderInfo.TabIndex = 24;
|
||||
this.lblBorderInfo.Text = "null";
|
||||
this.lblBorderInfo.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// ZXSpectrumCoreEmulationSettings
|
||||
//
|
||||
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(385, 428);
|
||||
this.Controls.Add(this.lblBorderInfo);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.borderTypecomboBox1);
|
||||
this.Controls.Add(this.determEmucheckBox1);
|
||||
this.Controls.Add(this.lblMachineNotes);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.MachineSelectionComboBox);
|
||||
this.Controls.Add(this.CancelBtn);
|
||||
this.Controls.Add(this.OkBtn);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "ZXSpectrumCoreEmulationSettings";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Core Emulation Settings";
|
||||
this.Load += new System.EventHandler(this.IntvControllerSettings_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button OkBtn;
|
||||
private System.Windows.Forms.Button CancelBtn;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.ComboBox MachineSelectionComboBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label lblMachineNotes;
|
||||
private System.Windows.Forms.CheckBox determEmucheckBox1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox borderTypecomboBox1;
|
||||
private System.Windows.Forms.Label lblBorderInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Cores.Computers.SinclairSpectrum;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class ZXSpectrumCoreEmulationSettings : Form
|
||||
{
|
||||
private ZXSpectrum.ZXSpectrumSyncSettings _syncSettings;
|
||||
|
||||
public ZXSpectrumCoreEmulationSettings()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void IntvControllerSettings_Load(object sender, EventArgs e)
|
||||
{
|
||||
_syncSettings = ((ZXSpectrum)Global.Emulator).GetSyncSettings().Clone();
|
||||
|
||||
// machine selection
|
||||
var machineTypes = Enum.GetNames(typeof(MachineType));
|
||||
foreach (var val in machineTypes)
|
||||
{
|
||||
MachineSelectionComboBox.Items.Add(val);
|
||||
}
|
||||
MachineSelectionComboBox.SelectedItem = _syncSettings.MachineType.ToString();
|
||||
UpdateMachineNotes((MachineType)Enum.Parse(typeof(MachineType), MachineSelectionComboBox.SelectedItem.ToString()));
|
||||
|
||||
// border selecton
|
||||
var borderTypes = Enum.GetNames(typeof(ZXSpectrum.BorderType));
|
||||
foreach (var val in borderTypes)
|
||||
{
|
||||
borderTypecomboBox1.Items.Add(val);
|
||||
}
|
||||
borderTypecomboBox1.SelectedItem = _syncSettings.BorderType.ToString();
|
||||
UpdateBorderNotes((ZXSpectrum.BorderType)Enum.Parse(typeof(ZXSpectrum.BorderType), borderTypecomboBox1.SelectedItem.ToString()));
|
||||
|
||||
// deterministic emulation
|
||||
determEmucheckBox1.Checked = _syncSettings.DeterministicEmulation;
|
||||
}
|
||||
|
||||
private void OkBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool changed =
|
||||
_syncSettings.MachineType.ToString() != MachineSelectionComboBox.SelectedItem.ToString()
|
||||
|| _syncSettings.BorderType.ToString() != borderTypecomboBox1.SelectedItem.ToString()
|
||||
|| _syncSettings.DeterministicEmulation != determEmucheckBox1.Checked;
|
||||
|
||||
if (changed)
|
||||
{
|
||||
_syncSettings.MachineType = (MachineType)Enum.Parse(typeof(MachineType), MachineSelectionComboBox.SelectedItem.ToString());
|
||||
_syncSettings.BorderType = (ZXSpectrum.BorderType)Enum.Parse(typeof(ZXSpectrum.BorderType), borderTypecomboBox1.SelectedItem.ToString());
|
||||
_syncSettings.DeterministicEmulation = determEmucheckBox1.Checked;
|
||||
|
||||
GlobalWin.MainForm.PutCoreSyncSettings(_syncSettings);
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
GlobalWin.OSD.AddMessage("Core emulator settings aborted");
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void MachineSelectionComboBox_SelectionChangeCommitted(object sender, EventArgs e)
|
||||
{
|
||||
ComboBox cb = sender as ComboBox;
|
||||
UpdateMachineNotes((MachineType)Enum.Parse(typeof(MachineType), cb.SelectedItem.ToString()));
|
||||
}
|
||||
|
||||
private void UpdateMachineNotes(MachineType type)
|
||||
{
|
||||
lblMachineNotes.Text = ZXMachineMetaData.GetMetaString(type);
|
||||
}
|
||||
|
||||
private void borderTypecomboBox1_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
ComboBox cb = sender as ComboBox;
|
||||
UpdateBorderNotes((ZXSpectrum.BorderType)Enum.Parse(typeof(ZXSpectrum.BorderType), cb.SelectedItem.ToString()));
|
||||
}
|
||||
|
||||
private void UpdateBorderNotes(ZXSpectrum.BorderType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ZXSpectrum.BorderType.Full:
|
||||
lblBorderInfo.Text = "Original border sizes";
|
||||
break;
|
||||
case ZXSpectrum.BorderType.Medium:
|
||||
lblBorderInfo.Text = "All borders 24px";
|
||||
break;
|
||||
case ZXSpectrum.BorderType.None:
|
||||
lblBorderInfo.Text = "No border at all";
|
||||
break;
|
||||
case ZXSpectrum.BorderType.Small:
|
||||
lblBorderInfo.Text = "All borders 10px";
|
||||
break;
|
||||
case ZXSpectrum.BorderType.Widescreen:
|
||||
lblBorderInfo.Text = "No top and bottom border (almost 16:9)";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +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>
|
||||
<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
|
||||
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
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXjU1h6NnZv/Fc3T/x3Bx/8dw
|
||||
cf/HcHH/x3Bx/8dwcf/HcHH/w3Jz/6ZoZ/9ZMzPTAQAAPQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyFxccektK0b12
|
||||
dv/HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xXR0/69wb/9jOjneBwMDSQAAAAUAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AABNKSlNlmBf9sh3d//HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xnd3/7Z4d/9sQUDnDgcHVQAA
|
||||
AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
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
|
||||
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
|
||||
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
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
184
BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumJoystickSettings.Designer.cs
generated
Normal file
184
BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumJoystickSettings.Designer.cs
generated
Normal file
|
@ -0,0 +1,184 @@
|
|||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
partial class ZXSpectrumJoystickSettings
|
||||
{
|
||||
/// <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(ZXSpectrumJoystickSettings));
|
||||
this.OkBtn = new System.Windows.Forms.Button();
|
||||
this.CancelBtn = new System.Windows.Forms.Button();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.Port2ComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.Port1ComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.Port3ComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.lblDoubleSize = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// 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(170, 312);
|
||||
this.OkBtn.Name = "OkBtn";
|
||||
this.OkBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.OkBtn.TabIndex = 3;
|
||||
this.OkBtn.Text = "&OK";
|
||||
this.OkBtn.UseVisualStyleBackColor = true;
|
||||
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
|
||||
//
|
||||
// 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(236, 312);
|
||||
this.CancelBtn.Name = "CancelBtn";
|
||||
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.CancelBtn.TabIndex = 4;
|
||||
this.CancelBtn.Text = "&Cancel";
|
||||
this.CancelBtn.UseVisualStyleBackColor = true;
|
||||
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Location = new System.Drawing.Point(9, 207);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(57, 13);
|
||||
this.label5.TabIndex = 16;
|
||||
this.label5.Text = "Joystick 2:";
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(12, 157);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(57, 13);
|
||||
this.label4.TabIndex = 15;
|
||||
this.label4.Text = "Joystick 1:";
|
||||
//
|
||||
// Port2ComboBox
|
||||
//
|
||||
this.Port2ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Port2ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.Port2ComboBox.FormattingEnabled = true;
|
||||
this.Port2ComboBox.Location = new System.Drawing.Point(12, 223);
|
||||
this.Port2ComboBox.Name = "Port2ComboBox";
|
||||
this.Port2ComboBox.Size = new System.Drawing.Size(284, 21);
|
||||
this.Port2ComboBox.TabIndex = 14;
|
||||
//
|
||||
// Port1ComboBox
|
||||
//
|
||||
this.Port1ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Port1ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.Port1ComboBox.FormattingEnabled = true;
|
||||
this.Port1ComboBox.Location = new System.Drawing.Point(12, 173);
|
||||
this.Port1ComboBox.Name = "Port1ComboBox";
|
||||
this.Port1ComboBox.Size = new System.Drawing.Size(284, 21);
|
||||
this.Port1ComboBox.TabIndex = 13;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(12, 14);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(151, 13);
|
||||
this.label1.TabIndex = 17;
|
||||
this.label1.Text = "ZX Spectrum Joystick Settings";
|
||||
//
|
||||
// Port3ComboBox
|
||||
//
|
||||
this.Port3ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Port3ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.Port3ComboBox.FormattingEnabled = true;
|
||||
this.Port3ComboBox.Location = new System.Drawing.Point(12, 275);
|
||||
this.Port3ComboBox.Name = "Port3ComboBox";
|
||||
this.Port3ComboBox.Size = new System.Drawing.Size(284, 21);
|
||||
this.Port3ComboBox.TabIndex = 18;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(12, 259);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(57, 13);
|
||||
this.label2.TabIndex = 19;
|
||||
this.label2.Text = "Joystick 3:";
|
||||
//
|
||||
// lblDoubleSize
|
||||
//
|
||||
this.lblDoubleSize.Location = new System.Drawing.Point(26, 40);
|
||||
this.lblDoubleSize.Name = "lblDoubleSize";
|
||||
this.lblDoubleSize.Size = new System.Drawing.Size(254, 117);
|
||||
this.lblDoubleSize.TabIndex = 20;
|
||||
this.lblDoubleSize.Text = resources.GetString("lblDoubleSize.Text");
|
||||
//
|
||||
// ZXSpectrumJoystickSettings
|
||||
//
|
||||
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(308, 347);
|
||||
this.Controls.Add(this.lblDoubleSize);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.Port3ComboBox);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.label5);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.Port2ComboBox);
|
||||
this.Controls.Add(this.Port1ComboBox);
|
||||
this.Controls.Add(this.CancelBtn);
|
||||
this.Controls.Add(this.OkBtn);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "ZXSpectrumJoystickSettings";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Joystick Settings";
|
||||
this.Load += new System.EventHandler(this.IntvControllerSettings_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button OkBtn;
|
||||
private System.Windows.Forms.Button CancelBtn;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.ComboBox Port2ComboBox;
|
||||
private System.Windows.Forms.ComboBox Port1ComboBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.ComboBox Port3ComboBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label lblDoubleSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Cores.Computers.SinclairSpectrum;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class ZXSpectrumJoystickSettings : Form
|
||||
{
|
||||
private ZXSpectrum.ZXSpectrumSyncSettings _syncSettings;
|
||||
|
||||
public ZXSpectrumJoystickSettings()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private string[] possibleControllers;
|
||||
|
||||
private void IntvControllerSettings_Load(object sender, EventArgs e)
|
||||
{
|
||||
_syncSettings = ((ZXSpectrum)Global.Emulator).GetSyncSettings().Clone();
|
||||
|
||||
possibleControllers = Enum.GetNames(typeof(JoystickType));
|
||||
|
||||
foreach (var val in possibleControllers)
|
||||
{
|
||||
Port1ComboBox.Items.Add(val);
|
||||
Port2ComboBox.Items.Add(val);
|
||||
Port3ComboBox.Items.Add(val);
|
||||
}
|
||||
|
||||
Port1ComboBox.SelectedItem = _syncSettings.JoystickType1.ToString();
|
||||
Port2ComboBox.SelectedItem = _syncSettings.JoystickType2.ToString();
|
||||
Port3ComboBox.SelectedItem = _syncSettings.JoystickType3.ToString();
|
||||
}
|
||||
|
||||
private void OkBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool changed =
|
||||
_syncSettings.JoystickType1.ToString() != Port1ComboBox.SelectedItem.ToString()
|
||||
|| _syncSettings.JoystickType2.ToString() != Port2ComboBox.SelectedItem.ToString()
|
||||
|| _syncSettings.JoystickType3.ToString() != Port3ComboBox.SelectedItem.ToString();
|
||||
|
||||
if (changed)
|
||||
{
|
||||
// enforce unique joystick selection
|
||||
|
||||
bool selectionValid = true;
|
||||
|
||||
var j1 = Port1ComboBox.SelectedItem.ToString();
|
||||
if (j1 != possibleControllers.First())
|
||||
{
|
||||
if (j1 == Port2ComboBox.SelectedItem.ToString())
|
||||
{
|
||||
Port2ComboBox.SelectedItem = possibleControllers.First();
|
||||
selectionValid = false;
|
||||
}
|
||||
if (j1 == Port3ComboBox.SelectedItem.ToString())
|
||||
{
|
||||
Port3ComboBox.SelectedItem = possibleControllers.First();
|
||||
selectionValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
var j2 = Port2ComboBox.SelectedItem.ToString();
|
||||
if (j2 != possibleControllers.First())
|
||||
{
|
||||
if (j2 == Port1ComboBox.SelectedItem.ToString())
|
||||
{
|
||||
Port1ComboBox.SelectedItem = possibleControllers.First();
|
||||
selectionValid = false;
|
||||
}
|
||||
if (j2 == Port3ComboBox.SelectedItem.ToString())
|
||||
{
|
||||
Port3ComboBox.SelectedItem = possibleControllers.First();
|
||||
selectionValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
var j3 = Port3ComboBox.SelectedItem.ToString();
|
||||
if (j3 != possibleControllers.First())
|
||||
{
|
||||
if (j3 == Port1ComboBox.SelectedItem.ToString())
|
||||
{
|
||||
Port1ComboBox.SelectedItem = possibleControllers.First();
|
||||
selectionValid = false;
|
||||
}
|
||||
if (j3 == Port2ComboBox.SelectedItem.ToString())
|
||||
{
|
||||
Port2ComboBox.SelectedItem = possibleControllers.First();
|
||||
selectionValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectionValid)
|
||||
{
|
||||
_syncSettings.JoystickType1 = (JoystickType)Enum.Parse(typeof(JoystickType), Port1ComboBox.SelectedItem.ToString());
|
||||
_syncSettings.JoystickType2 = (JoystickType)Enum.Parse(typeof(JoystickType), Port2ComboBox.SelectedItem.ToString());
|
||||
_syncSettings.JoystickType3 = (JoystickType)Enum.Parse(typeof(JoystickType), Port3ComboBox.SelectedItem.ToString());
|
||||
|
||||
GlobalWin.MainForm.PutCoreSyncSettings(_syncSettings);
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Invalid joystick configuration. \nDuplicates have automatically been changed to NULL.\n\nPlease review the configuration");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
GlobalWin.OSD.AddMessage("Joystick settings aborted");
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,630 @@
|
|||
<?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>
|
||||
<data name="lblDoubleSize.Text" xml:space="preserve">
|
||||
<value>ZXHawk is set up to allow 3 different unique joysticks to be attached at one time.
|
||||
|
||||
This is because the Kempston joystick had to be attached via a Kempton interface plugged into the single expansion port. The Sinclair and Cursor joysticks effectively mapped to different key presses on the keyboard.
|
||||
</value>
|
||||
</data>
|
||||
<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
|
||||
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
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXjU1h6NnZv/Fc3T/x3Bx/8dw
|
||||
cf/HcHH/x3Bx/8dwcf/HcHH/w3Jz/6ZoZ/9ZMzPTAQAAPQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyFxccektK0b12
|
||||
dv/HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xXR0/69wb/9jOjneBwMDSQAAAAUAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AABNKSlNlmBf9sh3d//HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xnd3/7Z4d/9sQUDnDgcHVQAA
|
||||
AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
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
|
||||
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
|
||||
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
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
162
BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumNonSyncSettings.Designer.cs
generated
Normal file
162
BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumNonSyncSettings.Designer.cs
generated
Normal file
|
@ -0,0 +1,162 @@
|
|||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
partial class ZXSpectrumNonSyncSettings
|
||||
{
|
||||
/// <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(ZXSpectrumNonSyncSettings));
|
||||
this.OkBtn = new System.Windows.Forms.Button();
|
||||
this.CancelBtn = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.autoLoadcheckBox1 = new System.Windows.Forms.CheckBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.panTypecomboBox1 = new System.Windows.Forms.ComboBox();
|
||||
this.lblBorderInfo = new System.Windows.Forms.Label();
|
||||
this.lblAutoLoadText = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// 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(247, 158);
|
||||
this.OkBtn.Name = "OkBtn";
|
||||
this.OkBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.OkBtn.TabIndex = 3;
|
||||
this.OkBtn.Text = "&OK";
|
||||
this.OkBtn.UseVisualStyleBackColor = true;
|
||||
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
|
||||
//
|
||||
// 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(313, 158);
|
||||
this.CancelBtn.Name = "CancelBtn";
|
||||
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
|
||||
this.CancelBtn.TabIndex = 4;
|
||||
this.CancelBtn.Text = "&Cancel";
|
||||
this.CancelBtn.UseVisualStyleBackColor = true;
|
||||
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(12, 14);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(185, 13);
|
||||
this.label1.TabIndex = 17;
|
||||
this.label1.Text = "ZX Spectrum Misc Non-Sync Settings";
|
||||
//
|
||||
// autoLoadcheckBox1
|
||||
//
|
||||
this.autoLoadcheckBox1.AutoSize = true;
|
||||
this.autoLoadcheckBox1.Location = new System.Drawing.Point(15, 52);
|
||||
this.autoLoadcheckBox1.Name = "autoLoadcheckBox1";
|
||||
this.autoLoadcheckBox1.Size = new System.Drawing.Size(103, 17);
|
||||
this.autoLoadcheckBox1.TabIndex = 21;
|
||||
this.autoLoadcheckBox1.Text = "Auto-Load Tape";
|
||||
this.autoLoadcheckBox1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(12, 97);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(135, 13);
|
||||
this.label2.TabIndex = 23;
|
||||
this.label2.Text = "AY-3-8912 Panning Config:";
|
||||
//
|
||||
// panTypecomboBox1
|
||||
//
|
||||
this.panTypecomboBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.panTypecomboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.panTypecomboBox1.FormattingEnabled = true;
|
||||
this.panTypecomboBox1.Location = new System.Drawing.Point(12, 113);
|
||||
this.panTypecomboBox1.Name = "panTypecomboBox1";
|
||||
this.panTypecomboBox1.Size = new System.Drawing.Size(157, 21);
|
||||
this.panTypecomboBox1.TabIndex = 22;
|
||||
//
|
||||
// lblBorderInfo
|
||||
//
|
||||
this.lblBorderInfo.Font = new System.Drawing.Font("Lucida Console", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblBorderInfo.Location = new System.Drawing.Point(175, 106);
|
||||
this.lblBorderInfo.Name = "lblBorderInfo";
|
||||
this.lblBorderInfo.Size = new System.Drawing.Size(196, 37);
|
||||
this.lblBorderInfo.TabIndex = 24;
|
||||
this.lblBorderInfo.Text = "Selects a particular panning configuration for the 3ch AY-3-8912 Programmable Sou" +
|
||||
"nd Generator (128K models only)";
|
||||
this.lblBorderInfo.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblAutoLoadText
|
||||
//
|
||||
this.lblAutoLoadText.Font = new System.Drawing.Font("Lucida Console", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblAutoLoadText.Location = new System.Drawing.Point(175, 46);
|
||||
this.lblAutoLoadText.Name = "lblAutoLoadText";
|
||||
this.lblAutoLoadText.Size = new System.Drawing.Size(196, 30);
|
||||
this.lblAutoLoadText.TabIndex = 25;
|
||||
this.lblAutoLoadText.Text = "When enabled ZXHawk will attempt to control the tape device automatically when th" +
|
||||
"e correct traps are detected";
|
||||
this.lblAutoLoadText.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// ZXSpectrumNonSyncSettings
|
||||
//
|
||||
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(385, 193);
|
||||
this.Controls.Add(this.lblAutoLoadText);
|
||||
this.Controls.Add(this.lblBorderInfo);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.panTypecomboBox1);
|
||||
this.Controls.Add(this.autoLoadcheckBox1);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.CancelBtn);
|
||||
this.Controls.Add(this.OkBtn);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "ZXSpectrumNonSyncSettings";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Other Non-Sync Settings";
|
||||
this.Load += new System.EventHandler(this.IntvControllerSettings_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button OkBtn;
|
||||
private System.Windows.Forms.Button CancelBtn;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox autoLoadcheckBox1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox panTypecomboBox1;
|
||||
private System.Windows.Forms.Label lblBorderInfo;
|
||||
private System.Windows.Forms.Label lblAutoLoadText;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Cores.Computers.SinclairSpectrum;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class ZXSpectrumNonSyncSettings : Form
|
||||
{
|
||||
private ZXSpectrum.ZXSpectrumSettings _settings;
|
||||
|
||||
public ZXSpectrumNonSyncSettings()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void IntvControllerSettings_Load(object sender, EventArgs e)
|
||||
{
|
||||
_settings = ((ZXSpectrum)Global.Emulator).GetSettings().Clone();
|
||||
|
||||
// autoload tape
|
||||
autoLoadcheckBox1.Checked = _settings.AutoLoadTape;
|
||||
|
||||
// AY panning config
|
||||
var panTypes = Enum.GetNames(typeof(AYChip.AYPanConfig));
|
||||
foreach (var val in panTypes)
|
||||
{
|
||||
panTypecomboBox1.Items.Add(val);
|
||||
}
|
||||
panTypecomboBox1.SelectedItem = _settings.AYPanConfig.ToString();
|
||||
}
|
||||
|
||||
private void OkBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool changed =
|
||||
_settings.AutoLoadTape != autoLoadcheckBox1.Checked
|
||||
|| _settings.AYPanConfig.ToString() != panTypecomboBox1.SelectedItem.ToString();
|
||||
|
||||
if (changed)
|
||||
{
|
||||
_settings.AutoLoadTape = autoLoadcheckBox1.Checked;
|
||||
_settings.AYPanConfig = (AYChip.AYPanConfig)Enum.Parse(typeof(AYChip.AYPanConfig), panTypecomboBox1.SelectedItem.ToString());
|
||||
|
||||
GlobalWin.MainForm.PutCoreSettings(_settings);
|
||||
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
GlobalWin.OSD.AddMessage("Misc settings aborted");
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +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>
|
||||
<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
|
||||
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
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXjU1h6NnZv/Fc3T/x3Bx/8dw
|
||||
cf/HcHH/x3Bx/8dwcf/HcHH/w3Jz/6ZoZ/9ZMzPTAQAAPQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyFxccektK0b12
|
||||
dv/HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xXR0/69wb/9jOjneBwMDSQAAAAUAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AABNKSlNlmBf9sh3d//HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xnd3/7Z4d/9sQUDnDgcHVQAA
|
||||
AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
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
|
||||
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
|
||||
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
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
|
@ -143,7 +143,8 @@
|
|||
"GB",
|
||||
"PCFX",
|
||||
"PSX",
|
||||
"SAT"});
|
||||
"SAT",
|
||||
"ZXSpectrum"});
|
||||
this.SystemDropDown.Location = new System.Drawing.Point(425, 75);
|
||||
this.SystemDropDown.Name = "SystemDropDown";
|
||||
this.SystemDropDown.Size = new System.Drawing.Size(69, 21);
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
[Schema("ZXSpectrum")]
|
||||
class ZXSpectrumSchema : IVirtualPadSchema
|
||||
{
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
|
||||
{
|
||||
yield return Joystick(1);
|
||||
yield return Joystick(2);
|
||||
yield return Joystick(3);
|
||||
yield return Keyboard();
|
||||
//yield return TapeDevice();
|
||||
}
|
||||
|
||||
private static PadSchema Joystick(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Joystick " + controller,
|
||||
IsConsole = false,
|
||||
DefaultSize = new Size(174, 74),
|
||||
MaxSize = new Size(174, 74),
|
||||
Buttons = new[]
|
||||
{
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Up",
|
||||
DisplayName = "",
|
||||
Icon = Properties.Resources.BlueUp,
|
||||
Location = new Point(23, 15),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Down",
|
||||
DisplayName = "",
|
||||
Icon = Properties.Resources.BlueDown,
|
||||
Location = new Point(23, 36),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Left",
|
||||
DisplayName = "",
|
||||
Icon = Properties.Resources.Back,
|
||||
Location = new Point(2, 24),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Right",
|
||||
DisplayName = "",
|
||||
Icon = Properties.Resources.Forward,
|
||||
Location = new Point(44, 24),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Button",
|
||||
DisplayName = "B",
|
||||
Location = new Point(124, 24),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class ButtonLayout
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string DisName { get; set; }
|
||||
public double WidthFactor { get; set; }
|
||||
public int Row { get; set; }
|
||||
public bool IsActive = true;
|
||||
}
|
||||
|
||||
private static PadSchema Keyboard()
|
||||
{
|
||||
List<ButtonLayout> bls = new List<ButtonLayout>
|
||||
{
|
||||
new ButtonLayout { Name = "Key True Video", DisName = "TV", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Inv Video", DisName = "IV", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 1", DisName = "1", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 2", DisName = "2", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 3", DisName = "3", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 4", DisName = "4", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 5", DisName = "5", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 6", DisName = "6", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 7", DisName = "7", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 8", DisName = "8", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 9", DisName = "9", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key 0", DisName = "0", Row = 0, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Break", DisName = "BREAK", Row = 0, WidthFactor = 1.5 },
|
||||
|
||||
new ButtonLayout { Name = "Key Delete", DisName = "DEL", Row = 1, WidthFactor = 1.5 },
|
||||
new ButtonLayout { Name = "Key Graph", DisName = "GR", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Q", DisName = "Q", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key W", DisName = "W", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key E", DisName = "E", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key R", DisName = "R", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key T", DisName = "T", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Y", DisName = "Y", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key U", DisName = "U", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key I", DisName = "I", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key O", DisName = "O", Row = 1, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key P", DisName = "P", Row = 1, WidthFactor = 1 },
|
||||
|
||||
new ButtonLayout { Name = "Key Extend Mode", DisName = "EM", Row = 2, WidthFactor = 1.5 },
|
||||
new ButtonLayout { Name = "Key Edit", DisName = "ED", Row = 2, WidthFactor = 1.25},
|
||||
new ButtonLayout { Name = "Key A", DisName = "A", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key S", DisName = "S", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key D", DisName = "D", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key F", DisName = "F", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key G", DisName = "G", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key H", DisName = "H", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key J", DisName = "J", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key K", DisName = "K", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key L", DisName = "L", Row = 2, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Return", DisName = "ENTER", Row = 2, WidthFactor = 1.75 },
|
||||
|
||||
new ButtonLayout { Name = "Key Caps Shift", DisName = "CAPS-S", Row = 3, WidthFactor = 2.25 },
|
||||
new ButtonLayout { Name = "Key Caps Lock", DisName = "CL", Row = 3, WidthFactor = 1},
|
||||
new ButtonLayout { Name = "Key Z", DisName = "Z", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key X", DisName = "X", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key C", DisName = "C", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key V", DisName = "V", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key B", DisName = "B", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key N", DisName = "N", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key M", DisName = "M", Row = 3, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Period", DisName = ".", Row = 3, WidthFactor = 1},
|
||||
new ButtonLayout { Name = "Key Caps Shift", DisName = "CAPS-S", Row = 3, WidthFactor = 2.25 },
|
||||
|
||||
new ButtonLayout { Name = "Key Symbol Shift", DisName = "SS", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Semi-Colon", DisName = ";", Row = 4, WidthFactor = 1},
|
||||
new ButtonLayout { Name = "Key Quote", DisName = "\"", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Left Cursor", DisName = "←", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Right Cursor", DisName = "→", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Space", DisName = "SPACE", Row = 4, WidthFactor = 4.5 },
|
||||
new ButtonLayout { Name = "Key Up Cursor", DisName = "↑", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Down Cursor", DisName = "↓", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Comma", DisName = ",", Row = 4, WidthFactor = 1 },
|
||||
new ButtonLayout { Name = "Key Symbol Shift", DisName = "SS", Row = 4, WidthFactor = 1 },
|
||||
};
|
||||
|
||||
PadSchema ps = new PadSchema
|
||||
{
|
||||
DisplayName = "Keyboard",
|
||||
IsConsole = false,
|
||||
DefaultSize = new Size(500, 170)
|
||||
};
|
||||
|
||||
List<PadSchema.ButtonSchema> btns = new List<PadSchema.ButtonSchema>();
|
||||
|
||||
int rowHeight = 29; //24
|
||||
int stdButtonWidth = 29; //24
|
||||
int yPos = 18;
|
||||
int xPos = 22;
|
||||
int currRow = 0;
|
||||
|
||||
foreach (var b in bls)
|
||||
{
|
||||
if (b.Row > currRow)
|
||||
{
|
||||
currRow++;
|
||||
yPos += rowHeight;
|
||||
xPos = 22;
|
||||
}
|
||||
|
||||
int txtLength = b.DisName.Length;
|
||||
int btnSize = System.Convert.ToInt32((double)stdButtonWidth * b.WidthFactor);
|
||||
|
||||
|
||||
string disp = b.DisName;
|
||||
if (txtLength == 1)
|
||||
disp = " " + disp;
|
||||
|
||||
switch(b.DisName)
|
||||
{
|
||||
case "SPACE": disp = " " + disp + " "; break;
|
||||
case "I": disp = " " + disp + " "; break;
|
||||
case "W": disp = b.DisName; break;
|
||||
}
|
||||
|
||||
|
||||
if (b.IsActive)
|
||||
{
|
||||
PadSchema.ButtonSchema btn = new PadSchema.ButtonSchema();
|
||||
btn.Name = b.Name;
|
||||
btn.DisplayName = disp;
|
||||
btn.Location = new Point(xPos, yPos);
|
||||
btn.Type = PadSchema.PadInputType.Boolean;
|
||||
btns.Add(btn);
|
||||
}
|
||||
|
||||
xPos += btnSize;
|
||||
}
|
||||
|
||||
ps.Buttons = btns.ToArray();
|
||||
return ps;
|
||||
}
|
||||
|
||||
private static PadSchema TapeDevice()
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "DATACORDER",
|
||||
IsConsole = false,
|
||||
DefaultSize = new Size(174, 74),
|
||||
MaxSize = new Size(174, 74),
|
||||
Buttons = new[]
|
||||
{
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Play Tape",
|
||||
Icon = Properties.Resources.Play,
|
||||
Location = new Point(23, 22),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Stop Tape",
|
||||
Icon = Properties.Resources.Stop,
|
||||
Location = new Point(53, 22),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "RTZ Tape",
|
||||
Icon = Properties.Resources.BackMore,
|
||||
Location = new Point(83, 22),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Insert Next Tape",
|
||||
DisplayName = "NEXT TAPE",
|
||||
//Icon = Properties.Resources.MoveRight,
|
||||
Location = new Point(23, 52),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Insert Previous Tape",
|
||||
DisplayName = "PREV TAPE",
|
||||
//Icon = Properties.Resources.MoveLeft,
|
||||
Location = new Point(100, 52),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Common
|
||||
{
|
||||
|
@ -298,12 +299,24 @@ namespace BizHawk.Emulation.Common
|
|||
case ".D64":
|
||||
case ".T64":
|
||||
case ".G64":
|
||||
case ".CRT":
|
||||
case ".TAP":
|
||||
case ".CRT":
|
||||
game.System = "C64";
|
||||
break;
|
||||
|
||||
case ".Z64":
|
||||
case ".TZX":
|
||||
game.System = "ZXSpectrum";
|
||||
break;
|
||||
|
||||
case ".TAP":
|
||||
|
||||
byte[] head = romData.Take(8).ToArray();
|
||||
if (System.Text.Encoding.Default.GetString(head).Contains("C64-TAPE"))
|
||||
game.System = "C64";
|
||||
else
|
||||
game.System = "ZXSpectrum";
|
||||
break;
|
||||
|
||||
case ".Z64":
|
||||
case ".V64":
|
||||
case ".N64":
|
||||
game.System = "N64";
|
||||
|
|
|
@ -50,9 +50,17 @@ namespace BizHawk.Emulation.Common
|
|||
FirmwareAndOption("AB16F56989B27D89BABE5F89C5A8CB3DA71A82F0", 16384, "C64", "Drive1541", "drive-1541.bin", "1541 Disk Drive Rom");
|
||||
FirmwareAndOption("D3B78C3DBAC55F5199F33F3FE0036439811F7FB3", 16384, "C64", "Drive1541II", "drive-1541ii.bin", "1541-II Disk Drive Rom");
|
||||
|
||||
// for saturn, we think any bios region can pretty much run any iso
|
||||
// so, we're going to lay this out carefully so that we choose things in a sensible order, but prefer the correct region
|
||||
var ss_100_j = File("2B8CB4F87580683EB4D760E4ED210813D667F0A2", 524288, "saturn-1.00-(J).bin", "Bios v1.00 (J)");
|
||||
// ZX Spectrum
|
||||
/* These are now shipped with bizhawk
|
||||
FirmwareAndOption("5EA7C2B824672E914525D1D5C419D71B84A426A2", 16384, "ZXSpectrum", "48ROM", "48.ROM", "Spectrum 48K ROM");
|
||||
FirmwareAndOption("16375D42EA109B47EDDED7A16028DE7FDB3013A1", 32768, "ZXSpectrum", "128ROM", "128.ROM", "Spectrum 128K ROM");
|
||||
FirmwareAndOption("8CAFB292AF58617907B9E6B9093D3588A75849B8", 32768, "ZXSpectrum", "PLUS2ROM", "PLUS2.ROM", "Spectrum 128K +2 ROM");
|
||||
FirmwareAndOption("929BF1A5E5687EBD8D7245F9B513A596C0EC21A4", 65536, "ZXSpectrum", "PLUS3ROM", "PLUS3.ROM", "Spectrum 128K +3 ROM");
|
||||
*/
|
||||
|
||||
// for saturn, we think any bios region can pretty much run any iso
|
||||
// so, we're going to lay this out carefully so that we choose things in a sensible order, but prefer the correct region
|
||||
var ss_100_j = File("2B8CB4F87580683EB4D760E4ED210813D667F0A2", 524288, "saturn-1.00-(J).bin", "Bios v1.00 (J)");
|
||||
var ss_100_ue = File("FAA8EA183A6D7BBE5D4E03BB1332519800D3FBC3", 524288, "saturn-1.00-(U+E).bin", "Bios v1.00 (U+E)");
|
||||
var ss_100a_ue = File("3BB41FEB82838AB9A35601AC666DE5AACFD17A58", 524288, "saturn-1.00a-(U+E).bin", "Bios v1.00a (U+E)"); // ?? is this size correct?
|
||||
var ss_101_j = File("DF94C5B4D47EB3CC404D88B33A8FDA237EAF4720", 524288, "saturn-1.01-(J).bin", "Bios v1.01 (J)"); // ?? is this size correct?
|
||||
|
|
|
@ -32,7 +32,8 @@ namespace BizHawk.Emulation.Common
|
|||
|
||||
new SystemInfo { SystemId = "C64", FullName = "Commodore 64" },
|
||||
new SystemInfo { SystemId = "AppleII", FullName = "Apple II" },
|
||||
new SystemInfo { SystemId = "INTV", FullName = "Intellivision" }
|
||||
new SystemInfo { SystemId = "INTV", FullName = "Intellivision" },
|
||||
new SystemInfo { SystemId = "ZXSpectrum", FullName = "Sinclair ZX Spectrum" }
|
||||
};
|
||||
|
||||
public SystemInfo this[string systemId]
|
||||
|
|
|
@ -258,6 +258,61 @@
|
|||
<Compile Include="Computers\Commodore64\MOS\Vic.VideoProvider.cs" />
|
||||
<Compile Include="Computers\Commodore64\SaveState.cs" />
|
||||
<Compile Include="Computers\Commodore64\User\UserPortDevice.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IJoystick.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IPortIODevice.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IPSG.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\CursorJoystick.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\SinclairJoystick2.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\SinclairJoystick1.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\NullJoystick.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\SoundOuput\AYChip.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\SoundOuput\Buzzer.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Datacorder\DatacorderDevice.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IKeyboard.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\KempstonJoystick.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IBeeperDevice.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ULABase.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.Memory.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.Port.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum16K\ZX16.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\MediaSerializationType.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\MediaSerializer.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapeCommand.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapeDataBlock.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapSerializer.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TzxSerializer.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\SoundProviderMixer.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\MachineType.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Input.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Port.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Memory.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2\ZX128Plus2.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.Memory.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.Port.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.Memory.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.Port.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.Memory.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\SoundOuput\Pulse.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Rom\RomData.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.Controllers.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.IDebuggable.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.IEmulator.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.IInputPollable.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.IMemoryDomains.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.ISettable.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.IStatable.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.Messaging.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\ZXSpectrum.Util.cs" />
|
||||
<Compile Include="Consoles\Atari\2600\Atari2600.cs" />
|
||||
<Compile Include="Consoles\Atari\2600\Atari2600.Core.cs">
|
||||
<DependentUpon>Atari2600.cs</DependentUpon>
|
||||
|
@ -1338,16 +1393,29 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\StandardKeyboard.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.Port.cs" />
|
||||
<None Include="Computers\SinclairSpectrum\readme.md" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Media.cs" />
|
||||
<None Include="Consoles\Atari\docs\stella.pdf" />
|
||||
<None Include="Consoles\Coleco\docs\colecovision tech1.pdf" />
|
||||
<None Include="Consoles\Coleco\docs\colecovision tech2.pdf" />
|
||||
<None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" />
|
||||
<None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" />
|
||||
<None Include="Consoles\Nintendo\NES\Docs\nesasm.pdf" />
|
||||
<None Include="Resources\128.ROM.gz" />
|
||||
<None Include="Resources\48.ROM.gz" />
|
||||
<None Include="Resources\cgb_boot.bin.gz" />
|
||||
<None Include="Resources\dmg_boot.bin.gz" />
|
||||
<None Include="Resources\plus2.rom.gz" />
|
||||
<None Include="Resources\plus2a.rom.gz" />
|
||||
<None Include="Resources\sgb-cart-present.spc.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM0.bin.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM1.bin.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM2.bin.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM3.bin.gz" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">"$(SolutionDir)subwcrev.bat" "$(ProjectDir)"</PreBuildEvent>
|
||||
|
|
|
@ -4,8 +4,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
private int totalExecutedCycles;
|
||||
public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } }
|
||||
public long TotalExecutedCycles;
|
||||
|
||||
private int EI_pending;
|
||||
|
||||
|
|
|
@ -83,28 +83,27 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
}
|
||||
|
||||
// Interrupt mode 2 uses the I vector combined with a byte on the data bus
|
||||
// Again for now we assume only a 0 on the data bus and jump to (0xI00)
|
||||
private void INTERRUPT_2(ushort src)
|
||||
private void INTERRUPT_2()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
FTCH_DB,
|
||||
TR, Z, DB,
|
||||
TR, W, I,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
ASGN, PCl, 0,
|
||||
TR, PCh, I,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
RD, PCl, Z, W,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
RD, PCh, Z, W,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
|
|
@ -435,6 +435,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
addr += extra_inc;
|
||||
|
||||
size = addr - start_addr;
|
||||
// handle case of addr wrapping around at 16 bit boundary
|
||||
if (addr < start_addr)
|
||||
{
|
||||
size = (0x10000 + addr) - start_addr;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,31 +8,37 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
public void Read_Func(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
|
||||
Regs[DB] = Regs[dest];
|
||||
}
|
||||
|
||||
public void I_Read_Func(ushort dest, ushort src_l, ushort src_h, ushort inc)
|
||||
{
|
||||
Regs[dest] = ReadMemory((ushort)((Regs[src_l] | (Regs[src_h] << 8)) + inc));
|
||||
Regs[DB] = Regs[dest];
|
||||
}
|
||||
|
||||
public void Write_Func(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
Regs[DB] = Regs[src];
|
||||
WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]);
|
||||
}
|
||||
|
||||
public void I_Write_Func(ushort dest_l, ushort dest_h, ushort inc, ushort src)
|
||||
{
|
||||
Regs[DB] = Regs[src];
|
||||
WriteMemory((ushort)((Regs[dest_l] | (Regs[dest_h] << 8)) + inc), (byte)Regs[src]);
|
||||
}
|
||||
|
||||
public void OUT_Func(ushort dest, ushort src)
|
||||
public void OUT_Func(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
WriteHardware(Regs[dest], (byte)(Regs[src]));
|
||||
Regs[DB] = Regs[src];
|
||||
WriteHardware((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)(Regs[src]));
|
||||
}
|
||||
|
||||
public void IN_Func(ushort dest, ushort src)
|
||||
public void IN_Func(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
Regs[dest] = ReadHardware(Regs[src]);
|
||||
Regs[dest] = ReadHardware((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
|
||||
Regs[DB] = Regs[dest];
|
||||
}
|
||||
|
||||
public void TR_Func(ushort dest, ushort src)
|
||||
|
@ -738,5 +744,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
Flag3 = (Regs[A] & 0x08) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void FTCH_DB_Func()
|
||||
{
|
||||
Regs[DB] = FetchDB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
TODO:
|
||||
|
||||
Mode 0 and 2 interrupts
|
||||
Mode 0
|
||||
Check T-cycle level memory access timing
|
||||
Check R register
|
||||
new tests for WZ Registers
|
||||
Memory refresh - IR is pushed onto the address bus at instruction start, does anything need this?
|
||||
Data Bus - For mode zero and 2 interrupts, need a system that uses it to test
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
public partial class Z80A
|
||||
{
|
||||
// registers
|
||||
// note these are not constants. When shadows are used, they will be changed accordingly
|
||||
public ushort PCl = 0;
|
||||
public ushort PCh = 1;
|
||||
public ushort SPl = 2;
|
||||
|
@ -40,6 +39,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
public ushort E_s = 29;
|
||||
public ushort H_s = 30;
|
||||
public ushort L_s = 31;
|
||||
public ushort DB = 32;
|
||||
|
||||
public ushort[] Regs = new ushort[36];
|
||||
|
||||
|
|
|
@ -452,13 +452,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
TR, W, A,
|
||||
OUT, ALU, A,
|
||||
TR, Z, ALU,
|
||||
INC16, Z, ALU,
|
||||
OUT, Z, W, A,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP};
|
||||
|
@ -469,9 +469,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
OUT, dest, src,
|
||||
IDLE,
|
||||
TR16, Z, W, C, B,
|
||||
OUT, Z, W, src,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
OP};
|
||||
|
@ -481,12 +481,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
TR, W, A,
|
||||
IN, A, ALU,
|
||||
TR, Z, ALU,
|
||||
IN, A, Z, W,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
|
@ -498,7 +498,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IN, dest, src,
|
||||
IN, dest, src, B,
|
||||
IDLE,
|
||||
TR16, Z, W, C, B,
|
||||
INC16, Z, W,
|
||||
|
|
|
@ -419,7 +419,7 @@
|
|||
private void IN_OP_R(ushort operation, ushort repeat_instr)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IN, ALU, C,
|
||||
{IN, ALU, C, B,
|
||||
IDLE,
|
||||
WR, L, H, ALU,
|
||||
IDLE,
|
||||
|
@ -438,7 +438,7 @@
|
|||
cur_instr = new ushort[]
|
||||
{RD, ALU, L, H,
|
||||
IDLE,
|
||||
OUT, C, ALU,
|
||||
OUT, C, B, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
operation, L, H,
|
||||
|
|
|
@ -74,6 +74,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
public const ushort SET_FL_IR = 59;
|
||||
public const ushort I_BIT = 60;
|
||||
public const ushort HL_BIT = 61;
|
||||
public const ushort FTCH_DB = 62;
|
||||
|
||||
public byte temp_R;
|
||||
|
||||
|
@ -106,6 +107,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
public Func<ushort, byte> ReadHardware;
|
||||
public Action<ushort, byte> WriteHardware;
|
||||
|
||||
// Data Bus
|
||||
// Interrupting Devices are responsible for putting a value onto the data bus
|
||||
// for as long as the interrupt is valid
|
||||
public Func<byte> FetchDB;
|
||||
|
||||
//this only calls when the first byte of an instruction is fetched.
|
||||
public Action<ushort> OnExecFetch;
|
||||
|
||||
|
@ -190,9 +196,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
INTERRUPT_1();
|
||||
break;
|
||||
case 2:
|
||||
// Low byte of interrupt vector comes from data bus
|
||||
// We'll assume it's zero for now
|
||||
INTERRUPT_2(0);
|
||||
INTERRUPT_2();
|
||||
break;
|
||||
}
|
||||
IRQCallback();
|
||||
|
@ -315,9 +319,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
INTERRUPT_1();
|
||||
break;
|
||||
case 2:
|
||||
// Low byte of interrupt vector comes from data bus
|
||||
// We'll assume it's zero for now
|
||||
INTERRUPT_2(0);
|
||||
INTERRUPT_2();
|
||||
break;
|
||||
}
|
||||
IRQCallback();
|
||||
|
@ -339,6 +341,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
|
||||
case HALT:
|
||||
halted = true;
|
||||
// NOTE: Check how halt state effects the DB
|
||||
Regs[DB] = 0xFF;
|
||||
|
||||
if (EI_pending > 0)
|
||||
{
|
||||
EI_pending--;
|
||||
|
@ -382,9 +387,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
INTERRUPT_1();
|
||||
break;
|
||||
case 2:
|
||||
// Low byte of interrupt vector comes from data bus
|
||||
// We'll assume it's zero for now
|
||||
INTERRUPT_2(0);
|
||||
INTERRUPT_2();
|
||||
break;
|
||||
}
|
||||
IRQCallback();
|
||||
|
@ -569,10 +572,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
iff1 = iff2;
|
||||
break;
|
||||
case OUT:
|
||||
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case IN:
|
||||
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case NEG:
|
||||
NEG_8_Func(cur_instr[instr_pntr++]);
|
||||
|
@ -595,8 +598,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
case SET_FL_IR:
|
||||
SET_FL_IR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case FTCH_DB:
|
||||
FTCH_DB_Func();
|
||||
break;
|
||||
}
|
||||
totalExecutedCycles++;
|
||||
TotalExecutedCycles++;
|
||||
}
|
||||
|
||||
// tracer stuff
|
||||
|
@ -651,8 +657,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
FlagI ? "E" : "e")
|
||||
};
|
||||
}
|
||||
// State Save/Load
|
||||
|
||||
// State Save/Load
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Z80A");
|
||||
|
@ -663,7 +669,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
|
|||
ser.Sync("IFF1", ref iff1);
|
||||
ser.Sync("IFF2", ref iff2);
|
||||
ser.Sync("Halted", ref halted);
|
||||
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
|
||||
ser.Sync("ExecutedCycles", ref TotalExecutedCycles);
|
||||
ser.Sync("EI_pending", ref EI_pending);
|
||||
|
||||
ser.Sync("instruction_pointer", ref instr_pntr);
|
||||
|
|
|
@ -12,35 +12,35 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = _cpu.Regs[_cpu.A],
|
||||
["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8),
|
||||
["B"] = _cpu.Regs[_cpu.B],
|
||||
["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8),
|
||||
["C"] = _cpu.Regs[_cpu.C],
|
||||
["D"] = _cpu.Regs[_cpu.D],
|
||||
["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8),
|
||||
["E"] = _cpu.Regs[_cpu.E],
|
||||
["F"] = _cpu.Regs[_cpu.F],
|
||||
["H"] = _cpu.Regs[_cpu.H],
|
||||
["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8),
|
||||
["I"] = _cpu.Regs[_cpu.I],
|
||||
["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8),
|
||||
["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
|
||||
["L"] = _cpu.Regs[_cpu.L],
|
||||
["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8),
|
||||
["R"] = _cpu.Regs[_cpu.R],
|
||||
["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8),
|
||||
["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8),
|
||||
["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8),
|
||||
["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8),
|
||||
["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
|
||||
["Flag C"] = _cpu.FlagC,
|
||||
["Flag N"] = _cpu.FlagN,
|
||||
["Flag P/V"] = _cpu.FlagP,
|
||||
["Flag 3rd"] = _cpu.Flag3,
|
||||
["Flag H"] = _cpu.FlagH,
|
||||
["Flag 5th"] = _cpu.Flag5,
|
||||
["Flag Z"] = _cpu.FlagZ,
|
||||
["A"] = _cpu.Regs[_cpu.A],
|
||||
["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8),
|
||||
["B"] = _cpu.Regs[_cpu.B],
|
||||
["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8),
|
||||
["C"] = _cpu.Regs[_cpu.C],
|
||||
["D"] = _cpu.Regs[_cpu.D],
|
||||
["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8),
|
||||
["E"] = _cpu.Regs[_cpu.E],
|
||||
["F"] = _cpu.Regs[_cpu.F],
|
||||
["H"] = _cpu.Regs[_cpu.H],
|
||||
["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8),
|
||||
["I"] = _cpu.Regs[_cpu.I],
|
||||
["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8),
|
||||
["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
|
||||
["L"] = _cpu.Regs[_cpu.L],
|
||||
["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8),
|
||||
["R"] = _cpu.Regs[_cpu.R],
|
||||
["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8),
|
||||
["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8),
|
||||
["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8),
|
||||
["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8),
|
||||
["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
|
||||
["Flag C"] = _cpu.FlagC,
|
||||
["Flag N"] = _cpu.FlagN,
|
||||
["Flag P/V"] = _cpu.FlagP,
|
||||
["Flag 3rd"] = _cpu.Flag3,
|
||||
["Flag H"] = _cpu.FlagH,
|
||||
["Flag 5th"] = _cpu.Flag5,
|
||||
["Flag Z"] = _cpu.FlagZ,
|
||||
["Flag S"] = _cpu.FlagS
|
||||
};
|
||||
}
|
||||
|
@ -49,85 +49,85 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.Regs[_cpu.A] = (ushort)value;
|
||||
break;
|
||||
case "AF":
|
||||
_cpu.Regs[_cpu.F] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "B":
|
||||
_cpu.Regs[_cpu.B] = (ushort)value;
|
||||
break;
|
||||
case "BC":
|
||||
_cpu.Regs[_cpu.C] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "C":
|
||||
_cpu.Regs[_cpu.C] = (ushort)value;
|
||||
break;
|
||||
case "D":
|
||||
_cpu.Regs[_cpu.D] = (ushort)value;
|
||||
break;
|
||||
case "DE":
|
||||
_cpu.Regs[_cpu.E] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "E":
|
||||
_cpu.Regs[_cpu.E] = (ushort)value;
|
||||
break;
|
||||
case "F":
|
||||
_cpu.Regs[_cpu.F] = (ushort)value;
|
||||
break;
|
||||
case "H":
|
||||
_cpu.Regs[_cpu.H] = (ushort)value;
|
||||
break;
|
||||
case "HL":
|
||||
_cpu.Regs[_cpu.L] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "I":
|
||||
_cpu.Regs[_cpu.I] = (ushort)value;
|
||||
break;
|
||||
case "IX":
|
||||
_cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "IY":
|
||||
_cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "L":
|
||||
_cpu.Regs[_cpu.L] = (ushort)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "R":
|
||||
_cpu.Regs[_cpu.R] = (ushort)value;
|
||||
break;
|
||||
case "Shadow AF":
|
||||
_cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow BC":
|
||||
_cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow DE":
|
||||
_cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow HL":
|
||||
_cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "SP":
|
||||
_cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00);
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.Regs[_cpu.A] = (ushort)value;
|
||||
break;
|
||||
case "AF":
|
||||
_cpu.Regs[_cpu.F] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "B":
|
||||
_cpu.Regs[_cpu.B] = (ushort)value;
|
||||
break;
|
||||
case "BC":
|
||||
_cpu.Regs[_cpu.C] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "C":
|
||||
_cpu.Regs[_cpu.C] = (ushort)value;
|
||||
break;
|
||||
case "D":
|
||||
_cpu.Regs[_cpu.D] = (ushort)value;
|
||||
break;
|
||||
case "DE":
|
||||
_cpu.Regs[_cpu.E] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "E":
|
||||
_cpu.Regs[_cpu.E] = (ushort)value;
|
||||
break;
|
||||
case "F":
|
||||
_cpu.Regs[_cpu.F] = (ushort)value;
|
||||
break;
|
||||
case "H":
|
||||
_cpu.Regs[_cpu.H] = (ushort)value;
|
||||
break;
|
||||
case "HL":
|
||||
_cpu.Regs[_cpu.L] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "I":
|
||||
_cpu.Regs[_cpu.I] = (ushort)value;
|
||||
break;
|
||||
case "IX":
|
||||
_cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "IY":
|
||||
_cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "L":
|
||||
_cpu.Regs[_cpu.L] = (ushort)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "R":
|
||||
_cpu.Regs[_cpu.R] = (ushort)value;
|
||||
break;
|
||||
case "Shadow AF":
|
||||
_cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow BC":
|
||||
_cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow DE":
|
||||
_cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow HL":
|
||||
_cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "SP":
|
||||
_cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +145,6 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
return false;
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles => _cpu.TotalExecutedCycles;
|
||||
public int TotalExecutedCycles => (int)_cpu.TotalExecutedCycles;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,6 +137,8 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
|
||||
private void WriteHardware(ushort addr, byte value)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0: // PORT_LINK
|
||||
|
@ -232,6 +234,8 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
|
||||
private byte ReadHardware(ushort addr)
|
||||
{
|
||||
addr &= 0xFF;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0: // PORT_LINK
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public interface IBeeperDevice
|
||||
{
|
||||
void Init(int sampleRate, int tStatesPerFrame);
|
||||
|
||||
void ProcessPulseValue(bool fromTape, bool earPulse);
|
||||
|
||||
void StartFrame();
|
||||
|
||||
void EndFrame();
|
||||
|
||||
void SetTapeMode(bool tapeMode);
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a spectrum joystick
|
||||
/// </summary>
|
||||
public interface IJoystick
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of joystick
|
||||
/// </summary>
|
||||
JoystickType JoyType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Array of all the possibly button press names
|
||||
/// </summary>
|
||||
string[] ButtonCollection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The player number that this controller is currently assigned to
|
||||
/// </summary>
|
||||
int PlayerNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joystick line based on key pressed
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
void SetJoyInput(string key, bool isPressed);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of a particular joystick binding
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
bool GetJoyInput(string key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a spectrum keyboard
|
||||
/// </summary>
|
||||
public interface IKeyboard : IPortIODevice
|
||||
{
|
||||
/// <summary>
|
||||
/// The calling spectrumbase class
|
||||
/// </summary>
|
||||
SpectrumBase _machine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The keyboard matrix for a particular spectrum model
|
||||
/// </summary>
|
||||
string[] KeyboardMatrix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Other keyboard keys that are not in the matrix
|
||||
/// (usually keys derived from key combos)
|
||||
/// </summary>
|
||||
string[] NonMatrixKeys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Represents the spectrum key state
|
||||
/// </summary>
|
||||
int[] KeyLine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resets the line status
|
||||
/// </summary>
|
||||
void ResetLineStatus();
|
||||
|
||||
/// <summary>
|
||||
/// There are some slight differences in how PortIN and PortOUT functions
|
||||
/// between Issue2 and Issue3 keyboards (16k/48k spectrum only)
|
||||
/// It is possible that some very old games require Issue2 emulation
|
||||
/// </summary>
|
||||
bool IsIssue2Keyboard { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the spectrum key status
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
void SetKeyStatus(string key, bool isPressed);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status of a spectrum key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
bool GetKeyStatus(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the query byte
|
||||
/// </summary>
|
||||
/// <param name="lines"></param>
|
||||
/// <returns></returns>
|
||||
byte GetLineStatus(byte lines);
|
||||
|
||||
/// <summary>
|
||||
/// Reads a keyboard byte
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
byte ReadKeyboardByte(ushort addr);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a key in the keyboard matrix and returns the relevent byte value
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
byte GetByteFromKeyMatrix(string key);
|
||||
|
||||
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a PSG device (in this case an AY-3-891x)
|
||||
/// </summary>
|
||||
public interface IPSG : ISoundProvider, IPortIODevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Initlization routine
|
||||
/// </summary>
|
||||
/// <param name="sampleRate"></param>
|
||||
/// <param name="tStatesPerFrame"></param>
|
||||
void Init(int sampleRate, int tStatesPerFrame);
|
||||
|
||||
/// <summary>
|
||||
/// Activates a register
|
||||
/// </summary>
|
||||
int SelectedRegister { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes to the PSG
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
void PortWrite(int value);
|
||||
|
||||
/// <summary>
|
||||
/// Reads from the PSG
|
||||
/// </summary>
|
||||
int PortRead();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets the PSG
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Called at the start of a frame
|
||||
/// </summary>
|
||||
void StartFrame();
|
||||
|
||||
/// <summary>
|
||||
/// called at the end of a frame
|
||||
/// </summary>
|
||||
void EndFrame();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the sound based on number of frame cycles
|
||||
/// </summary>
|
||||
/// <param name="frameCycle"></param>
|
||||
void UpdateSound(int frameCycle);
|
||||
|
||||
/// <summary>
|
||||
/// IStatable serialization
|
||||
/// </summary>
|
||||
/// <param name="ser"></param>
|
||||
void SyncState(Serializer ser);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a device that utilizes port IN & OUT
|
||||
/// </summary>
|
||||
public interface IPortIODevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Device responds to an IN instruction
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
bool ReadPort(ushort port, ref int result);
|
||||
|
||||
/// <summary>
|
||||
/// Device responds to an OUT instruction
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
bool WritePort(ushort port, int result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,876 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the tape device (or build-in datacorder as it was called +2 and above)
|
||||
/// </summary>
|
||||
public class DatacorderDevice : IPortIODevice
|
||||
{
|
||||
#region Construction
|
||||
|
||||
private SpectrumBase _machine { get; set; }
|
||||
private Z80A _cpu { get; set; }
|
||||
private IBeeperDevice _buzzer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public DatacorderDevice()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the datacorder device
|
||||
/// </summary>
|
||||
/// <param name="machine"></param>
|
||||
public void Init(SpectrumBase machine)
|
||||
{
|
||||
_machine = machine;
|
||||
_cpu = _machine.CPU;
|
||||
_buzzer = machine.BuzzerDevice;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Information
|
||||
|
||||
/// <summary>
|
||||
/// The index of the current tape data block that is loaded
|
||||
/// </summary>
|
||||
private int _currentDataBlockIndex = 0;
|
||||
public int CurrentDataBlockIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dataBlocks.Count() > 0) { return _currentDataBlockIndex; }
|
||||
else { return -1; }
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == _currentDataBlockIndex) { return; }
|
||||
if (value < _dataBlocks.Count() && value >= 0)
|
||||
{
|
||||
_currentDataBlockIndex = value;
|
||||
_position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current position within the current data block
|
||||
/// </summary>
|
||||
private int _position = 0;
|
||||
public int Position
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count) { return 0; }
|
||||
else { return _position; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether the tape is currently playing or not
|
||||
/// </summary>
|
||||
private bool _tapeIsPlaying = false;
|
||||
public bool TapeIsPlaying
|
||||
{
|
||||
get { return _tapeIsPlaying; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of the currently loaded data blocks
|
||||
/// </summary>
|
||||
private List<TapeDataBlock> _dataBlocks = new List<TapeDataBlock>();
|
||||
public List<TapeDataBlock> DataBlocks
|
||||
{
|
||||
get { return _dataBlocks; }
|
||||
set { _dataBlocks = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the last CPU t-state value
|
||||
/// </summary>
|
||||
private long _lastCycle = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Edge
|
||||
/// </summary>
|
||||
private int _waitEdge = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Current tapebit state
|
||||
/// </summary>
|
||||
private bool currentState = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Datacorder Device Settings
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether the device should autodetect when the Z80 has entered into
|
||||
/// 'load' mode and auto-play the tape if neccesary
|
||||
/// </summary>
|
||||
private bool _autoPlay;
|
||||
public bool AutoPlay
|
||||
{
|
||||
get { return _machine.Spectrum.Settings.AutoLoadTape; }
|
||||
set { _autoPlay = value; MonitorReset(); }
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Emulator
|
||||
|
||||
/// <summary>
|
||||
/// Should be fired at the end of every frame
|
||||
/// Primary purpose is to detect tape traps and manage auto play (if/when this is ever implemented)
|
||||
/// </summary>
|
||||
public void EndFrame()
|
||||
{
|
||||
MonitorFrame();
|
||||
}
|
||||
|
||||
public void StartFrame()
|
||||
{
|
||||
//if (TapeIsPlaying && AutoPlay)
|
||||
//FlashLoad();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape Controls
|
||||
|
||||
/// <summary>
|
||||
/// Starts the tape playing from the beginning of the current block
|
||||
/// </summary>
|
||||
public void Play()
|
||||
{
|
||||
if (_tapeIsPlaying)
|
||||
return;
|
||||
|
||||
_machine.BuzzerDevice.SetTapeMode(true);
|
||||
|
||||
_machine.Spectrum.OSD_TapePlaying();
|
||||
|
||||
// update the lastCycle
|
||||
_lastCycle = _cpu.TotalExecutedCycles;
|
||||
|
||||
// reset waitEdge and position
|
||||
_waitEdge = 0;
|
||||
_position = 0;
|
||||
|
||||
if (
|
||||
_dataBlocks.Count > 0 && // data blocks are present &&
|
||||
_currentDataBlockIndex >= 0 // the current data block index is 1 or greater
|
||||
)
|
||||
{
|
||||
while (_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count)
|
||||
{
|
||||
// we are at the end of a data block - move to the next
|
||||
_position = 0;
|
||||
_currentDataBlockIndex++;
|
||||
|
||||
// are we at the end of the tape?
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for end of tape
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count)
|
||||
{
|
||||
// end of tape reached. Rewind to beginning
|
||||
RTZ();
|
||||
return;
|
||||
}
|
||||
|
||||
// update waitEdge with the current position in the current block
|
||||
_waitEdge = _dataBlocks[_currentDataBlockIndex].DataPeriods[_position];
|
||||
|
||||
// sign that the tape is now playing
|
||||
_tapeIsPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the tape
|
||||
/// (should move to the beginning of the next block)
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (!_tapeIsPlaying)
|
||||
return;
|
||||
|
||||
_machine.BuzzerDevice.SetTapeMode(false);
|
||||
|
||||
_machine.Spectrum.OSD_TapeStopped();
|
||||
|
||||
// sign that the tape is no longer playing
|
||||
_tapeIsPlaying = false;
|
||||
|
||||
if (
|
||||
_currentDataBlockIndex >= 0 && // we are at datablock 1 or above
|
||||
_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count - 1 // the block is still playing back
|
||||
)
|
||||
{
|
||||
// move to the next block
|
||||
_currentDataBlockIndex++;
|
||||
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count())
|
||||
{
|
||||
_currentDataBlockIndex = -1;
|
||||
}
|
||||
|
||||
// reset waitEdge and position
|
||||
_waitEdge = 0;
|
||||
_position = 0;
|
||||
|
||||
if (
|
||||
_currentDataBlockIndex < 0 && // block index is -1
|
||||
_dataBlocks.Count() > 0 // number of blocks is greater than 0
|
||||
)
|
||||
{
|
||||
// move the index on to 0
|
||||
_currentDataBlockIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// update the lastCycle
|
||||
_lastCycle = _cpu.TotalExecutedCycles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rewinds the tape to it's beginning (return to zero)
|
||||
/// </summary>
|
||||
public void RTZ()
|
||||
{
|
||||
Stop();
|
||||
_machine.Spectrum.OSD_TapeRTZ();
|
||||
_currentDataBlockIndex = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a block skip operation on the current tape
|
||||
/// TRUE: skip forward
|
||||
/// FALSE: skip backward
|
||||
/// </summary>
|
||||
/// <param name="skipForward"></param>
|
||||
public void SkipBlock(bool skipForward)
|
||||
{
|
||||
int blockCount = _dataBlocks.Count;
|
||||
int targetBlockId = _currentDataBlockIndex;
|
||||
|
||||
if (skipForward)
|
||||
{
|
||||
if (_currentDataBlockIndex == blockCount - 1)
|
||||
{
|
||||
// last block, go back to beginning
|
||||
targetBlockId = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetBlockId++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentDataBlockIndex == 0)
|
||||
{
|
||||
// already first block, goto last block
|
||||
targetBlockId = blockCount - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetBlockId--;
|
||||
}
|
||||
}
|
||||
|
||||
var bl = _dataBlocks[targetBlockId];
|
||||
|
||||
StringBuilder sbd = new StringBuilder();
|
||||
sbd.Append("(");
|
||||
sbd.Append((targetBlockId + 1) + " of " + _dataBlocks.Count());
|
||||
sbd.Append(") : ");
|
||||
//sbd.Append("ID" + bl.BlockID.ToString("X2") + " - ");
|
||||
sbd.Append(bl.BlockDescription);
|
||||
if (bl.MetaData.Count > 0)
|
||||
{
|
||||
sbd.Append(" - ");
|
||||
sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value);
|
||||
//sbd.Append("\n");
|
||||
//sbd.Append(bl.MetaData.Skip(1).First().Key + ": " + bl.MetaData.Skip(1).First().Value);
|
||||
}
|
||||
|
||||
if (skipForward)
|
||||
_machine.Spectrum.OSD_TapeNextBlock(sbd.ToString());
|
||||
else
|
||||
_machine.Spectrum.OSD_TapePrevBlock(sbd.ToString());
|
||||
|
||||
CurrentDataBlockIndex = targetBlockId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new tape and sets up the tape device accordingly
|
||||
/// </summary>
|
||||
/// <param name="tapeData"></param>
|
||||
public void LoadTape(byte[] tapeData)
|
||||
{
|
||||
// attempt TZX deserialization
|
||||
TzxSerializer tzxSer = new TzxSerializer(this);
|
||||
try
|
||||
{
|
||||
tzxSer.DeSerialize(tapeData);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TAP format not detected
|
||||
var e = ex;
|
||||
}
|
||||
|
||||
// attempt TAP deserialization
|
||||
TapSerializer tapSer = new TapSerializer(this);
|
||||
try
|
||||
{
|
||||
tapSer.DeSerialize(tapeData);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TAP format not detected
|
||||
var e = ex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the tape
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
RTZ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tape Device Methods
|
||||
|
||||
/// <summary>
|
||||
/// Simulates the spectrum 'EAR' input reading data from the tape
|
||||
/// </summary>
|
||||
/// <param name="cpuCycles"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetEarBit(long cpuCycle)
|
||||
{
|
||||
// decide how many cycles worth of data we are capturing
|
||||
long cycles = cpuCycle - _lastCycle;
|
||||
|
||||
bool is48k = _machine.IsIn48kMode();
|
||||
|
||||
// check whether tape is actually playing
|
||||
if (_tapeIsPlaying == false)
|
||||
{
|
||||
// it's not playing. Update lastCycle and return
|
||||
_lastCycle = cpuCycle;
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for end of tape
|
||||
if (_currentDataBlockIndex < 0)
|
||||
{
|
||||
// end of tape reached - RTZ (and stop)
|
||||
RTZ();
|
||||
return currentState;
|
||||
}
|
||||
|
||||
// process the cycles based on the waitEdge
|
||||
while (cycles >= _waitEdge)
|
||||
{
|
||||
// decrement cycles
|
||||
cycles -= _waitEdge;
|
||||
|
||||
// flip the current state
|
||||
currentState = !currentState;
|
||||
|
||||
if (_position == 0 && _tapeIsPlaying)
|
||||
{
|
||||
// start of block
|
||||
|
||||
// notify about the current block
|
||||
var bl = _dataBlocks[_currentDataBlockIndex];
|
||||
|
||||
StringBuilder sbd = new StringBuilder();
|
||||
sbd.Append("(");
|
||||
sbd.Append((_currentDataBlockIndex + 1) + " of " + _dataBlocks.Count());
|
||||
sbd.Append(") : ");
|
||||
//sbd.Append("ID" + bl.BlockID.ToString("X2") + " - ");
|
||||
sbd.Append(bl.BlockDescription);
|
||||
if (bl.MetaData.Count > 0)
|
||||
{
|
||||
sbd.Append(" - ");
|
||||
sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value);
|
||||
}
|
||||
_machine.Spectrum.OSD_TapePlayingBlockInfo(sbd.ToString());
|
||||
}
|
||||
|
||||
|
||||
// increment the current period position
|
||||
_position++;
|
||||
|
||||
if (_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count())
|
||||
{
|
||||
// we have reached the end of the current block
|
||||
|
||||
if (_dataBlocks[_currentDataBlockIndex].DataPeriods.Count() == 0)
|
||||
{
|
||||
// notify about the current block (we are skipping it because its empty)
|
||||
var bl = _dataBlocks[_currentDataBlockIndex];
|
||||
StringBuilder sbd = new StringBuilder();
|
||||
sbd.Append("(");
|
||||
sbd.Append((_currentDataBlockIndex + 1) + " of " + _dataBlocks.Count());
|
||||
sbd.Append(") : ");
|
||||
//sbd.Append("ID" + bl.BlockID.ToString("X2") + " - ");
|
||||
sbd.Append(bl.BlockDescription);
|
||||
if (bl.MetaData.Count > 0)
|
||||
{
|
||||
sbd.Append(" - ");
|
||||
sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value);
|
||||
}
|
||||
_machine.Spectrum.OSD_TapePlayingSkipBlockInfo(sbd.ToString());
|
||||
|
||||
}
|
||||
|
||||
// skip any empty blocks (and process any command blocks)
|
||||
while (_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count())
|
||||
{
|
||||
// check for any commands
|
||||
var command = _dataBlocks[_currentDataBlockIndex].Command;
|
||||
var block = _dataBlocks[_currentDataBlockIndex];
|
||||
bool shouldStop = false;
|
||||
switch (command)
|
||||
{
|
||||
// Stop the tape command found - if this is the end of the tape RTZ
|
||||
// otherwise just STOP and move to the next block
|
||||
case TapeCommand.STOP_THE_TAPE:
|
||||
|
||||
_machine.Spectrum.OSD_TapeStoppedAuto();
|
||||
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count())
|
||||
RTZ();
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
_monitorTimeOut = 2000;
|
||||
|
||||
break;
|
||||
case TapeCommand.STOP_THE_TAPE_48K:
|
||||
if (is48k)
|
||||
{
|
||||
_machine.Spectrum.OSD_TapeStoppedAuto();
|
||||
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count())
|
||||
RTZ();
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
_monitorTimeOut = 2000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shouldStop)
|
||||
break;
|
||||
|
||||
_position = 0;
|
||||
_currentDataBlockIndex++;
|
||||
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for end of tape
|
||||
if (_currentDataBlockIndex >= _dataBlocks.Count())
|
||||
{
|
||||
_currentDataBlockIndex = -1;
|
||||
RTZ();
|
||||
return currentState;
|
||||
}
|
||||
}
|
||||
|
||||
// update waitEdge with current position within the current block
|
||||
_waitEdge = _dataBlocks[_currentDataBlockIndex].DataPeriods[_position];
|
||||
|
||||
}
|
||||
|
||||
// update lastCycle and return currentstate
|
||||
_lastCycle = cpuCycle - (long)cycles;
|
||||
|
||||
// play the buzzer
|
||||
_buzzer.ProcessPulseValue(false, currentState);
|
||||
|
||||
return currentState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flash loading implementation
|
||||
/// (Deterministic Emulation must be FALSE)
|
||||
/// </summary>
|
||||
private bool FlashLoad()
|
||||
{
|
||||
// deterministic emulation must = false
|
||||
//if (_machine.Spectrum.SyncSettings.DeterministicEmulation)
|
||||
//return;
|
||||
|
||||
var util = _machine.Spectrum;
|
||||
|
||||
if (_currentDataBlockIndex < 0)
|
||||
_currentDataBlockIndex = 0;
|
||||
|
||||
if (_currentDataBlockIndex >= DataBlocks.Count)
|
||||
return false;
|
||||
|
||||
//var val = GetEarBit(_cpu.TotalExecutedCycles);
|
||||
//_buzzer.ProcessPulseValue(true, val);
|
||||
|
||||
ushort addr = _cpu.RegPC;
|
||||
|
||||
if (_machine.Spectrum.SyncSettings.DeterministicEmulation)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
var tb = DataBlocks[_currentDataBlockIndex];
|
||||
var tData = tb.BlockData;
|
||||
|
||||
if (tData == null || tData.Length < 2)
|
||||
{
|
||||
// skip this
|
||||
return false;
|
||||
}
|
||||
|
||||
var toRead = tData.Length - 1;
|
||||
|
||||
if (toRead < _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
toRead = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8);
|
||||
}
|
||||
|
||||
if (toRead <= 0)
|
||||
return false;
|
||||
|
||||
var parity = tData[0];
|
||||
|
||||
if (parity != _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8) >> 8)
|
||||
return false;
|
||||
|
||||
util.SetCpuRegister("Shadow AF", 0x0145);
|
||||
|
||||
for (var i = 0; i < toRead; i++)
|
||||
{
|
||||
var v = tData[i + 1];
|
||||
_cpu.Regs[_cpu.L] = v;
|
||||
parity ^= v;
|
||||
var d = (ushort)(_cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8) + 1);
|
||||
_machine.WriteBus(d, v);
|
||||
}
|
||||
var pc = (ushort)0x05DF;
|
||||
|
||||
if (_cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8) == toRead &&
|
||||
toRead + 1 < tData.Length)
|
||||
{
|
||||
var v = tData[toRead + 1];
|
||||
_cpu.Regs[_cpu.L] = v;
|
||||
parity ^= v;
|
||||
_cpu.Regs[_cpu.B] = 0xB0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpu.Regs[_cpu.L] = 1;
|
||||
_cpu.Regs[_cpu.B] = 0;
|
||||
_cpu.Regs[_cpu.F] = 0x50;
|
||||
_cpu.Regs[_cpu.A] = parity;
|
||||
pc = 0x05EE;
|
||||
}
|
||||
|
||||
_cpu.Regs[_cpu.H] = parity;
|
||||
var de = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8);
|
||||
util.SetCpuRegister("DE", de - toRead);
|
||||
var ix = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8);
|
||||
util.SetCpuRegister("IX", ix + toRead);
|
||||
|
||||
util.SetCpuRegister("PC", pc);
|
||||
|
||||
_currentDataBlockIndex++;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TapeMonitor
|
||||
|
||||
private long _lastINCycle = 0;
|
||||
private int _monitorCount;
|
||||
private int _monitorTimeOut;
|
||||
private ushort _monitorLastPC;
|
||||
private ushort[] _monitorLastRegs = new ushort[7];
|
||||
|
||||
/// <summary>
|
||||
/// Resets the TapeMonitor
|
||||
/// </summary>
|
||||
private void MonitorReset()
|
||||
{
|
||||
_lastINCycle = 0;
|
||||
_monitorCount = 0;
|
||||
_monitorLastPC = 0;
|
||||
_monitorLastRegs = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An iteration of the monitor process
|
||||
/// </summary>
|
||||
public void MonitorRead()
|
||||
{
|
||||
long cpuCycle = _cpu.TotalExecutedCycles;
|
||||
int delta = (int)(cpuCycle - _lastINCycle);
|
||||
_lastINCycle = cpuCycle;
|
||||
|
||||
var nRegs = new ushort[]
|
||||
{
|
||||
_cpu.Regs[_cpu.A],
|
||||
_cpu.Regs[_cpu.B],
|
||||
_cpu.Regs[_cpu.C],
|
||||
_cpu.Regs[_cpu.D],
|
||||
_cpu.Regs[_cpu.E],
|
||||
_cpu.Regs[_cpu.H],
|
||||
_cpu.Regs[_cpu.L]
|
||||
};
|
||||
|
||||
if (delta > 0 &&
|
||||
delta < 96 &&
|
||||
_cpu.RegPC == _monitorLastPC &&
|
||||
_monitorLastRegs != null)
|
||||
{
|
||||
int dCnt = 0;
|
||||
int dVal = 0;
|
||||
|
||||
for (int i = 0; i < nRegs.Length; i++)
|
||||
{
|
||||
if (_monitorLastRegs[i] != nRegs[i])
|
||||
{
|
||||
dVal = _monitorLastRegs[i] - nRegs[i];
|
||||
dCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dCnt == 1 &&
|
||||
(dVal == 1 || dVal == -1))
|
||||
{
|
||||
_monitorCount++;
|
||||
|
||||
if (_monitorCount >= 16 && _cpu.RegPC == 1523 && _machine.Spectrum.Settings.AutoLoadTape)
|
||||
{
|
||||
if (!_tapeIsPlaying)
|
||||
{
|
||||
Play();
|
||||
_machine.Spectrum.OSD_TapePlayingAuto();
|
||||
}
|
||||
|
||||
_monitorTimeOut = 250;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_monitorCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_monitorLastRegs = nRegs;
|
||||
_monitorLastPC = _cpu.RegPC;
|
||||
}
|
||||
|
||||
public void AutoStopTape()
|
||||
{
|
||||
if (_tapeIsPlaying)
|
||||
return;
|
||||
|
||||
if (!_machine.Spectrum.Settings.AutoLoadTape)
|
||||
return;
|
||||
|
||||
Stop();
|
||||
_machine.Spectrum.OSD_TapeStoppedAuto();
|
||||
}
|
||||
|
||||
public void AutoStartTape()
|
||||
{
|
||||
if (_tapeIsPlaying)
|
||||
return;
|
||||
|
||||
if (!_machine.Spectrum.Settings.AutoLoadTape)
|
||||
return;
|
||||
|
||||
Play();
|
||||
_machine.Spectrum.OSD_TapePlayingAuto();
|
||||
}
|
||||
|
||||
private void MonitorFrame()
|
||||
{
|
||||
if (_tapeIsPlaying && _machine.Spectrum.Settings.AutoLoadTape)
|
||||
{
|
||||
_monitorTimeOut--;
|
||||
|
||||
if (_monitorTimeOut < 0)
|
||||
{
|
||||
// does not work properly - disabled for now (handled elsewhere)
|
||||
|
||||
//Stop();
|
||||
//_machine.Spectrum.OSD_TapeStoppedAuto();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IPortIODevice
|
||||
|
||||
/// <summary>
|
||||
/// Mask constants
|
||||
/// </summary>
|
||||
private const int TAPE_BIT = 0x40;
|
||||
private const int EAR_BIT = 0x10;
|
||||
private const int MIC_BIT = 0x08;
|
||||
|
||||
/// <summary>
|
||||
/// Device responds to an IN instruction
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadPort(ushort port, ref int result)
|
||||
{
|
||||
if (TapeIsPlaying)
|
||||
{
|
||||
GetEarBit(_cpu.TotalExecutedCycles);
|
||||
}
|
||||
if (currentState)
|
||||
{
|
||||
result |= TAPE_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
result &= ~TAPE_BIT;
|
||||
}
|
||||
|
||||
MonitorRead();
|
||||
|
||||
/*
|
||||
|
||||
if (TapeIsPlaying)
|
||||
{
|
||||
if (GetEarBit(_cpu.TotalExecutedCycles))
|
||||
{
|
||||
result &= ~(TAPE_BIT); // reset is EAR ON
|
||||
}
|
||||
else
|
||||
{
|
||||
result |= (TAPE_BIT); // set is EAR Off
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_machine.KeyboardDevice.IsIssue2Keyboard)
|
||||
{
|
||||
if ((_machine.LASTULAOutByte & (EAR_BIT + MIC_BIT)) == 0)
|
||||
{
|
||||
result &= ~(TAPE_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
result |= (TAPE_BIT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_machine.LASTULAOutByte & EAR_BIT) == 0)
|
||||
{
|
||||
result &= ~(TAPE_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
result |= TAPE_BIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Device responds to an OUT instruction
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool WritePort(ushort port, int result)
|
||||
{
|
||||
if (!TapeIsPlaying)
|
||||
{
|
||||
currentState = ((byte)result & 0x10) != 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Serialization
|
||||
|
||||
/// <summary>
|
||||
/// Bizhawk state serialization
|
||||
/// </summary>
|
||||
/// <param name="ser"></param>
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("DatacorderDevice");
|
||||
ser.Sync("_currentDataBlockIndex", ref _currentDataBlockIndex);
|
||||
ser.Sync("_position", ref _position);
|
||||
ser.Sync("_tapeIsPlaying", ref _tapeIsPlaying);
|
||||
ser.Sync("_lastCycle", ref _lastCycle);
|
||||
ser.Sync("_waitEdge", ref _waitEdge);
|
||||
ser.Sync("currentState", ref currentState);
|
||||
ser.Sync("_lastINCycle", ref _lastINCycle);
|
||||
ser.Sync("_monitorCount", ref _monitorCount);
|
||||
ser.Sync("_monitorTimeOut", ref _monitorTimeOut);
|
||||
ser.Sync("_monitorLastPC", ref _monitorLastPC);
|
||||
ser.Sync("_monitorLastRegs", ref _monitorLastRegs, false);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Cursor joystick
|
||||
/// Maps to a combination of 0xf7fe and 0xeffe
|
||||
/// </summary>
|
||||
public class CursorJoystick : IJoystick
|
||||
{
|
||||
private int _joyLine;
|
||||
private SpectrumBase _machine;
|
||||
|
||||
#region Construction
|
||||
|
||||
public CursorJoystick(SpectrumBase machine, int playerNumber)
|
||||
{
|
||||
_machine = machine;
|
||||
_joyLine = 0;
|
||||
_playerNumber = playerNumber;
|
||||
|
||||
ButtonCollection = new List<string>
|
||||
{
|
||||
"P" + _playerNumber + " Left",
|
||||
"P" + _playerNumber + " Right",
|
||||
"P" + _playerNumber + " Down",
|
||||
"P" + _playerNumber + " Up",
|
||||
"P" + _playerNumber + " Button",
|
||||
}.ToArray();
|
||||
}
|
||||
|
||||
private List<string> btnLookups = new List<string>
|
||||
{
|
||||
"Key 5", // left
|
||||
"Key 8", // right
|
||||
"Key 6", // down
|
||||
"Key 7", // up
|
||||
"Key 0", // fire
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region IJoystick
|
||||
|
||||
public JoystickType JoyType => JoystickType.Cursor;
|
||||
|
||||
public string[] ButtonCollection { get; set; }
|
||||
|
||||
private int _playerNumber;
|
||||
public int PlayerNumber
|
||||
{
|
||||
get { return _playerNumber; }
|
||||
set { _playerNumber = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joystick line based on key pressed
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
public void SetJoyInput(string key, bool isPressed)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
|
||||
if (isPressed)
|
||||
{
|
||||
_machine.KeyboardDevice.SetKeyStatus(btnLookups[pos], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_machine.KeyboardDevice.GetKeyStatus(btnLookups[pos]))
|
||||
{
|
||||
// key is already pressed elswhere - leave it as is
|
||||
}
|
||||
else
|
||||
{
|
||||
// key is safe to unpress
|
||||
_machine.KeyboardDevice.SetKeyStatus(btnLookups[pos], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of a particular joystick binding
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetJoyInput(string key)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
if (_machine == null)
|
||||
return false;
|
||||
|
||||
var l = _machine.KeyboardDevice.GetKeyStatus(btnLookups[pos]);
|
||||
return l;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bit position of a particular joystick binding from the matrix
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public int GetBitPos(string key)
|
||||
{
|
||||
int index = Array.IndexOf(ButtonCollection, key);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public class KempstonJoystick : IJoystick
|
||||
{
|
||||
private int _joyLine;
|
||||
private SpectrumBase _machine;
|
||||
|
||||
#region Construction
|
||||
|
||||
public KempstonJoystick(SpectrumBase machine, int playerNumber)
|
||||
{
|
||||
_machine = machine;
|
||||
_joyLine = 0;
|
||||
_playerNumber = playerNumber;
|
||||
|
||||
ButtonCollection = new List<string>
|
||||
{
|
||||
"P" + _playerNumber + " Right",
|
||||
"P" + _playerNumber + " Left",
|
||||
"P" + _playerNumber + " Down",
|
||||
"P" + _playerNumber + " Up",
|
||||
"P" + _playerNumber + " Button",
|
||||
}.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IJoystick
|
||||
|
||||
public JoystickType JoyType => JoystickType.Kempston;
|
||||
|
||||
public string[] ButtonCollection { get; set; }
|
||||
|
||||
private int _playerNumber;
|
||||
public int PlayerNumber
|
||||
{
|
||||
get { return _playerNumber; }
|
||||
set { _playerNumber = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joystick line based on key pressed
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
public void SetJoyInput(string key, bool isPressed)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
if (isPressed)
|
||||
_joyLine |= (1 << pos);
|
||||
else
|
||||
_joyLine &= ~(1 << pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of a particular joystick binding
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetJoyInput(string key)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
return (_joyLine & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Active bits high
|
||||
/// 0 0 0 F U D L R
|
||||
/// </summary>
|
||||
public int JoyLine
|
||||
{
|
||||
get { return _joyLine; }
|
||||
set { _joyLine = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bit position of a particular joystick binding from the matrix
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public int GetBitPos(string key)
|
||||
{
|
||||
int index = Array.IndexOf(ButtonCollection, key);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public readonly string[] _bitPos = new string[]
|
||||
{
|
||||
"P1 Right",
|
||||
"P1 Left",
|
||||
"P1 Down",
|
||||
"P1 Up",
|
||||
"P1 Button"
|
||||
};
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// A null joystick object
|
||||
/// </summary>
|
||||
public class NullJoystick : IJoystick
|
||||
{
|
||||
private int _joyLine;
|
||||
private SpectrumBase _machine;
|
||||
|
||||
#region Construction
|
||||
|
||||
public NullJoystick(SpectrumBase machine, int playerNumber)
|
||||
{
|
||||
_machine = machine;
|
||||
_joyLine = 0;
|
||||
_playerNumber = playerNumber;
|
||||
|
||||
ButtonCollection = new List<string>
|
||||
{
|
||||
|
||||
}.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IJoystick
|
||||
|
||||
public JoystickType JoyType => JoystickType.NULL;
|
||||
|
||||
public string[] ButtonCollection { get; set; }
|
||||
|
||||
private int _playerNumber;
|
||||
public int PlayerNumber
|
||||
{
|
||||
get { return _playerNumber; }
|
||||
set { _playerNumber = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joystick line based on key pressed
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
public void SetJoyInput(string key, bool isPressed)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
if (isPressed)
|
||||
_joyLine |= (1 << pos);
|
||||
else
|
||||
_joyLine &= ~(1 << pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of a particular joystick binding
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetJoyInput(string key)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
return (_joyLine & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Active bits high
|
||||
/// 0 0 0 F U D L R
|
||||
/// </summary>
|
||||
public int JoyLine
|
||||
{
|
||||
get { return _joyLine; }
|
||||
set { _joyLine = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bit position of a particular joystick binding from the matrix
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public int GetBitPos(string key)
|
||||
{
|
||||
int index = Array.IndexOf(ButtonCollection, key);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public readonly string[] _bitPos = new string[]
|
||||
{
|
||||
"P1 Right",
|
||||
"P1 Left",
|
||||
"P1 Down",
|
||||
"P1 Up",
|
||||
"P1 Button"
|
||||
};
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Sinclair Joystick LEFT
|
||||
/// Just maps to the standard keyboard and is read the same (from port 0xf7fe)
|
||||
/// </summary>
|
||||
public class SinclairJoystick1 : IJoystick
|
||||
{
|
||||
private int _joyLine;
|
||||
private SpectrumBase _machine;
|
||||
|
||||
#region Construction
|
||||
|
||||
public SinclairJoystick1(SpectrumBase machine, int playerNumber)
|
||||
{
|
||||
_machine = machine;
|
||||
_joyLine = 0;
|
||||
_playerNumber = playerNumber;
|
||||
|
||||
ButtonCollection = new List<string>
|
||||
{
|
||||
"P" + _playerNumber + " Left",
|
||||
"P" + _playerNumber + " Right",
|
||||
"P" + _playerNumber + " Down",
|
||||
"P" + _playerNumber + " Up",
|
||||
"P" + _playerNumber + " Button",
|
||||
}.ToArray();
|
||||
}
|
||||
|
||||
private List<string> btnLookups = new List<string>
|
||||
{
|
||||
"Key 1", // left
|
||||
"Key 2", // right
|
||||
"Key 3", // down
|
||||
"Key 4", // up
|
||||
"Key 5", // fire
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region IJoystick
|
||||
|
||||
public JoystickType JoyType => JoystickType.SinclairLEFT;
|
||||
|
||||
public string[] ButtonCollection { get; set; }
|
||||
|
||||
private int _playerNumber;
|
||||
public int PlayerNumber
|
||||
{
|
||||
get { return _playerNumber; }
|
||||
set { _playerNumber = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joystick line based on key pressed
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
public void SetJoyInput(string key, bool isPressed)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
|
||||
if (isPressed)
|
||||
{
|
||||
_machine.KeyboardDevice.SetKeyStatus(btnLookups[pos], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_machine.KeyboardDevice.GetKeyStatus(btnLookups[pos]))
|
||||
{
|
||||
// key is already pressed elswhere - leave it as is
|
||||
}
|
||||
else
|
||||
{
|
||||
// key is safe to unpress
|
||||
_machine.KeyboardDevice.SetKeyStatus(btnLookups[pos], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of a particular joystick binding
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetJoyInput(string key)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
if (_machine == null)
|
||||
return false;
|
||||
|
||||
return _machine.KeyboardDevice.GetKeyStatus(btnLookups[pos]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bit position of a particular joystick binding from the matrix
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public int GetBitPos(string key)
|
||||
{
|
||||
int index = Array.IndexOf(ButtonCollection, key);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Sinclair Joystick RIGHT
|
||||
/// Just maps to the standard keyboard and is read the same (from port 0xeffe)
|
||||
/// </summary>
|
||||
public class SinclairJoystick2 : IJoystick
|
||||
{
|
||||
private int _joyLine;
|
||||
private SpectrumBase _machine;
|
||||
|
||||
#region Construction
|
||||
|
||||
public SinclairJoystick2(SpectrumBase machine, int playerNumber)
|
||||
{
|
||||
_machine = machine;
|
||||
_joyLine = 0;
|
||||
_playerNumber = playerNumber;
|
||||
|
||||
ButtonCollection = new List<string>
|
||||
{
|
||||
"P" + _playerNumber + " Left",
|
||||
"P" + _playerNumber + " Right",
|
||||
"P" + _playerNumber + " Down",
|
||||
"P" + _playerNumber + " Up",
|
||||
"P" + _playerNumber + " Button",
|
||||
}.ToArray();
|
||||
}
|
||||
|
||||
private List<string> btnLookups = new List<string>
|
||||
{
|
||||
"Key 6", // left
|
||||
"Key 7", // right
|
||||
"Key 8", // down
|
||||
"Key 9", // up
|
||||
"Key 0", // fire
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region IJoystick
|
||||
|
||||
public JoystickType JoyType => JoystickType.SinclairRIGHT;
|
||||
|
||||
public string[] ButtonCollection { get; set; }
|
||||
|
||||
private int _playerNumber;
|
||||
public int PlayerNumber
|
||||
{
|
||||
get { return _playerNumber; }
|
||||
set { _playerNumber = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joystick line based on key pressed
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="isPressed"></param>
|
||||
public void SetJoyInput(string key, bool isPressed)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
|
||||
if (isPressed)
|
||||
{
|
||||
_machine.KeyboardDevice.SetKeyStatus(btnLookups[pos], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_machine.KeyboardDevice.GetKeyStatus(btnLookups[pos]))
|
||||
{
|
||||
// key is already pressed elswhere - leave it as is
|
||||
}
|
||||
else
|
||||
{
|
||||
// key is safe to unpress
|
||||
_machine.KeyboardDevice.SetKeyStatus(btnLookups[pos], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of a particular joystick binding
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetJoyInput(string key)
|
||||
{
|
||||
var pos = GetBitPos(key);
|
||||
if (_machine == null)
|
||||
return false;
|
||||
|
||||
return _machine.KeyboardDevice.GetKeyStatus(btnLookups[pos]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bit position of a particular joystick binding from the matrix
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public int GetBitPos(string key)
|
||||
{
|
||||
int index = Array.IndexOf(ButtonCollection, key);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The 48k keyboard device
|
||||
/// </summary>
|
||||
public class StandardKeyboard : IKeyboard
|
||||
{
|
||||
public SpectrumBase _machine { get; set; }
|
||||
private byte[] LineStatus;
|
||||
private string[] _keyboardMatrix;
|
||||
private int[] _keyLine;
|
||||
private bool _isIssue2Keyboard;
|
||||
private string[] _nonMatrixKeys;
|
||||
|
||||
public bool IsIssue2Keyboard
|
||||
{
|
||||
get { return _isIssue2Keyboard; }
|
||||
set { _isIssue2Keyboard = value; }
|
||||
}
|
||||
|
||||
public int[] KeyLine
|
||||
{
|
||||
get { return _keyLine; }
|
||||
set { _keyLine = value; }
|
||||
}
|
||||
|
||||
public string[] KeyboardMatrix
|
||||
{
|
||||
get { return _keyboardMatrix; }
|
||||
set { _keyboardMatrix = value; }
|
||||
}
|
||||
|
||||
public string[] NonMatrixKeys
|
||||
{
|
||||
get { return _nonMatrixKeys; }
|
||||
set { _nonMatrixKeys = value; }
|
||||
}
|
||||
|
||||
public StandardKeyboard(SpectrumBase machine)
|
||||
{
|
||||
_machine = machine;
|
||||
|
||||
KeyboardMatrix = new string[]
|
||||
{
|
||||
// 0xfefe - 0 - 4
|
||||
"Key Caps Shift", "Key Z", "Key X", "Key C", "Key V",
|
||||
// 0xfdfe - 5 - 9
|
||||
"Key A", "Key S", "Key D", "Key F", "Key G",
|
||||
// 0xfbfe - 10 - 14
|
||||
"Key Q", "Key W", "Key E", "Key R", "Key T",
|
||||
// 0xf7fe - 15 - 19
|
||||
"Key 1", "Key 2", "Key 3", "Key 4", "Key 5",
|
||||
// 0xeffe - 20 - 24
|
||||
"Key 0", "Key 9", "Key 8", "Key 7", "Key 6",
|
||||
// 0xdffe - 25 - 29
|
||||
"Key P", "Key O", "Key I", "Key U", "Key Y",
|
||||
// 0xbffe - 30 - 34
|
||||
"Key Return", "Key L", "Key K", "Key J", "Key H",
|
||||
// 0x7ffe - 35 - 39
|
||||
"Key Space", "Key Symbol Shift", "Key M", "Key N", "Key B"
|
||||
};
|
||||
|
||||
var nonMatrix = new List<string>();
|
||||
|
||||
foreach (var key in _machine.Spectrum.ZXSpectrumControllerDefinition.BoolButtons)
|
||||
{
|
||||
if (!KeyboardMatrix.Any(s => s == key))
|
||||
nonMatrix.Add(key);
|
||||
}
|
||||
|
||||
NonMatrixKeys = nonMatrix.ToArray();
|
||||
|
||||
LineStatus = new byte[8];
|
||||
_keyLine = new int[] { 255, 255, 255, 255, 255, 255, 255, 255 };
|
||||
IsIssue2Keyboard = true;
|
||||
}
|
||||
|
||||
public void SetKeyStatus(string key, bool isPressed)
|
||||
{
|
||||
int k = GetByteFromKeyMatrix(key);
|
||||
|
||||
if (k != 255)
|
||||
{
|
||||
var lineIndex = k / 5;
|
||||
var lineMask = 1 << k % 5;
|
||||
|
||||
_keyLine[lineIndex] = isPressed
|
||||
? (byte)(_keyLine[lineIndex] & ~lineMask)
|
||||
: (byte)(_keyLine[lineIndex] | lineMask);
|
||||
}
|
||||
|
||||
/*
|
||||
if (isPressed)
|
||||
{
|
||||
switch (k)
|
||||
{
|
||||
// 0xfefe - 0 - 4
|
||||
case 0: _keyLine[0] = (_keyLine[0] & ~(0x1)); break;
|
||||
case 1: _keyLine[0] = (_keyLine[0] & ~(0x02)); break;
|
||||
case 2: _keyLine[0] = (_keyLine[0] & ~(0x04)); break;
|
||||
case 3: _keyLine[0] = (_keyLine[0] & ~(0x08)); break;
|
||||
case 4: _keyLine[0] = (_keyLine[0] & ~(0x10)); break;
|
||||
// 0xfdfe - 5 - 9
|
||||
case 5: _keyLine[1] = (_keyLine[1] & ~(0x1)); break;
|
||||
case 6: _keyLine[1] = (_keyLine[1] & ~(0x02)); break;
|
||||
case 7: _keyLine[1] = (_keyLine[1] & ~(0x04)); break;
|
||||
case 8: _keyLine[1] = (_keyLine[1] & ~(0x08)); break;
|
||||
case 9: _keyLine[1] = (_keyLine[1] & ~(0x10)); break;
|
||||
// 0xfbfe - 10 - 14
|
||||
case 10: _keyLine[2] = (_keyLine[2] & ~(0x1)); break;
|
||||
case 11: _keyLine[2] = (_keyLine[2] & ~(0x02)); break;
|
||||
case 12: _keyLine[2] = (_keyLine[2] & ~(0x04)); break;
|
||||
case 13: _keyLine[2] = (_keyLine[2] & ~(0x08)); break;
|
||||
case 14: _keyLine[2] = (_keyLine[2] & ~(0x10)); break;
|
||||
// 0xf7fe - 15 - 19
|
||||
case 15: _keyLine[3] = (_keyLine[3] & ~(0x1)); break;
|
||||
case 16: _keyLine[3] = (_keyLine[3] & ~(0x02)); break;
|
||||
case 17: _keyLine[3] = (_keyLine[3] & ~(0x04)); break;
|
||||
case 18: _keyLine[3] = (_keyLine[3] & ~(0x08)); break;
|
||||
case 19: _keyLine[3] = (_keyLine[3] & ~(0x10)); break;
|
||||
// 0xeffe - 20 - 24
|
||||
case 20: _keyLine[4] = (_keyLine[4] & ~(0x1)); break;
|
||||
case 21: _keyLine[4] = (_keyLine[4] & ~(0x02)); break;
|
||||
case 22: _keyLine[4] = (_keyLine[4] & ~(0x04)); break;
|
||||
case 23: _keyLine[4] = (_keyLine[4] & ~(0x08)); break;
|
||||
case 24: _keyLine[4] = (_keyLine[4] & ~(0x10)); break;
|
||||
// 0xdffe - 25 - 29
|
||||
case 25: _keyLine[5] = (_keyLine[5] & ~(0x1)); break;
|
||||
case 26: _keyLine[5] = (_keyLine[5] & ~(0x02)); break;
|
||||
case 27: _keyLine[5] = (_keyLine[5] & ~(0x04)); break;
|
||||
case 28: _keyLine[5] = (_keyLine[5] & ~(0x08)); break;
|
||||
case 29: _keyLine[5] = (_keyLine[5] & ~(0x10)); break;
|
||||
// 0xbffe - 30 - 34
|
||||
case 30: _keyLine[6] = (_keyLine[6] & ~(0x1)); break;
|
||||
case 31: _keyLine[6] = (_keyLine[6] & ~(0x02)); break;
|
||||
case 32: _keyLine[6] = (_keyLine[6] & ~(0x04)); break;
|
||||
case 33: _keyLine[6] = (_keyLine[6] & ~(0x08)); break;
|
||||
case 34: _keyLine[6] = (_keyLine[6] & ~(0x10)); break;
|
||||
// 0x7ffe - 35 - 39
|
||||
case 35: _keyLine[7] = (_keyLine[7] & ~(0x1)); break;
|
||||
case 36: _keyLine[7] = (_keyLine[7] & ~(0x02)); break;
|
||||
case 37: _keyLine[7] = (_keyLine[7] & ~(0x04)); break;
|
||||
case 38: _keyLine[7] = (_keyLine[7] & ~(0x08)); break;
|
||||
case 39: _keyLine[7] = (_keyLine[7] & ~(0x10)); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (k)
|
||||
{
|
||||
// 0xfefe - 0 - 4
|
||||
case 0: _keyLine[0] = (_keyLine[0] | (0x1)); break;
|
||||
case 1: _keyLine[0] = (_keyLine[0] | (0x02)); break;
|
||||
case 2: _keyLine[0] = (_keyLine[0] | (0x04)); break;
|
||||
case 3: _keyLine[0] = (_keyLine[0] | (0x08)); break;
|
||||
case 4: _keyLine[0] = (_keyLine[0] | (0x10)); break;
|
||||
// 0xfdfe - 5 - 9
|
||||
case 5: _keyLine[1] = (_keyLine[1] | (0x1)); break;
|
||||
case 6: _keyLine[1] = (_keyLine[1] | (0x02)); break;
|
||||
case 7: _keyLine[1] = (_keyLine[1] | (0x04)); break;
|
||||
case 8: _keyLine[1] = (_keyLine[1] | (0x08)); break;
|
||||
case 9: _keyLine[1] = (_keyLine[1] | (0x10)); break;
|
||||
// 0xfbfe - 10 - 14
|
||||
case 10: _keyLine[2] = (_keyLine[2] | (0x1)); break;
|
||||
case 11: _keyLine[2] = (_keyLine[2] | (0x02)); break;
|
||||
case 12: _keyLine[2] = (_keyLine[2] | (0x04)); break;
|
||||
case 13: _keyLine[2] = (_keyLine[2] | (0x08)); break;
|
||||
case 14: _keyLine[2] = (_keyLine[2] | (0x10)); break;
|
||||
// 0xf7fe - 15 - 19
|
||||
case 15: _keyLine[3] = (_keyLine[3] | (0x1)); break;
|
||||
case 16: _keyLine[3] = (_keyLine[3] | (0x02)); break;
|
||||
case 17: _keyLine[3] = (_keyLine[3] | (0x04)); break;
|
||||
case 18: _keyLine[3] = (_keyLine[3] | (0x08)); break;
|
||||
case 19: _keyLine[3] = (_keyLine[3] | (0x10)); break;
|
||||
// 0xeffe - 20 - 24
|
||||
case 20: _keyLine[4] = (_keyLine[4] | (0x1)); break;
|
||||
case 21: _keyLine[4] = (_keyLine[4] | (0x02)); break;
|
||||
case 22: _keyLine[4] = (_keyLine[4] | (0x04)); break;
|
||||
case 23: _keyLine[4] = (_keyLine[4] | (0x08)); break;
|
||||
case 24: _keyLine[4] = (_keyLine[4] | (0x10)); break;
|
||||
// 0xdffe - 25 - 29
|
||||
case 25: _keyLine[5] = (_keyLine[5] | (0x1)); break;
|
||||
case 26: _keyLine[5] = (_keyLine[5] | (0x02)); break;
|
||||
case 27: _keyLine[5] = (_keyLine[5] | (0x04)); break;
|
||||
case 28: _keyLine[5] = (_keyLine[5] | (0x08)); break;
|
||||
case 29: _keyLine[5] = (_keyLine[5] | (0x10)); break;
|
||||
// 0xbffe - 30 - 34
|
||||
case 30: _keyLine[6] = (_keyLine[6] | (0x1)); break;
|
||||
case 31: _keyLine[6] = (_keyLine[6] | (0x02)); break;
|
||||
case 32: _keyLine[6] = (_keyLine[6] | (0x04)); break;
|
||||
case 33: _keyLine[6] = (_keyLine[6] | (0x08)); break;
|
||||
case 34: _keyLine[6] = (_keyLine[6] | (0x10)); break;
|
||||
// 0x7ffe - 35 - 39
|
||||
case 35: _keyLine[7] = (_keyLine[7] | (0x1)); break;
|
||||
case 36: _keyLine[7] = (_keyLine[7] | (0x02)); break;
|
||||
case 37: _keyLine[7] = (_keyLine[7] | (0x04)); break;
|
||||
case 38: _keyLine[7] = (_keyLine[7] | (0x08)); break;
|
||||
case 39: _keyLine[7] = (_keyLine[7] | (0x10)); break;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// Combination keys that are not in the keyboard matrix
|
||||
// but are available on the Spectrum+, 128k +2 & +3
|
||||
// (GetByteFromKeyMatrix() should return 255)
|
||||
// Processed after the matrix keys - only presses handled (unpressed get done above)
|
||||
if (k == 255)
|
||||
{
|
||||
if (isPressed)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
// Delete key (simulates Caps Shift + 0)
|
||||
case "Key Delete":
|
||||
_keyLine[0] = _keyLine[0] & ~(0x1);
|
||||
_keyLine[4] = _keyLine[4] & ~(0x1);
|
||||
break;
|
||||
// Cursor left (simulates Caps Shift + 5)
|
||||
case "Key Left Cursor":
|
||||
_keyLine[0] = _keyLine[0] & ~(0x1);
|
||||
_keyLine[3] = _keyLine[3] & ~(0x10);
|
||||
break;
|
||||
// Cursor right (simulates Caps Shift + 8)
|
||||
case "Key Right Cursor":
|
||||
_keyLine[0] = _keyLine[0] & ~(0x1);
|
||||
_keyLine[4] = _keyLine[4] & ~(0x04);
|
||||
break;
|
||||
// Cursor up (simulates Caps Shift + 7)
|
||||
case "Key Up Cursor":
|
||||
_keyLine[0] = _keyLine[0] & ~(0x1);
|
||||
_keyLine[4] = _keyLine[4] & ~(0x08);
|
||||
break;
|
||||
// Cursor down (simulates Caps Shift + 6)
|
||||
case "Key Down Cursor":
|
||||
_keyLine[0] = _keyLine[0] & ~(0x1);
|
||||
_keyLine[4] = _keyLine[4] & ~(0x10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetKeyStatus(string key)
|
||||
{
|
||||
byte keyByte = GetByteFromKeyMatrix(key);
|
||||
var lineIndex = keyByte / 5;
|
||||
var lineMask = 1 << keyByte % 5;
|
||||
|
||||
return (_keyLine[lineIndex] & lineMask) == 0;
|
||||
}
|
||||
|
||||
public void ResetLineStatus()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
for (int i = 0; i < KeyLine.Length; i++)
|
||||
KeyLine[i] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
public byte GetLineStatus(byte lines)
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
byte status = 0;
|
||||
lines = (byte)~lines;
|
||||
var lineIndex = 0;
|
||||
while (lines > 0)
|
||||
{
|
||||
if ((lines & 0x01) != 0)
|
||||
status |= (byte)_keyLine[lineIndex];
|
||||
lineIndex++;
|
||||
lines >>= 1;
|
||||
}
|
||||
var result = (byte)status;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
switch (lines)
|
||||
{
|
||||
case 0xfe: return (byte)KeyLine[0];
|
||||
case 0xfd: return (byte)KeyLine[1];
|
||||
case 0xfb: return (byte)KeyLine[2];
|
||||
case 0xf7: return (byte)KeyLine[3];
|
||||
case 0xef: return (byte)KeyLine[4];
|
||||
case 0xdf: return (byte)KeyLine[5];
|
||||
case 0xbf: return (byte)KeyLine[6];
|
||||
case 0x7f: return (byte)KeyLine[7];
|
||||
default: return 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public byte ReadKeyboardByte(ushort addr)
|
||||
{
|
||||
return GetLineStatus((byte)(addr >> 8));
|
||||
}
|
||||
|
||||
public byte GetByteFromKeyMatrix(string key)
|
||||
{
|
||||
int index = Array.IndexOf(KeyboardMatrix, key);
|
||||
return (byte)index;
|
||||
}
|
||||
|
||||
|
||||
#region IPortIODevice
|
||||
|
||||
/// <summary>
|
||||
/// Device responds to an IN instruction
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadPort(ushort port, ref int result)
|
||||
{
|
||||
/*
|
||||
The high byte indicates which half-row of keys is being polled
|
||||
A zero on one of these lines selects a particular half-row of five keys:
|
||||
|
||||
IN: Reads keys (bit 0 to bit 4 inclusive)
|
||||
0xfefe SHIFT, Z, X, C, V 0xeffe 0, 9, 8, 7, 6
|
||||
0xfdfe A, S, D, F, G 0xdffe P, O, I, U, Y
|
||||
0xfbfe Q, W, E, R, T 0xbffe ENTER, L, K, J, H
|
||||
0xf7fe 1, 2, 3, 4, 5 0x7ffe SPACE, SYM SHFT, M, N, B
|
||||
|
||||
A zero in one of the five lowest bits means that the corresponding key is pressed. If more than one address line
|
||||
is made low, the result is the logical AND of all single inputs, so a zero in a bit means that at least one of the
|
||||
appropriate keys is pressed. For example, only if each of the five lowest bits of the result from reading from Port 00FE
|
||||
(for instance by XOR A/IN A,(FE)) is one, no key is pressed
|
||||
*/
|
||||
|
||||
if ((port & 0x0001) != 0)
|
||||
return false;
|
||||
|
||||
if ((port & 0x8000) == 0)
|
||||
{
|
||||
result &= KeyLine[7];
|
||||
}
|
||||
|
||||
if ((port & 0x4000) == 0)
|
||||
{
|
||||
result &= KeyLine[6];
|
||||
}
|
||||
|
||||
if ((port & 0x2000) == 0)
|
||||
{
|
||||
result &= KeyLine[5];
|
||||
}
|
||||
|
||||
if ((port & 0x1000) == 0)
|
||||
{
|
||||
result &= KeyLine[4];
|
||||
}
|
||||
|
||||
if ((port & 0x800) == 0)
|
||||
{
|
||||
result &= KeyLine[3];
|
||||
}
|
||||
|
||||
if ((port & 0x400) == 0)
|
||||
{
|
||||
result &= KeyLine[2];
|
||||
}
|
||||
|
||||
if ((port & 0x200) == 0)
|
||||
{
|
||||
result &= KeyLine[1];
|
||||
}
|
||||
|
||||
if ((port & 0x100) == 0)
|
||||
{
|
||||
result &= KeyLine[0];
|
||||
}
|
||||
|
||||
// mask out lower 4 bits
|
||||
result = result & 0x1f;
|
||||
|
||||
// set bit 5 & 7 to 1
|
||||
result = result | 0xa0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Device responds to an OUT instruction
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool WritePort(ushort port, int result)
|
||||
{
|
||||
// not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Keyboard");
|
||||
ser.Sync("LineStatus", ref LineStatus, false);
|
||||
ser.Sync("_keyLine", ref _keyLine, false);
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
|
||||
public class RomData
|
||||
{
|
||||
/// <summary>
|
||||
/// ROM Contents
|
||||
/// </summary>
|
||||
public byte[] RomBytes
|
||||
{
|
||||
get { return _romBytes; }
|
||||
set { _romBytes = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Useful ROM addresses that are needed during tape operations
|
||||
/// </summary>
|
||||
public ushort SaveBytesRoutineAddress
|
||||
{
|
||||
get { return _saveBytesRoutineAddress; }
|
||||
set { _saveBytesRoutineAddress = value; }
|
||||
}
|
||||
public ushort LoadBytesRoutineAddress
|
||||
{
|
||||
get { return _loadBytesRoutineAddress; }
|
||||
set { _loadBytesRoutineAddress = value; }
|
||||
}
|
||||
public ushort SaveBytesResumeAddress
|
||||
{
|
||||
get { return _saveBytesResumeAddress; }
|
||||
set { _saveBytesResumeAddress = value; }
|
||||
}
|
||||
public ushort LoadBytesResumeAddress
|
||||
{
|
||||
get { return _loadBytesResumeAddress; }
|
||||
set { _loadBytesResumeAddress = value; }
|
||||
}
|
||||
public ushort LoadBytesInvalidHeaderAddress
|
||||
{
|
||||
get { return _loadBytesInvalidHeaderAddress; }
|
||||
set { _loadBytesInvalidHeaderAddress = value; }
|
||||
}
|
||||
|
||||
private byte[] _romBytes;
|
||||
private ushort _saveBytesRoutineAddress;
|
||||
private ushort _loadBytesRoutineAddress;
|
||||
private ushort _saveBytesResumeAddress;
|
||||
private ushort _loadBytesResumeAddress;
|
||||
private ushort _loadBytesInvalidHeaderAddress;
|
||||
|
||||
|
||||
public static RomData InitROM(MachineType machineType, byte[] rom)
|
||||
{
|
||||
RomData RD = new RomData();
|
||||
RD.RomBytes = new byte[rom.Length];
|
||||
RD.RomBytes = rom;
|
||||
|
||||
switch (machineType)
|
||||
{
|
||||
case MachineType.ZXSpectrum48:
|
||||
RD.SaveBytesRoutineAddress = 0x04C2;
|
||||
RD.SaveBytesResumeAddress = 0x0000;
|
||||
RD.LoadBytesRoutineAddress = 0x0808; //0x0556; //0x056C;
|
||||
RD.LoadBytesResumeAddress = 0x05E2;
|
||||
RD.LoadBytesInvalidHeaderAddress = 0x05B6;
|
||||
break;
|
||||
|
||||
case MachineType.ZXSpectrum128:
|
||||
RD.SaveBytesRoutineAddress = 0x04C2;
|
||||
RD.SaveBytesResumeAddress = 0x0000;
|
||||
RD.LoadBytesRoutineAddress = 0x0808; //0x0556; //0x056C;
|
||||
RD.LoadBytesResumeAddress = 0x05E2;
|
||||
RD.LoadBytesInvalidHeaderAddress = 0x05B6;
|
||||
break;
|
||||
}
|
||||
|
||||
return RD;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("RomData");
|
||||
ser.Sync("RomBytes", ref _romBytes, false);
|
||||
ser.Sync("_saveBytesRoutineAddress", ref _saveBytesRoutineAddress);
|
||||
ser.Sync("_loadBytesRoutineAddress", ref _loadBytesRoutineAddress);
|
||||
ser.Sync("_saveBytesResumeAddress", ref _saveBytesResumeAddress);
|
||||
ser.Sync("_loadBytesResumeAddress", ref _loadBytesResumeAddress);
|
||||
ser.Sync("_loadBytesInvalidHeaderAddress", ref _loadBytesInvalidHeaderAddress);
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,802 @@
|
|||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// AY-3-8912 Emulated Device
|
||||
///
|
||||
/// Based heavily on the YM-2149F / AY-3-8910 emulator used in Unreal Speccy
|
||||
/// (Originally created under Public Domain license by SMT jan.2006)
|
||||
///
|
||||
/// https://github.com/mkoloberdin/unrealspeccy/blob/master/sndrender/sndchip.cpp
|
||||
/// https://github.com/mkoloberdin/unrealspeccy/blob/master/sndrender/sndchip.h
|
||||
/// </summary>
|
||||
public class AYChip : IPSG
|
||||
{
|
||||
#region Device Fields
|
||||
|
||||
/// <summary>
|
||||
/// The emulated machine (passed in via constructor)
|
||||
/// </summary>
|
||||
private SpectrumBase _machine;
|
||||
|
||||
private int _tStatesPerFrame;
|
||||
private int _sampleRate;
|
||||
private int _samplesPerFrame;
|
||||
private int _tStatesPerSample;
|
||||
private short[] _audioBuffer;
|
||||
private int _audioBufferIndex;
|
||||
private int _lastStateRendered;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction & Initialization
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
public AYChip(SpectrumBase machine)
|
||||
{
|
||||
_machine = machine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises the AY chip
|
||||
/// </summary>
|
||||
public void Init(int sampleRate, int tStatesPerFrame)
|
||||
{
|
||||
InitTiming(sampleRate, tStatesPerFrame);
|
||||
UpdateVolume();
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IPortIODevice
|
||||
|
||||
public bool ReadPort(ushort port, ref int value)
|
||||
{
|
||||
if (port != 0xfffd)
|
||||
{
|
||||
// port read is not addressing this device
|
||||
return false;
|
||||
}
|
||||
|
||||
value = PortRead();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WritePort(ushort port, int value)
|
||||
{
|
||||
if (port == 0xfffd)
|
||||
{
|
||||
// register select
|
||||
SelectedRegister = value & 0x0f;
|
||||
return true;
|
||||
}
|
||||
else if (port == 0xbffd)
|
||||
{
|
||||
// Update the audiobuffer based on the current CPU cycle
|
||||
// (this process the previous data BEFORE writing to the currently selected register)
|
||||
int d = (int)(_machine.CurrentFrameCycle);
|
||||
BufferUpdate(d);
|
||||
|
||||
// write to register
|
||||
PortWrite(value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AY Implementation
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// AY mixer panning configuration
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum AYPanConfig
|
||||
{
|
||||
MONO = 0,
|
||||
ABC = 1,
|
||||
ACB = 2,
|
||||
BAC = 3,
|
||||
BCA = 4,
|
||||
CAB = 5,
|
||||
CBA = 6,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AY panning configuration
|
||||
/// </summary>
|
||||
public AYPanConfig PanningConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentPanTab;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _currentPanTab)
|
||||
{
|
||||
_currentPanTab = value;
|
||||
UpdateVolume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The AY chip output volume
|
||||
/// (0 - 100)
|
||||
/// </summary>
|
||||
public int Volume
|
||||
{
|
||||
get
|
||||
{
|
||||
return _volume;
|
||||
}
|
||||
set
|
||||
{
|
||||
value = Math.Max(0, value);
|
||||
value = Math.Max(100, value);
|
||||
if (_volume == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_volume = value;
|
||||
UpdateVolume();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The currently selected register
|
||||
/// </summary>
|
||||
public int SelectedRegister
|
||||
{
|
||||
get { return _activeRegister; }
|
||||
set
|
||||
{
|
||||
_activeRegister = (byte)value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Resets the PSG
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
/*
|
||||
_noiseVal = 0x0FFFF;
|
||||
_outABC = 0;
|
||||
_outNoiseABC = 0;
|
||||
_counterNoise = 0;
|
||||
_counterA = 0;
|
||||
_counterB = 0;
|
||||
_counterC = 0;
|
||||
_EnvelopeCounterBend = 0;
|
||||
|
||||
// clear all the registers
|
||||
for (int i = 0; i < 14; i++)
|
||||
{
|
||||
SelectedRegister = i;
|
||||
PortWrite(0);
|
||||
}
|
||||
|
||||
randomSeed = 1;
|
||||
|
||||
// number of frames to update
|
||||
var fr = (_audioBufferIndex * _tStatesPerFrame) / _audioBuffer.Length;
|
||||
|
||||
// update the audio buffer
|
||||
BufferUpdate(fr);
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the value from the currently selected register
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int PortRead()
|
||||
{
|
||||
return _registers[_activeRegister];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes to the currently selected register
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void PortWrite(int value)
|
||||
{
|
||||
if (_activeRegister >= 0x10)
|
||||
return;
|
||||
|
||||
byte val = (byte)value;
|
||||
|
||||
if (((1 << _activeRegister) & ((1 << 1) | (1 << 3) | (1 << 5) | (1 << 13))) != 0)
|
||||
val &= 0x0F;
|
||||
|
||||
if (((1 << _activeRegister) & ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))) != 0)
|
||||
val &= 0x1F;
|
||||
|
||||
if (_activeRegister != 13 && _registers[_activeRegister] == val)
|
||||
return;
|
||||
|
||||
_registers[_activeRegister] = val;
|
||||
|
||||
switch (_activeRegister)
|
||||
{
|
||||
// Channel A (Combined Pitch)
|
||||
// (not written to directly)
|
||||
case 0:
|
||||
case 1:
|
||||
_dividerA = _registers[AY_A_FINE] | (_registers[AY_A_COARSE] << 8);
|
||||
break;
|
||||
// Channel B (Combined Pitch)
|
||||
// (not written to directly)
|
||||
case 2:
|
||||
case 3:
|
||||
_dividerB = _registers[AY_B_FINE] | (_registers[AY_B_COARSE] << 8);
|
||||
break;
|
||||
// Channel C (Combined Pitch)
|
||||
// (not written to directly)
|
||||
case 4:
|
||||
case 5:
|
||||
_dividerC = _registers[AY_C_FINE] | (_registers[AY_C_COARSE] << 8);
|
||||
break;
|
||||
// Noise Pitch
|
||||
case 6:
|
||||
_dividerN = val * 2;
|
||||
break;
|
||||
// Mixer
|
||||
case 7:
|
||||
_bit0 = 0 - ((val >> 0) & 1);
|
||||
_bit1 = 0 - ((val >> 1) & 1);
|
||||
_bit2 = 0 - ((val >> 2) & 1);
|
||||
_bit3 = 0 - ((val >> 3) & 1);
|
||||
_bit4 = 0 - ((val >> 4) & 1);
|
||||
_bit5 = 0 - ((val >> 5) & 1);
|
||||
break;
|
||||
// Channel Volumes
|
||||
case 8:
|
||||
_eMaskA = (val & 0x10) != 0 ? -1 : 0;
|
||||
_vA = ((val & 0x0F) * 2 + 1) & ~_eMaskA;
|
||||
break;
|
||||
case 9:
|
||||
_eMaskB = (val & 0x10) != 0 ? -1 : 0;
|
||||
_vB = ((val & 0x0F) * 2 + 1) & ~_eMaskB;
|
||||
break;
|
||||
case 10:
|
||||
_eMaskC = (val & 0x10) != 0 ? -1 : 0;
|
||||
_vC = ((val & 0x0F) * 2 + 1) & ~_eMaskC;
|
||||
break;
|
||||
// Envelope (Combined Duration)
|
||||
// (not written to directly)
|
||||
case 11:
|
||||
case 12:
|
||||
_dividerE = _registers[AY_E_FINE] | (_registers[AY_E_COARSE] << 8);
|
||||
break;
|
||||
// Envelope Shape
|
||||
case 13:
|
||||
// reset the envelope counter
|
||||
_countE = 0;
|
||||
|
||||
if ((_registers[AY_E_SHAPE] & 4) != 0)
|
||||
{
|
||||
// attack
|
||||
_eState = 0;
|
||||
_eDirection = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// decay
|
||||
_eState = 31;
|
||||
_eDirection = -1;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
// IO Port - not implemented
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start of frame
|
||||
/// </summary>
|
||||
public void StartFrame()
|
||||
{
|
||||
_audioBufferIndex = 0;
|
||||
BufferUpdate(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End of frame
|
||||
/// </summary>
|
||||
public void EndFrame()
|
||||
{
|
||||
BufferUpdate(_tStatesPerFrame);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the audiobuffer based on the current frame t-state
|
||||
/// </summary>
|
||||
/// <param name="frameCycle"></param>
|
||||
public void UpdateSound(int frameCycle)
|
||||
{
|
||||
BufferUpdate(frameCycle);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Register indicies
|
||||
/// </summary>
|
||||
private const int AY_A_FINE = 0;
|
||||
private const int AY_A_COARSE = 1;
|
||||
private const int AY_B_FINE = 2;
|
||||
private const int AY_B_COARSE = 3;
|
||||
private const int AY_C_FINE = 4;
|
||||
private const int AY_C_COARSE = 5;
|
||||
private const int AY_NOISEPITCH = 6;
|
||||
private const int AY_MIXER = 7;
|
||||
private const int AY_A_VOL = 8;
|
||||
private const int AY_B_VOL = 9;
|
||||
private const int AY_C_VOL = 10;
|
||||
private const int AY_E_FINE = 11;
|
||||
private const int AY_E_COARSE = 12;
|
||||
private const int AY_E_SHAPE = 13;
|
||||
private const int AY_PORT_A = 14;
|
||||
private const int AY_PORT_B = 15;
|
||||
|
||||
/// <summary>
|
||||
/// The register array
|
||||
/*
|
||||
The AY-3-8910/8912 contains 16 internal registers as follows:
|
||||
|
||||
Register Function Range
|
||||
0 Channel A fine pitch 8-bit (0-255)
|
||||
1 Channel A course pitch 4-bit (0-15)
|
||||
2 Channel B fine pitch 8-bit (0-255)
|
||||
3 Channel B course pitch 4-bit (0-15)
|
||||
4 Channel C fine pitch 8-bit (0-255)
|
||||
5 Channel C course pitch 4-bit (0-15)
|
||||
6 Noise pitch 5-bit (0-31)
|
||||
7 Mixer 8-bit (see below)
|
||||
8 Channel A volume 4-bit (0-15, see below)
|
||||
9 Channel B volume 4-bit (0-15, see below)
|
||||
10 Channel C volume 4-bit (0-15, see below)
|
||||
11 Envelope fine duration 8-bit (0-255)
|
||||
12 Envelope course duration 8-bit (0-255)
|
||||
13 Envelope shape 4-bit (0-15)
|
||||
14 I/O port A 8-bit (0-255)
|
||||
15 I/O port B 8-bit (0-255) (Not present on the AY-3-8912)
|
||||
|
||||
* The volume registers (8, 9 and 10) contain a 4-bit setting but if bit 5 is set then that channel uses the
|
||||
envelope defined by register 13 and ignores its volume setting.
|
||||
* The mixer (register 7) is made up of the following bits (low=enabled):
|
||||
|
||||
Bit: 7 6 5 4 3 2 1 0
|
||||
Register: I/O I/O Noise Noise Noise Tone Tone Tone
|
||||
Channel: B A C B A C B A
|
||||
|
||||
The AY-3-8912 ignores bit 7 of this register.
|
||||
*/
|
||||
/// </summary>
|
||||
private int[] _registers = new int[16];
|
||||
|
||||
/// <summary>
|
||||
/// The currently selected register
|
||||
/// </summary>
|
||||
private byte _activeRegister;
|
||||
|
||||
/// <summary>
|
||||
/// The frequency of the AY chip
|
||||
/// </summary>
|
||||
private static int _chipFrequency = 1773400;
|
||||
|
||||
/// <summary>
|
||||
/// The rendering resolution of the chip
|
||||
/// </summary>
|
||||
private double _resolution = 50D * 8D / _chipFrequency;
|
||||
|
||||
/// <summary>
|
||||
/// Channel generator state
|
||||
/// </summary>
|
||||
private int _bitA;
|
||||
private int _bitB;
|
||||
private int _bitC;
|
||||
|
||||
/// <summary>
|
||||
/// Envelope state
|
||||
/// </summary>
|
||||
private int _eState;
|
||||
|
||||
/// <summary>
|
||||
/// Envelope direction
|
||||
/// </summary>
|
||||
private int _eDirection;
|
||||
|
||||
/// <summary>
|
||||
/// Noise seed
|
||||
/// </summary>
|
||||
private int _noiseSeed;
|
||||
|
||||
/// <summary>
|
||||
/// Mixer state
|
||||
/// </summary>
|
||||
private int _bit0;
|
||||
private int _bit1;
|
||||
private int _bit2;
|
||||
private int _bit3;
|
||||
private int _bit4;
|
||||
private int _bit5;
|
||||
|
||||
/// <summary>
|
||||
/// Noise generator state
|
||||
/// </summary>
|
||||
private int _bitN;
|
||||
|
||||
/// <summary>
|
||||
/// Envelope masks
|
||||
/// </summary>
|
||||
private int _eMaskA;
|
||||
private int _eMaskB;
|
||||
private int _eMaskC;
|
||||
|
||||
/// <summary>
|
||||
/// Amplitudes
|
||||
/// </summary>
|
||||
private int _vA;
|
||||
private int _vB;
|
||||
private int _vC;
|
||||
|
||||
/// <summary>
|
||||
/// Channel gen counters
|
||||
/// </summary>
|
||||
private int _countA;
|
||||
private int _countB;
|
||||
private int _countC;
|
||||
|
||||
/// <summary>
|
||||
/// Envelope gen counter
|
||||
/// </summary>
|
||||
private int _countE;
|
||||
|
||||
/// <summary>
|
||||
/// Noise gen counter
|
||||
/// </summary>
|
||||
private int _countN;
|
||||
|
||||
/// <summary>
|
||||
/// Channel gen dividers
|
||||
/// </summary>
|
||||
private int _dividerA;
|
||||
private int _dividerB;
|
||||
private int _dividerC;
|
||||
|
||||
/// <summary>
|
||||
/// Envelope gen divider
|
||||
/// </summary>
|
||||
private int _dividerE;
|
||||
|
||||
/// <summary>
|
||||
/// Noise gen divider
|
||||
/// </summary>
|
||||
private int _dividerN;
|
||||
|
||||
/// <summary>
|
||||
/// Panning table list
|
||||
/// </summary>
|
||||
private static List<uint[]> PanTabs = new List<uint[]>
|
||||
{
|
||||
// MONO
|
||||
new uint[] { 100,100, 100,100, 100,100 },
|
||||
// ABC
|
||||
new uint[] { 100,10, 66,66, 10,100 },
|
||||
// ACB
|
||||
new uint[] { 100,10, 10,100, 66,66 },
|
||||
// BAC
|
||||
new uint[] { 66,66, 100,10, 10,100 },
|
||||
// BCA
|
||||
new uint[] { 10,100, 100,10, 66,66 },
|
||||
// CAB
|
||||
new uint[] { 66,66, 10,100, 100,10 },
|
||||
// CBA
|
||||
new uint[] { 10,100, 66,66, 100,10 }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The currently selected panning configuration
|
||||
/// </summary>
|
||||
private AYPanConfig _currentPanTab = AYPanConfig.ABC;
|
||||
|
||||
/// <summary>
|
||||
/// The current volume
|
||||
/// </summary>
|
||||
private int _volume = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Volume tables state
|
||||
/// </summary>
|
||||
private uint[][] _volumeTables;
|
||||
|
||||
/// <summary>
|
||||
/// Volume table to be used
|
||||
/// </summary>
|
||||
private static uint[] AYVolumes = new uint[]
|
||||
{
|
||||
0x0000,0x0000,0x0340,0x0340,0x04C0,0x04C0,0x06F2,0x06F2,
|
||||
0x0A44,0x0A44,0x0F13,0x0F13,0x1510,0x1510,0x227E,0x227E,
|
||||
0x289F,0x289F,0x414E,0x414E,0x5B21,0x5B21,0x7258,0x7258,
|
||||
0x905E,0x905E,0xB550,0xB550,0xD7A0,0xD7A0,0xFFFF,0xFFFF,
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Forces an update of the volume tables
|
||||
/// </summary>
|
||||
private void UpdateVolume()
|
||||
{
|
||||
var vol = (ulong)0xFFFF * (ulong)_volume / 100UL;
|
||||
_volumeTables = new uint[6][];
|
||||
|
||||
// parent array
|
||||
for (int j = 0; j < _volumeTables.Length; j++)
|
||||
{
|
||||
_volumeTables[j] = new uint[32];
|
||||
|
||||
// child array
|
||||
for (int i = 0; i < _volumeTables[j].Length; i++)
|
||||
{
|
||||
_volumeTables[j][i] = (uint)(
|
||||
(PanTabs[(int)_currentPanTab][j] * AYVolumes[i] * vol) /
|
||||
(3 * 65535 * 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int mult_const;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes timing information for the frame
|
||||
/// </summary>
|
||||
/// <param name="sampleRate"></param>
|
||||
/// <param name="frameTactCount"></param>
|
||||
private void InitTiming(int sampleRate, int frameTactCount)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_tStatesPerFrame = frameTactCount;
|
||||
|
||||
_tStatesPerSample = 79; //(int)Math.Round(((double)_tStatesPerFrame * 50D) /
|
||||
//(16D * (double)_sampleRate),
|
||||
//MidpointRounding.AwayFromZero);
|
||||
|
||||
_samplesPerFrame = _tStatesPerFrame / _tStatesPerSample;
|
||||
_audioBuffer = new short[_samplesPerFrame * 2]; //[_sampleRate / 50];
|
||||
_audioBufferIndex = 0;
|
||||
|
||||
mult_const = ((_chipFrequency / 8) << 14) / _machine.ULADevice.ClockSpeed;
|
||||
|
||||
var aytickspercputick = (double)_machine.ULADevice.ClockSpeed / (double)_chipFrequency;
|
||||
int ayCyclesPerSample = (int)((double)_tStatesPerSample * (double)aytickspercputick);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the audiobuffer based on the current frame t-state
|
||||
/// </summary>
|
||||
/// <param name="cycle"></param>
|
||||
private void BufferUpdate(int cycle)
|
||||
{
|
||||
if (cycle > _tStatesPerFrame)
|
||||
{
|
||||
// we are outside of the frame - just process the last value
|
||||
cycle = _tStatesPerFrame;
|
||||
}
|
||||
|
||||
// get the current length of the audiobuffer
|
||||
int bufferLength = _samplesPerFrame; // _audioBuffer.Length;
|
||||
|
||||
int toEnd = ((bufferLength * cycle) / _tStatesPerFrame);
|
||||
|
||||
// loop through the number of samples we need to render
|
||||
while(_audioBufferIndex < toEnd)
|
||||
{
|
||||
// run the AY chip processing at the correct resolution
|
||||
for (int i = 0; i < _tStatesPerSample / 14; i++)
|
||||
{
|
||||
if (++_countA >= _dividerA)
|
||||
{
|
||||
_countA = 0;
|
||||
_bitA ^= -1;
|
||||
}
|
||||
|
||||
if (++_countB >= _dividerB)
|
||||
{
|
||||
_countB = 0;
|
||||
_bitB ^= -1;
|
||||
}
|
||||
|
||||
if (++_countC >= _dividerC)
|
||||
{
|
||||
_countC = 0;
|
||||
_bitC ^= -1;
|
||||
}
|
||||
|
||||
if (++_countN >= _dividerN)
|
||||
{
|
||||
_countN = 0;
|
||||
_noiseSeed = (_noiseSeed * 2 + 1) ^ (((_noiseSeed >> 16) ^ (_noiseSeed >> 13)) & 1);
|
||||
_bitN = 0 - ((_noiseSeed >> 16) & 1);
|
||||
}
|
||||
|
||||
if (++_countE >= _dividerE)
|
||||
{
|
||||
_countE = 0;
|
||||
_eState += +_eDirection;
|
||||
|
||||
if ((_eState & ~31) != 0)
|
||||
{
|
||||
var mask = (1 << _registers[AY_E_SHAPE]);
|
||||
|
||||
if ((mask & ((1 << 0) | (1 << 1) | (1 << 2) |
|
||||
(1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) |
|
||||
(1 << 7) | (1 << 9) | (1 << 15))) != 0)
|
||||
{
|
||||
_eState = _eDirection = 0;
|
||||
}
|
||||
else if ((mask & ((1 << 8) | (1 << 12))) != 0)
|
||||
{
|
||||
_eState &= 31;
|
||||
}
|
||||
else if ((mask & ((1 << 10) | (1 << 14))) != 0)
|
||||
{
|
||||
_eDirection = -_eDirection;
|
||||
_eState += _eDirection;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 11,13
|
||||
_eState = 31;
|
||||
_eDirection = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mix the sample
|
||||
var mixA = ((_eMaskA & _eState) | _vA) & ((_bitA | _bit0) & (_bitN | _bit3));
|
||||
var mixB = ((_eMaskB & _eState) | _vB) & ((_bitB | _bit1) & (_bitN | _bit4));
|
||||
var mixC = ((_eMaskC & _eState) | _vC) & ((_bitC | _bit2) & (_bitN | _bit5));
|
||||
|
||||
var l = _volumeTables[0][mixA];
|
||||
var r = _volumeTables[1][mixA];
|
||||
|
||||
l += _volumeTables[2][mixB];
|
||||
r += _volumeTables[3][mixB];
|
||||
l += _volumeTables[4][mixC];
|
||||
r += _volumeTables[5][mixC];
|
||||
|
||||
_audioBuffer[_audioBufferIndex * 2] = (short)l;
|
||||
_audioBuffer[(_audioBufferIndex * 2) + 1] = (short)r;
|
||||
|
||||
_audioBufferIndex++;
|
||||
}
|
||||
|
||||
_lastStateRendered = cycle;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_audioBuffer = new short[_samplesPerFrame * 2];
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
nsamp = _samplesPerFrame;
|
||||
samples = _audioBuffer;
|
||||
DiscardSamples();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region State Serialization
|
||||
|
||||
public int nullDump = 0;
|
||||
|
||||
/// <summary>
|
||||
/// State serialization
|
||||
/// </summary>
|
||||
/// <param name="ser"></param>
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("PSG-AY");
|
||||
|
||||
ser.Sync("_tStatesPerFrame", ref _tStatesPerFrame);
|
||||
ser.Sync("_sampleRate", ref _sampleRate);
|
||||
ser.Sync("_samplesPerFrame", ref _samplesPerFrame);
|
||||
ser.Sync("_tStatesPerSample", ref _tStatesPerSample);
|
||||
ser.Sync("_audioBufferIndex", ref _audioBufferIndex);
|
||||
ser.Sync("_audioBuffer", ref _audioBuffer, false);
|
||||
|
||||
ser.Sync("_registers", ref _registers, false);
|
||||
ser.Sync("_activeRegister", ref _activeRegister);
|
||||
ser.Sync("_bitA", ref _bitA);
|
||||
ser.Sync("_bitB", ref _bitB);
|
||||
ser.Sync("_bitC", ref _bitC);
|
||||
ser.Sync("_eState", ref _eState);
|
||||
ser.Sync("_eDirection", ref _eDirection);
|
||||
ser.Sync("_noiseSeed", ref _noiseSeed);
|
||||
ser.Sync("_bit0", ref _bit0);
|
||||
ser.Sync("_bit1", ref _bit1);
|
||||
ser.Sync("_bit2", ref _bit2);
|
||||
ser.Sync("_bit3", ref _bit3);
|
||||
ser.Sync("_bit4", ref _bit4);
|
||||
ser.Sync("_bit5", ref _bit5);
|
||||
ser.Sync("_bitN", ref _bitN);
|
||||
ser.Sync("_eMaskA", ref _eMaskA);
|
||||
ser.Sync("_eMaskB", ref _eMaskB);
|
||||
ser.Sync("_eMaskC", ref _eMaskC);
|
||||
ser.Sync("_vA", ref _vA);
|
||||
ser.Sync("_vB", ref _vB);
|
||||
ser.Sync("_vC", ref _vC);
|
||||
ser.Sync("_countA", ref _countA);
|
||||
ser.Sync("_countB", ref _countB);
|
||||
ser.Sync("_countC", ref _countC);
|
||||
ser.Sync("_countE", ref _countE);
|
||||
ser.Sync("_countN", ref _countN);
|
||||
ser.Sync("_dividerA", ref _dividerA);
|
||||
ser.Sync("_dividerB", ref _dividerB);
|
||||
ser.Sync("_dividerC", ref _dividerC);
|
||||
ser.Sync("_dividerE", ref _dividerE);
|
||||
ser.Sync("_dividerN", ref _dividerN);
|
||||
ser.SyncEnum("_currentPanTab", ref _currentPanTab);
|
||||
ser.Sync("_volume", ref nullDump);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
ser.Sync("volTable" + i, ref _volumeTables[i], false);
|
||||
}
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the piezoelectric buzzer used in the Spectrum to produce sound
|
||||
/// The beeper is controlled by rapidly toggling bit 4 of port &FE
|
||||
///
|
||||
/// For the purposes of emulation this devices is locked to a frame
|
||||
/// a list of Pulses is built up over the course of the frame and outputted at the end of the frame
|
||||
/// </summary>
|
||||
public class Buzzer : ISoundProvider, IBeeperDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Supplied values are right for 48K spectrum
|
||||
/// These will deviate for 128k and up (as there are more T-States per frame)
|
||||
/// </summary>
|
||||
//public int SampleRate = 44100; //35000;
|
||||
//public int SamplesPerFrame = 882; //699;
|
||||
//public int TStatesPerSample = 79; //100;
|
||||
|
||||
/// <summary>
|
||||
/// Sample Rate
|
||||
/// This usually has to be 44100 for ISoundProvider
|
||||
/// </summary>
|
||||
public int SampleRate
|
||||
{
|
||||
get { return _sampleRate; }
|
||||
set { _sampleRate = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of samples in one frame
|
||||
/// </summary>
|
||||
public int SamplesPerFrame
|
||||
{
|
||||
get { return _samplesPerFrame; }
|
||||
set { _samplesPerFrame = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of TStates in each sample
|
||||
/// </summary>
|
||||
public int TStatesPerSample
|
||||
{
|
||||
get { return _tStatesPerSample; }
|
||||
set { _tStatesPerSample = value; }
|
||||
}
|
||||
|
||||
private SpectrumBase _machine;
|
||||
|
||||
/// <summary>
|
||||
/// State fields
|
||||
/// </summary>
|
||||
private long _frameStart;
|
||||
private bool _tapeMode;
|
||||
private long _tStatesPerFrame;
|
||||
private int _sampleRate;
|
||||
private int _samplesPerFrame;
|
||||
private int _tStatesPerSample;
|
||||
|
||||
/// <summary>
|
||||
/// Pulses collected during the last frame
|
||||
/// </summary>
|
||||
public List<Pulse> Pulses { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last pulse
|
||||
/// </summary>
|
||||
public bool LastPulse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last T-State (cpu cycle) that the last pulse was received
|
||||
/// </summary>
|
||||
public long LastPulseTState { get; set; }
|
||||
|
||||
#region Construction & Initialisation
|
||||
|
||||
public Buzzer(SpectrumBase machine)
|
||||
{
|
||||
_machine = machine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises the buzzer
|
||||
/// </summary>
|
||||
public void Init(int sampleRate, int tStatesPerFrame)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
_tStatesPerFrame = tStatesPerFrame;
|
||||
_tStatesPerSample = 79;
|
||||
_samplesPerFrame = (int)_tStatesPerFrame / _tStatesPerSample;
|
||||
|
||||
/*
|
||||
|
||||
// set the tstatesperframe
|
||||
_tStatesPerFrame = tStatesPerFrame;
|
||||
|
||||
// calculate actual refresh rate
|
||||
double refresh = (double)_machine.ULADevice.ClockSpeed / (double)_tStatesPerFrame;
|
||||
|
||||
// how many samples per frame are expected by ISoundProvider (at 44.1KHz)
|
||||
_samplesPerFrame = 880;// (int)((double)sampleRate / (double)refresh);
|
||||
|
||||
// set the sample rate
|
||||
_sampleRate = sampleRate;
|
||||
|
||||
// calculate samples per frame (what ISoundProvider will be expecting at 44100)
|
||||
//_samplesPerFrame = (int)((double)_tStatesPerFrame / (double)refresh);
|
||||
|
||||
// calculate tstates per sameple
|
||||
_tStatesPerSample = 79;// _tStatesPerFrame / _samplesPerFrame;
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// get divisors
|
||||
var divs = from a in Enumerable.Range(2, _tStatesPerFrame / 2)
|
||||
where _tStatesPerFrame % a == 0
|
||||
select a;
|
||||
|
||||
// get the highest int value under 120 (this will be TStatesPerSample)
|
||||
_tStatesPerSample = divs.Where(a => a < 100).Last();
|
||||
|
||||
// get _samplesPerFrame
|
||||
_samplesPerFrame = _tStatesPerFrame / _tStatesPerSample;
|
||||
|
||||
*/
|
||||
Pulses = new List<Pulse>(1000);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// When the pulse value from the EAR output changes it is processed here
|
||||
/// </summary>
|
||||
/// <param name="fromTape"></param>
|
||||
/// <param name="earPulse"></param>
|
||||
public void ProcessPulseValue(bool fromTape, bool earPulse)
|
||||
{
|
||||
if (!_machine._renderSound)
|
||||
return;
|
||||
|
||||
if (!fromTape && _tapeMode)
|
||||
{
|
||||
// tape mode is active but the pulse value came from an OUT instruction
|
||||
// do not process the value
|
||||
//return;
|
||||
}
|
||||
|
||||
if (earPulse == LastPulse)
|
||||
{
|
||||
// no change detected
|
||||
return;
|
||||
}
|
||||
|
||||
// set the lastpulse
|
||||
LastPulse = earPulse;
|
||||
|
||||
// get where we are in the frame
|
||||
var currentULACycle = _machine.CurrentFrameCycle;
|
||||
var currentBuzzerCycle = currentULACycle <= _tStatesPerFrame ? currentULACycle : _tStatesPerFrame;
|
||||
var length = currentBuzzerCycle - LastPulseTState;
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
// the first T-State has changed the pulse
|
||||
// do not add it
|
||||
}
|
||||
else if (length > 0)
|
||||
{
|
||||
// add the pulse
|
||||
Pulse p = new Pulse
|
||||
{
|
||||
State = !earPulse,
|
||||
Length = length
|
||||
};
|
||||
Pulses.Add(p);
|
||||
}
|
||||
|
||||
// set the last pulse tstate
|
||||
LastPulseTState = currentBuzzerCycle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// New frame starts
|
||||
/// </summary>
|
||||
public void StartFrame()
|
||||
{
|
||||
//DiscardSamples();
|
||||
Pulses.Clear();
|
||||
LastPulseTState = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frame is completed
|
||||
/// </summary>
|
||||
public void EndFrame()
|
||||
{
|
||||
// store the last pulse information
|
||||
if (LastPulseTState <= _tStatesPerFrame - 1)
|
||||
{
|
||||
Pulse p = new Pulse
|
||||
{
|
||||
State = LastPulse,
|
||||
Length = _tStatesPerFrame - LastPulseTState
|
||||
};
|
||||
Pulses.Add(p);
|
||||
}
|
||||
|
||||
// create the sample array
|
||||
var firstSampleOffset = _frameStart % TStatesPerSample == 0 ? 0 : TStatesPerSample - (_frameStart + TStatesPerSample) % TStatesPerSample;
|
||||
var samplesInFrame = (_tStatesPerFrame - firstSampleOffset - 1) / TStatesPerSample + 1;
|
||||
var samples = new short[samplesInFrame];
|
||||
|
||||
// convert pulses to samples
|
||||
var sampleIndex = 0;
|
||||
var currentEnd = _frameStart;
|
||||
|
||||
foreach (var pulse in Pulses)
|
||||
{
|
||||
var firstSample = currentEnd % TStatesPerSample == 0
|
||||
? currentEnd : currentEnd + TStatesPerSample - currentEnd % TStatesPerSample;
|
||||
|
||||
for (var i = firstSample; i < currentEnd + pulse.Length; i += TStatesPerSample)
|
||||
{
|
||||
if (_tapeMode)
|
||||
samples[sampleIndex++] = pulse.State ? (short)(short.MaxValue / 6) : (short)0;
|
||||
else
|
||||
samples[sampleIndex++] = pulse.State ? (short)(short.MaxValue / 3) : (short)0;
|
||||
}
|
||||
|
||||
currentEnd += pulse.Length;
|
||||
}
|
||||
|
||||
// fill the _sampleBuffer for ISoundProvider
|
||||
soundBufferContains = (int)samplesInFrame;
|
||||
|
||||
if (soundBuffer.Length != soundBufferContains)
|
||||
soundBuffer = new short[soundBufferContains];
|
||||
|
||||
samples.CopyTo(soundBuffer, 0);
|
||||
|
||||
_frameStart += _tStatesPerFrame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the spectrum is set to receive tape input, the EAR output on the ULA is disabled
|
||||
/// (so no buzzer sound is emitted)
|
||||
/// </summary>
|
||||
/// <param name="tapeMode"></param>
|
||||
public void SetTapeMode(bool tapeMode)
|
||||
{
|
||||
_tapeMode = tapeMode;
|
||||
}
|
||||
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
private short[] soundBuffer = new short[882];
|
||||
private int soundBufferContains = 0;
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
soundBufferContains = 0;
|
||||
soundBuffer = new short[SamplesPerFrame];
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
// convert to stereo
|
||||
short[] stereoBuffer = new short[soundBufferContains * 2];
|
||||
int index = 0;
|
||||
for (int i = 0; i < soundBufferContains; i++)
|
||||
{
|
||||
stereoBuffer[index++] = soundBuffer[i];
|
||||
stereoBuffer[index++] = soundBuffer[i];
|
||||
}
|
||||
|
||||
samples = stereoBuffer;
|
||||
nsamp = _samplesPerFrame; // soundBufferContains;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Buzzer");
|
||||
ser.Sync("_frameStart", ref _frameStart);
|
||||
ser.Sync("_tapeMode", ref _tapeMode);
|
||||
ser.Sync("_tStatesPerFrame", ref _tStatesPerFrame);
|
||||
ser.Sync("_sampleRate", ref _sampleRate);
|
||||
ser.Sync("_samplesPerFrame", ref _samplesPerFrame);
|
||||
ser.Sync("_tStatesPerSample", ref _tStatesPerSample);
|
||||
|
||||
ser.Sync("soundBuffer", ref soundBuffer, false);
|
||||
ser.Sync("soundBufferContains", ref soundBufferContains);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The MIC and EAR pins in the spectrum deal in on/off pulses of varying lengths
|
||||
/// This struct therefore represents 1 of these pulses
|
||||
/// </summary>
|
||||
public struct Pulse
|
||||
{
|
||||
/// <summary>
|
||||
/// True: High State
|
||||
/// False: Low State
|
||||
/// </summary>
|
||||
public bool State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pulse length in Z80 T-States (cycles)
|
||||
/// </summary>
|
||||
public long Length { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public enum MachineType
|
||||
{
|
||||
/// <summary>
|
||||
/// Original Sinclair Spectrum 16K model
|
||||
/// </summary>
|
||||
ZXSpectrum16,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 48K model
|
||||
/// </summary>
|
||||
ZXSpectrum48,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 128K model
|
||||
/// </summary>
|
||||
ZXSpectrum128,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 128 +2 model
|
||||
/// </summary>
|
||||
ZXSpectrum128Plus2,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 128 +2a model (same as the +3 just without disk drive)
|
||||
/// </summary>
|
||||
ZXSpectrum128Plus2a,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 128 +3 model
|
||||
/// </summary>
|
||||
ZXSpectrum128Plus3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles all ZX-level input
|
||||
/// </summary>
|
||||
public abstract partial class SpectrumBase
|
||||
{
|
||||
string Play = "Play Tape";
|
||||
string Stop = "Stop Tape";
|
||||
string RTZ = "RTZ Tape";
|
||||
string Record = "Record Tape";
|
||||
string NextTape = "Insert Next Tape";
|
||||
string PrevTape = "Insert Previous Tape";
|
||||
string NextBlock = "Next Tape Block";
|
||||
string PrevBlock = "Prev Tape Block";
|
||||
string TapeStatus = "Get Tape Status";
|
||||
|
||||
string HardResetStr = "Hard Reset";
|
||||
string SoftResetStr = "Soft Reset";
|
||||
|
||||
bool pressed_Play = false;
|
||||
bool pressed_Stop = false;
|
||||
bool pressed_RTZ = false;
|
||||
bool pressed_NextTape = false;
|
||||
bool pressed_PrevTape = false;
|
||||
bool pressed_NextBlock = false;
|
||||
bool pressed_PrevBlock = false;
|
||||
bool pressed_TapeStatus = false;
|
||||
bool pressed_HardReset = false;
|
||||
bool pressed_SoftReset = false;
|
||||
|
||||
/// <summary>
|
||||
/// Cycles through all the input callbacks
|
||||
/// This should be done once per frame
|
||||
/// </summary>
|
||||
public void PollInput()
|
||||
{
|
||||
Spectrum.InputCallbacks.Call();
|
||||
|
||||
lock (this)
|
||||
{
|
||||
// parse single keyboard matrix keys
|
||||
for (var i = 0; i < KeyboardDevice.KeyboardMatrix.Length; i++)
|
||||
{
|
||||
string key = KeyboardDevice.KeyboardMatrix[i];
|
||||
bool prevState = KeyboardDevice.GetKeyStatus(key);
|
||||
bool currState = Spectrum._controller.IsPressed(key);
|
||||
|
||||
if (currState != prevState)
|
||||
KeyboardDevice.SetKeyStatus(key, currState);
|
||||
}
|
||||
|
||||
// non matrix keys
|
||||
foreach (string k in KeyboardDevice.NonMatrixKeys)
|
||||
{
|
||||
if (!k.StartsWith("Key"))
|
||||
continue;
|
||||
|
||||
bool currState = Spectrum._controller.IsPressed(k);
|
||||
|
||||
KeyboardDevice.SetKeyStatus(k, currState);
|
||||
}
|
||||
|
||||
// J1
|
||||
foreach (string j in JoystickCollection[0].ButtonCollection)
|
||||
{
|
||||
bool prevState = JoystickCollection[0].GetJoyInput(j);
|
||||
bool currState = Spectrum._controller.IsPressed(j);
|
||||
|
||||
if (currState != prevState)
|
||||
JoystickCollection[0].SetJoyInput(j, currState);
|
||||
}
|
||||
|
||||
// J2
|
||||
foreach (string j in JoystickCollection[1].ButtonCollection)
|
||||
{
|
||||
bool prevState = JoystickCollection[1].GetJoyInput(j);
|
||||
bool currState = Spectrum._controller.IsPressed(j);
|
||||
|
||||
if (currState != prevState)
|
||||
JoystickCollection[1].SetJoyInput(j, currState);
|
||||
}
|
||||
|
||||
// J3
|
||||
foreach (string j in JoystickCollection[2].ButtonCollection)
|
||||
{
|
||||
bool prevState = JoystickCollection[2].GetJoyInput(j);
|
||||
bool currState = Spectrum._controller.IsPressed(j);
|
||||
|
||||
if (currState != prevState)
|
||||
JoystickCollection[2].SetJoyInput(j, currState);
|
||||
}
|
||||
}
|
||||
|
||||
// Tape control
|
||||
if (Spectrum._controller.IsPressed(Play))
|
||||
{
|
||||
if (!pressed_Play)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(Play);
|
||||
TapeDevice.Play();
|
||||
pressed_Play = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_Play = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(Stop))
|
||||
{
|
||||
if (!pressed_Stop)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(Stop);
|
||||
TapeDevice.Stop();
|
||||
pressed_Stop = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_Stop = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(RTZ))
|
||||
{
|
||||
if (!pressed_RTZ)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(RTZ);
|
||||
TapeDevice.RTZ();
|
||||
pressed_RTZ = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_RTZ = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(Record))
|
||||
{
|
||||
|
||||
}
|
||||
if (Spectrum._controller.IsPressed(NextTape))
|
||||
{
|
||||
if (!pressed_NextTape)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(NextTape);
|
||||
TapeMediaIndex++;
|
||||
pressed_NextTape = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_NextTape = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(PrevTape))
|
||||
{
|
||||
if (!pressed_PrevTape)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(PrevTape);
|
||||
TapeMediaIndex--;
|
||||
pressed_PrevTape = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_PrevTape = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(NextBlock))
|
||||
{
|
||||
if (!pressed_NextBlock)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(NextBlock);
|
||||
TapeDevice.SkipBlock(true);
|
||||
pressed_NextBlock = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_NextBlock = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(PrevBlock))
|
||||
{
|
||||
if (!pressed_PrevBlock)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage(PrevBlock);
|
||||
TapeDevice.SkipBlock(false);
|
||||
pressed_PrevBlock = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_PrevBlock = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(TapeStatus))
|
||||
{
|
||||
if (!pressed_TapeStatus)
|
||||
{
|
||||
//Spectrum.OSD_FireInputMessage(TapeStatus);
|
||||
Spectrum.OSD_ShowTapeStatus();
|
||||
pressed_TapeStatus = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_TapeStatus = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(HardResetStr))
|
||||
{
|
||||
if (!pressed_HardReset)
|
||||
{
|
||||
HardReset();
|
||||
pressed_HardReset = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_HardReset = false;
|
||||
|
||||
if (Spectrum._controller.IsPressed(SoftResetStr))
|
||||
{
|
||||
if (!pressed_SoftReset)
|
||||
{
|
||||
SoftReset();
|
||||
pressed_SoftReset = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_SoftReset = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates the joysticks array
|
||||
/// </summary>
|
||||
/// <param name="joys"></param>
|
||||
protected void InitJoysticks(List<JoystickType> joys)
|
||||
{
|
||||
List<IJoystick> jCollection = new List<IJoystick>();
|
||||
|
||||
for (int i = 0; i < joys.Count(); i++)
|
||||
{
|
||||
jCollection.Add(InstantiateJoystick(joys[i], i + 1));
|
||||
}
|
||||
|
||||
JoystickCollection = jCollection.ToArray();
|
||||
|
||||
for (int i = 0; i < JoystickCollection.Length; i++)
|
||||
{
|
||||
Spectrum.OSD_FireInputMessage("Joystick " + (i + 1) + ": " + JoystickCollection[i].JoyType.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new IJoystick object
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="playerNumber"></param>
|
||||
/// <returns></returns>
|
||||
public IJoystick InstantiateJoystick(JoystickType type, int playerNumber)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case JoystickType.Kempston:
|
||||
return new KempstonJoystick(this, playerNumber);
|
||||
case JoystickType.Cursor:
|
||||
return new CursorJoystick(this, playerNumber);
|
||||
case JoystickType.SinclairLEFT:
|
||||
return new SinclairJoystick1(this, playerNumber);
|
||||
case JoystickType.SinclairRIGHT:
|
||||
return new SinclairJoystick2(this, playerNumber);
|
||||
case JoystickType.NULL:
|
||||
return new NullJoystick(this, playerNumber);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a IJoystick object depending on the type (or null if not found)
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
protected IJoystick LocateUniqueJoystick(JoystickType type)
|
||||
{
|
||||
return JoystickCollection.Where(a => a.JoyType == type).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether input read has been requested
|
||||
/// This forms part of the IEmulator LagFrame implementation
|
||||
/// </summary>
|
||||
private bool inputRead;
|
||||
public bool InputRead
|
||||
{
|
||||
get { return inputRead; }
|
||||
set { inputRead = value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public abstract partial class SpectrumBase
|
||||
{
|
||||
// until +3 disk drive is emulated, we assume that incoming files are tape images
|
||||
|
||||
/// <summary>
|
||||
/// The tape or disk image(s) that are passed in from the main ZXSpectrum class
|
||||
/// </summary>
|
||||
protected List<byte[]> mediaImages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tape images
|
||||
/// </summary>
|
||||
protected List<byte[]> tapeImages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disk images
|
||||
/// </summary>
|
||||
protected List<byte[]> diskImages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The index of the currently 'loaded' tape image
|
||||
/// </summary>
|
||||
protected int tapeMediaIndex;
|
||||
public int TapeMediaIndex
|
||||
{
|
||||
get { return tapeMediaIndex; }
|
||||
set
|
||||
{
|
||||
int tmp = value;
|
||||
int result = value;
|
||||
|
||||
if (tapeImages == null || tapeImages.Count() == 0)
|
||||
{
|
||||
// no tape images found
|
||||
return;
|
||||
}
|
||||
|
||||
if (value >= tapeImages.Count())
|
||||
{
|
||||
// media at this index does not exist - loop back to 0
|
||||
result = 0;
|
||||
}
|
||||
else if (value < 0)
|
||||
{
|
||||
// negative index not allowed - move to last item in the collection
|
||||
result = tapeImages.Count() - 1;
|
||||
}
|
||||
|
||||
// load the media into the tape device
|
||||
tapeMediaIndex = result;
|
||||
// fire osd message
|
||||
Spectrum.OSD_TapeInserted();
|
||||
LoadTapeMedia();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The index of the currently 'loaded' disk image
|
||||
/// </summary>
|
||||
protected int diskMediaIndex;
|
||||
public int DiskMediaIndex
|
||||
{
|
||||
get { return diskMediaIndex; }
|
||||
set
|
||||
{
|
||||
int tmp = value;
|
||||
int result = value;
|
||||
|
||||
if (diskImages == null || diskImages.Count() == 0)
|
||||
{
|
||||
// no tape images found
|
||||
return;
|
||||
}
|
||||
|
||||
if (value >= diskImages.Count())
|
||||
{
|
||||
// media at this index does not exist - loop back to 0
|
||||
result = 0;
|
||||
}
|
||||
else if (value < 0)
|
||||
{
|
||||
// negative index not allowed - move to last item in the collection
|
||||
result = diskImages.Count() - 1;
|
||||
}
|
||||
|
||||
// load the media into the disk device
|
||||
diskMediaIndex = result;
|
||||
LoadDiskMedia();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on first instantiation (and subsequent core reboots)
|
||||
/// </summary>
|
||||
/// <param name="files"></param>
|
||||
protected void InitializeMedia(List<byte[]> files)
|
||||
{
|
||||
mediaImages = files;
|
||||
LoadAllMedia();
|
||||
Spectrum.OSD_TapeInit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load all media into the relevant structures
|
||||
/// </summary>
|
||||
protected void LoadAllMedia()
|
||||
{
|
||||
tapeImages = new List<byte[]>();
|
||||
diskImages = new List<byte[]>();
|
||||
|
||||
foreach (var m in mediaImages)
|
||||
{
|
||||
switch (IdentifyMedia(m))
|
||||
{
|
||||
case SpectrumMediaType.Tape:
|
||||
tapeImages.Add(m);
|
||||
break;
|
||||
case SpectrumMediaType.Disk:
|
||||
diskImages.Add(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tapeImages.Count > 0)
|
||||
LoadTapeMedia();
|
||||
|
||||
if (diskImages.Count > 0)
|
||||
LoadDiskMedia();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load a tape into the tape device based on tapeMediaIndex
|
||||
/// </summary>
|
||||
protected void LoadTapeMedia()
|
||||
{
|
||||
TapeDevice.LoadTape(tapeImages[tapeMediaIndex]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load a disk into the disk device based on diskMediaIndex
|
||||
/// </summary>
|
||||
protected void LoadDiskMedia()
|
||||
{
|
||||
throw new NotImplementedException("+3 disk drive device not yet implemented");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies and sorts the various media types
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private SpectrumMediaType IdentifyMedia(byte[] data)
|
||||
{
|
||||
// get first 16 bytes as a string
|
||||
string hdr = Encoding.ASCII.GetString(data.Take(16).ToArray());
|
||||
|
||||
// disk checking first
|
||||
if (hdr.ToUpper().Contains("EXTENDED CPC DSK"))
|
||||
{
|
||||
// spectrum .dsk disk file
|
||||
return SpectrumMediaType.Disk;
|
||||
}
|
||||
if (hdr.ToUpper().StartsWith("FDI"))
|
||||
{
|
||||
// spectrum .fdi disk file
|
||||
return SpectrumMediaType.Disk;
|
||||
}
|
||||
|
||||
// tape checking
|
||||
if (hdr.ToUpper().StartsWith("ZXTAPE!"))
|
||||
{
|
||||
// spectrum .tzx tape file
|
||||
return SpectrumMediaType.Tape;
|
||||
}
|
||||
|
||||
// if we get this far, assume a .tap file
|
||||
return SpectrumMediaType.Tape;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpectrumMediaType
|
||||
{
|
||||
None,
|
||||
Tape,
|
||||
Disk
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The abstract class that all emulated models will inherit from
|
||||
/// * Memory *
|
||||
/// </summary>
|
||||
public abstract partial class SpectrumBase
|
||||
{
|
||||
#region Memory Fields & Properties
|
||||
|
||||
/// <summary>
|
||||
/// ROM Banks
|
||||
/// </summary>
|
||||
public byte[] ROM0 = new byte[0x4000];
|
||||
public byte[] ROM1 = new byte[0x4000];
|
||||
public byte[] ROM2 = new byte[0x4000];
|
||||
public byte[] ROM3 = new byte[0x4000];
|
||||
|
||||
/// <summary>
|
||||
/// RAM Banks
|
||||
/// </summary>
|
||||
public byte[] RAM0 = new byte[0x4000]; // Bank 0
|
||||
public byte[] RAM1 = new byte[0x4000]; // Bank 1
|
||||
public byte[] RAM2 = new byte[0x4000]; // Bank 2
|
||||
public byte[] RAM3 = new byte[0x4000]; // Bank 3
|
||||
public byte[] RAM4 = new byte[0x4000]; // Bank 4
|
||||
public byte[] RAM5 = new byte[0x4000]; // Bank 5
|
||||
public byte[] RAM6 = new byte[0x4000]; // Bank 6
|
||||
public byte[] RAM7 = new byte[0x4000]; // Bank 7
|
||||
|
||||
/// <summary>
|
||||
/// Signs that the shadow screen is now displaying
|
||||
/// Note: normal screen memory in RAM5 is not altered, the ULA just outputs Screen1 instead (RAM7)
|
||||
/// </summary>
|
||||
protected bool SHADOWPaged;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current RAM page
|
||||
/// /// 128k, +2/2a and +3 only
|
||||
/// </summary>
|
||||
public int RAMPaged;
|
||||
|
||||
/// <summary>
|
||||
/// Signs that all paging is disabled
|
||||
/// If this is TRUE, then 128k and above machines need a hard reset before paging is allowed again
|
||||
/// </summary>
|
||||
protected bool PagingDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the currently paged ROM
|
||||
/// 128k, +2/2a and +3 only
|
||||
/// </summary>
|
||||
protected int ROMPaged;
|
||||
public virtual int _ROMpaged
|
||||
{
|
||||
get { return ROMPaged; }
|
||||
set { ROMPaged = value; }
|
||||
}
|
||||
|
||||
/*
|
||||
* +3/+2A only
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// High bit of the ROM selection (in normal paging mode)
|
||||
/// </summary>
|
||||
protected bool ROMhigh = false;
|
||||
|
||||
/// <summary>
|
||||
/// Low bit of the ROM selection (in normal paging mode)
|
||||
/// </summary>
|
||||
protected bool ROMlow = false;
|
||||
|
||||
/// <summary>
|
||||
/// Signs that the +2a/+3 special paging mode is activated
|
||||
/// </summary>
|
||||
protected bool SpecialPagingMode;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current special paging mode (0-3)
|
||||
/// </summary>
|
||||
protected int PagingConfiguration;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Memory Related Methods
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading from the bus
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public abstract byte ReadBus(ushort addr);
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a value onto the data bus that should be valid as long as the interrupt is true
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public virtual byte PushBus()
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates writing to the bus
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public virtual void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
throw new NotImplementedException("Must be overriden");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public abstract byte ReadMemory(ushort addr);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public abstract void WriteMemory(ushort addr, byte value);
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
public abstract void InitROM(RomData romData);
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public virtual byte FetchScreenMemory(ushort addr)
|
||||
{
|
||||
var value = ReadBus((ushort)((addr & 0x3FFF) + 0x4000));
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// Detects whether this is a 48k machine (or a 128k in 48k mode)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool IsIn48kMode()
|
||||
{
|
||||
if (this.GetType() == typeof(ZX48) ||
|
||||
this.GetType() == typeof(ZX16) ||
|
||||
PagingDisabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Monitors ROM access
|
||||
/// Used to auto start/stop the tape device when appropriate
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public virtual void TestForTapeTraps(int addr)
|
||||
{
|
||||
if (TapeDevice.TapeIsPlaying)
|
||||
{
|
||||
// THE 'ERROR' RESTART
|
||||
if (addr == 8)
|
||||
{
|
||||
TapeDevice?.AutoStopTape();
|
||||
return;
|
||||
}
|
||||
|
||||
// THE 'ED-ERROR' SUBROUTINE
|
||||
if (addr == 4223)
|
||||
{
|
||||
TapeDevice?.AutoStopTape();
|
||||
return;
|
||||
}
|
||||
|
||||
// THE 'ERROR-2' ROUTINE
|
||||
if (addr == 83)
|
||||
{
|
||||
TapeDevice?.AutoStopTape();
|
||||
return;
|
||||
}
|
||||
|
||||
// THE 'MASKABLE INTERRUPT' ROUTINE
|
||||
if (addr == 56)
|
||||
{
|
||||
//TapeDevice?.AutoStopTape();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// THE 'LD-BYTES' SUBROUTINE
|
||||
if (addr == 1366)
|
||||
{
|
||||
TapeDevice?.AutoStartTape();
|
||||
return;
|
||||
}
|
||||
|
||||
// THE 'LD-EDGE-2' AND 'LD-EDGE-1' SUBROUTINES
|
||||
if (addr == 1507)
|
||||
{
|
||||
TapeDevice?.AutoStartTape();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The abstract class that all emulated models will inherit from
|
||||
/// * Port Access *
|
||||
/// </summary>
|
||||
public abstract partial class SpectrumBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The last OUT data that was sent to the ULA
|
||||
/// </summary>
|
||||
protected byte LastULAOutByte;
|
||||
public byte LASTULAOutByte
|
||||
{
|
||||
get { return LastULAOutByte; }
|
||||
set { LastULAOutByte = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public abstract byte ReadPort(ushort port);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="value"></param>
|
||||
public abstract void WritePort(ushort port, byte value);
|
||||
|
||||
/// <summary>
|
||||
/// Increments the CPU totalCycles counter by the tStates value specified
|
||||
/// </summary>
|
||||
/// <param name="tStates"></param>
|
||||
public virtual void PortContention(int tStates)
|
||||
{
|
||||
CPU.TotalExecutedCycles += tStates;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates IO port contention based on the supplied address
|
||||
/// This method is for 48k and 128k/+2 machines only and should be overridden for other models
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public virtual void ContendPortAddress(ushort addr)
|
||||
{
|
||||
/*
|
||||
It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port. As is the case with memory access,
|
||||
this can be lengthened by the ULA. There are two effects which occur here:
|
||||
|
||||
If the port address being accessed has its low bit reset, the ULA is required to supply the result, which leads to a delay if it is
|
||||
currently busy handling the screen.
|
||||
The address of the port being accessed is placed on the data bus. If this is in the range 0x4000 to 0x7fff, the ULA treats this as an
|
||||
attempted access to contended memory and therefore introduces a delay. If the port being accessed is between 0xc000 and 0xffff,
|
||||
this effect does not apply, even on a 128K machine if a contended memory bank is paged into the range 0xc000 to 0xffff.
|
||||
|
||||
These two effects combine to lead to the following contention patterns:
|
||||
|
||||
High byte | |
|
||||
in 40 - 7F? | Low bit | Contention pattern
|
||||
------------+---------+-------------------
|
||||
No | Reset | N:1, C:3
|
||||
No | Set | N:4
|
||||
Yes | Reset | C:1, C:3
|
||||
Yes | Set | C:1, C:1, C:1, C:1
|
||||
|
||||
The 'Contention pattern' column should be interpreted from left to right. An "N:n" entry means that no delay is applied at this cycle, and the Z80 continues uninterrupted for 'n' T states. A "C:n" entry means that the ULA halts the Z80; the delay is exactly the same as would occur for a contended memory access at this cycle (eg 6 T states at cycle 14335, 5 at 14336, etc on the 48K machine). After this delay, the Z80 then continues for 'n' cycles.
|
||||
*/
|
||||
|
||||
// is the low bit reset (i.e. is this addressing the ULA)?
|
||||
bool lowBit = (addr & 0x0001) != 0;
|
||||
|
||||
if ((addr & 0xc000) == 0x4000 || (addr & 0xc000) == 0xC000)
|
||||
{
|
||||
// high byte is in 40 - 7F
|
||||
if (lowBit)
|
||||
{
|
||||
// lowbit is set
|
||||
// C:1, C:1, C:1, C:1
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
CPU.TotalExecutedCycles++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// low bit is reset
|
||||
// C:1, C:3
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
CPU.TotalExecutedCycles++;
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
CPU.TotalExecutedCycles += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// high byte is NOT in 40 - 7F
|
||||
if (lowBit)
|
||||
{
|
||||
// lowbit is set
|
||||
// C:1, C:1, C:1, C:1
|
||||
CPU.TotalExecutedCycles += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// lowbit is reset
|
||||
// N:1, C:3
|
||||
CPU.TotalExecutedCycles++;
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
CPU.TotalExecutedCycles += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The abstract class that all emulated models will inherit from
|
||||
/// * Main properties / fields / contruction*
|
||||
/// </summary>
|
||||
public abstract partial class SpectrumBase
|
||||
{
|
||||
#region Devices
|
||||
|
||||
/// <summary>
|
||||
/// The calling ZXSpectrum class (piped in via constructor)
|
||||
/// </summary>
|
||||
public ZXSpectrum Spectrum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the instantiated Z80 cpu (piped in via constructor)
|
||||
/// </summary>
|
||||
public Z80A CPU { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ROM and extended info
|
||||
/// </summary>
|
||||
public RomData RomData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The emulated ULA device
|
||||
/// </summary>
|
||||
public ULABase ULADevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The spectrum buzzer/beeper
|
||||
/// </summary>
|
||||
public IBeeperDevice BuzzerDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Device representing the AY-3-8912 chip found in the 128k and up spectrums
|
||||
/// </summary>
|
||||
public IPSG AYDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The spectrum keyboard
|
||||
/// </summary>
|
||||
public virtual IKeyboard KeyboardDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The spectrum datacorder device
|
||||
/// </summary>
|
||||
public virtual DatacorderDevice TapeDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the currently selected joysticks
|
||||
/// </summary>
|
||||
public virtual IJoystick[] JoystickCollection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether the disk motor is on or off
|
||||
/// </summary>
|
||||
protected bool DiskMotorState;
|
||||
|
||||
/// <summary>
|
||||
/// +3/2a printer port strobe
|
||||
/// </summary>
|
||||
protected bool PrinterPortStrobe;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Emulator State
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether the frame has ended
|
||||
/// </summary>
|
||||
public bool FrameCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Overflow from the previous frame (in Z80 cycles)
|
||||
/// </summary>
|
||||
public int OverFlow;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of frames rendered
|
||||
/// </summary>
|
||||
public int FrameCount;
|
||||
|
||||
/// <summary>
|
||||
/// The current cycle (T-State) that we are at in the frame
|
||||
/// </summary>
|
||||
public long _frameCycles;
|
||||
|
||||
/// <summary>
|
||||
/// Stores where we are in the frame after each CPU cycle
|
||||
/// </summary>
|
||||
public long LastFrameStartCPUTick;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current frame cycle according to the CPU tick count
|
||||
/// </summary>
|
||||
public virtual long CurrentFrameCycle => CPU.TotalExecutedCycles - LastFrameStartCPUTick;
|
||||
|
||||
/// <summary>
|
||||
/// Non-Deterministic bools
|
||||
/// </summary>
|
||||
public bool _render;
|
||||
public bool _renderSound;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Mask constants & misc
|
||||
/// </summary>
|
||||
protected const int BORDER_BIT = 0x07;
|
||||
protected const int EAR_BIT = 0x10;
|
||||
protected const int MIC_BIT = 0x08;
|
||||
protected const int TAPE_BIT = 0x40;
|
||||
protected const int AY_SAMPLE_RATE = 16;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Emulation Loop
|
||||
|
||||
/// <summary>
|
||||
/// Executes a single frame
|
||||
/// </summary>
|
||||
public virtual void ExecuteFrame(bool render, bool renderSound)
|
||||
{
|
||||
InputRead = false;
|
||||
_render = render;
|
||||
_renderSound = renderSound;
|
||||
|
||||
FrameCompleted = false;
|
||||
|
||||
TapeDevice.StartFrame();
|
||||
|
||||
if (_renderSound)
|
||||
{
|
||||
BuzzerDevice.StartFrame();
|
||||
if (AYDevice != null)
|
||||
AYDevice.StartFrame();
|
||||
}
|
||||
|
||||
PollInput();
|
||||
|
||||
while (CurrentFrameCycle < ULADevice.FrameLength)
|
||||
{
|
||||
// check for interrupt
|
||||
ULADevice.CheckForInterrupt(CurrentFrameCycle);
|
||||
|
||||
// run a single CPU instruction
|
||||
CPU.ExecuteOne();
|
||||
|
||||
// update AY
|
||||
int ayCnt = 0;
|
||||
if (_renderSound)
|
||||
{
|
||||
if (AYDevice != null)
|
||||
{
|
||||
//AYDevice.UpdateSound(CurrentFrameCycle);
|
||||
if (ayCnt > 10)
|
||||
{
|
||||
//AYDevice.UpdateSound(CurrentFrameCycle);
|
||||
ayCnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have reached the end of a frame
|
||||
LastFrameStartCPUTick = CPU.TotalExecutedCycles - OverFlow;
|
||||
|
||||
// paint the buffer if needed
|
||||
if (ULADevice.needsPaint && _render)
|
||||
ULADevice.UpdateScreenBuffer(ULADevice.FrameLength);
|
||||
|
||||
if (_renderSound)
|
||||
BuzzerDevice.EndFrame();
|
||||
|
||||
if (AYDevice != null)
|
||||
AYDevice.EndFrame();
|
||||
|
||||
FrameCount++;
|
||||
|
||||
// setup for next frame
|
||||
ULADevice.ResetInterrupt();
|
||||
|
||||
TapeDevice.EndFrame();
|
||||
|
||||
FrameCompleted = true;
|
||||
|
||||
// is this a lag frame?
|
||||
Spectrum.IsLagFrame = !InputRead;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reset Functions
|
||||
|
||||
/// <summary>
|
||||
/// Hard reset of the emulated machine
|
||||
/// </summary>
|
||||
public virtual void HardReset()
|
||||
{
|
||||
ULADevice.ResetInterrupt();
|
||||
ROMPaged = 0;
|
||||
SpecialPagingMode = false;
|
||||
RAMPaged = 0;
|
||||
CPU.RegPC = 0;
|
||||
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IY", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IX", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("HL", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow HL", 0xFFFF);
|
||||
|
||||
CPU.Regs[CPU.I] = 0;
|
||||
CPU.Regs[CPU.R] = 0;
|
||||
|
||||
TapeDevice.Reset();
|
||||
if (AYDevice != null)
|
||||
AYDevice.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Soft reset of the emulated machine
|
||||
/// </summary>
|
||||
public virtual void SoftReset()
|
||||
{
|
||||
ULADevice.ResetInterrupt();
|
||||
ROMPaged = 0;
|
||||
SpecialPagingMode = false;
|
||||
RAMPaged = 0;
|
||||
CPU.RegPC = 0;
|
||||
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IY", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IX", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("HL", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow HL", 0xFFFF);
|
||||
|
||||
CPU.Regs[CPU.I] = 0;
|
||||
CPU.Regs[CPU.R] = 0;
|
||||
|
||||
TapeDevice.Reset();
|
||||
if (AYDevice != null)
|
||||
AYDevice.Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStatable
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("ZXMachine");
|
||||
ser.Sync("FrameCompleted", ref FrameCompleted);
|
||||
ser.Sync("OverFlow", ref OverFlow);
|
||||
ser.Sync("FrameCount", ref FrameCount);
|
||||
ser.Sync("_frameCycles", ref _frameCycles);
|
||||
ser.Sync("inputRead", ref inputRead);
|
||||
ser.Sync("LastFrameStartCPUTick", ref LastFrameStartCPUTick);
|
||||
ser.Sync("LastULAOutByte", ref LastULAOutByte);
|
||||
ser.Sync("ROM0", ref ROM0, false);
|
||||
ser.Sync("ROM1", ref ROM1, false);
|
||||
ser.Sync("ROM2", ref ROM2, false);
|
||||
ser.Sync("ROM3", ref ROM3, false);
|
||||
ser.Sync("RAM0", ref RAM0, false);
|
||||
ser.Sync("RAM1", ref RAM1, false);
|
||||
ser.Sync("RAM2", ref RAM2, false);
|
||||
ser.Sync("RAM3", ref RAM3, false);
|
||||
ser.Sync("RAM4", ref RAM4, false);
|
||||
ser.Sync("RAM5", ref RAM5, false);
|
||||
ser.Sync("RAM6", ref RAM6, false);
|
||||
ser.Sync("RAM7", ref RAM7, false);
|
||||
ser.Sync("ROMPaged", ref ROMPaged);
|
||||
ser.Sync("SHADOWPaged", ref SHADOWPaged);
|
||||
ser.Sync("RAMPaged", ref RAMPaged);
|
||||
ser.Sync("PagingDisabled", ref PagingDisabled);
|
||||
ser.Sync("SpecialPagingMode", ref SpecialPagingMode);
|
||||
ser.Sync("PagingConfiguration", ref PagingConfiguration);
|
||||
ser.Sync("ROMhigh", ref ROMhigh);
|
||||
ser.Sync("ROMlow", ref ROMlow);
|
||||
|
||||
RomData.SyncState(ser);
|
||||
KeyboardDevice.SyncState(ser);
|
||||
BuzzerDevice.SyncState(ser);
|
||||
ULADevice.SyncState(ser);
|
||||
|
||||
if (AYDevice != null)
|
||||
AYDevice.SyncState(ser);
|
||||
|
||||
ser.Sync("tapeMediaIndex", ref tapeMediaIndex);
|
||||
TapeMediaIndex = tapeMediaIndex;
|
||||
|
||||
ser.Sync("diskMediaIndex", ref diskMediaIndex);
|
||||
DiskMediaIndex = diskMediaIndex;
|
||||
|
||||
TapeDevice.SyncState(ser);
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,760 @@
|
|||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// ULA (Uncommitted Logic Array) implementation
|
||||
/// </summary>
|
||||
public abstract class ULABase : IVideoProvider
|
||||
{
|
||||
#region General
|
||||
|
||||
/// <summary>
|
||||
/// Length of the frame in T-States
|
||||
/// </summary>
|
||||
public int FrameLength;
|
||||
|
||||
/// <summary>
|
||||
/// Emulated clock speed
|
||||
/// </summary>
|
||||
public int ClockSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// Whether machine is late or early timing model
|
||||
/// </summary>
|
||||
public bool LateTiming; //currently not implemented
|
||||
|
||||
/// <summary>
|
||||
/// The current cycle within the current frame
|
||||
/// </summary>
|
||||
public int CurrentTStateInFrame;
|
||||
|
||||
|
||||
protected SpectrumBase _machine;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Palettes
|
||||
|
||||
/// <summary>
|
||||
/// The standard ULA palette
|
||||
/// </summary>
|
||||
private static readonly int[] ULAPalette =
|
||||
{
|
||||
Colors.ARGB(0x00, 0x00, 0x00), // Black
|
||||
Colors.ARGB(0x00, 0x00, 0xD7), // Blue
|
||||
Colors.ARGB(0xD7, 0x00, 0x00), // Red
|
||||
Colors.ARGB(0xD7, 0x00, 0xD7), // Magenta
|
||||
Colors.ARGB(0x00, 0xD7, 0x00), // Green
|
||||
Colors.ARGB(0x00, 0xD7, 0xD7), // Cyan
|
||||
Colors.ARGB(0xD7, 0xD7, 0x00), // Yellow
|
||||
Colors.ARGB(0xD7, 0xD7, 0xD7), // White
|
||||
Colors.ARGB(0x00, 0x00, 0x00), // Bright Black
|
||||
Colors.ARGB(0x00, 0x00, 0xFF), // Bright Blue
|
||||
Colors.ARGB(0xFF, 0x00, 0x00), // Bright Red
|
||||
Colors.ARGB(0xFF, 0x00, 0xFF), // Bright Magenta
|
||||
Colors.ARGB(0x00, 0xFF, 0x00), // Bright Green
|
||||
Colors.ARGB(0x00, 0xFF, 0xFF), // Bright Cyan
|
||||
Colors.ARGB(0xFF, 0xFF, 0x00), // Bright Yellow
|
||||
Colors.ARGB(0xFF, 0xFF, 0xFF), // Bright White
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contention
|
||||
|
||||
/// <summary>
|
||||
/// T-State at which to start applying contention
|
||||
/// </summary>
|
||||
public int contentionStartPeriod;
|
||||
/// <summary>
|
||||
/// T-State at which to end applying contention
|
||||
/// </summary>
|
||||
public int contentionEndPeriod;
|
||||
/// <summary>
|
||||
/// T-State memory contention delay mapping
|
||||
/// </summary>
|
||||
public byte[] contentionTable;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Screen Rendering
|
||||
|
||||
/// <summary>
|
||||
/// Video output buffer
|
||||
/// </summary>
|
||||
public int[] ScreenBuffer;
|
||||
/// <summary>
|
||||
/// Display memory
|
||||
/// </summary>
|
||||
protected byte[] screen;
|
||||
/// <summary>
|
||||
/// Attribute memory lookup (mapped 1:1 to screen for convenience)
|
||||
/// </summary>
|
||||
protected short[] attr;
|
||||
/// <summary>
|
||||
/// T-State display mapping
|
||||
/// </summary>
|
||||
protected short[] tstateToDisp;
|
||||
/// <summary>
|
||||
/// Table that stores T-State to screen/attribute address values
|
||||
/// </summary>
|
||||
public short[] floatingBusTable;
|
||||
/// <summary>
|
||||
/// Cycle at which the last render update took place
|
||||
/// </summary>
|
||||
protected long lastTState;
|
||||
/// <summary>
|
||||
/// T-States elapsed since last render update
|
||||
/// </summary>
|
||||
protected long elapsedTStates;
|
||||
/// <summary>
|
||||
/// T-State of top left raster pixel
|
||||
/// </summary>
|
||||
protected int actualULAStart;
|
||||
/// <summary>
|
||||
/// Offset into display memory based on current T-State
|
||||
/// </summary>
|
||||
protected int screenByteCtr;
|
||||
/// <summary>
|
||||
/// Offset into current pixel of rasterizer
|
||||
/// </summary>
|
||||
protected int ULAByteCtr;
|
||||
/// <summary>
|
||||
/// The current border colour
|
||||
/// </summary>
|
||||
public int borderColour;
|
||||
/// <summary>
|
||||
/// Signs whether the colour flash is ON or OFF
|
||||
/// </summary>
|
||||
protected bool flashOn = false;
|
||||
|
||||
|
||||
protected int flashCounter;
|
||||
public int FlashCounter
|
||||
{
|
||||
get { return flashCounter; }
|
||||
set
|
||||
{
|
||||
flashCounter = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Internal frame counter used for flasher operations
|
||||
/// </summary>
|
||||
protected int frameCounter = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Last 8-bit bitmap read from display memory
|
||||
/// (Floating bus implementation)
|
||||
/// </summary>
|
||||
protected int lastPixelValue;
|
||||
/// <summary>
|
||||
/// Last 8-bit attr val read from attribute memory
|
||||
/// (Floating bus implementation)
|
||||
/// </summary>
|
||||
protected int lastAttrValue;
|
||||
/// <summary>
|
||||
/// Last 8-bit bitmap read from display memory+1
|
||||
/// (Floating bus implementation)
|
||||
/// </summary>
|
||||
protected int lastPixelValuePlusOne;
|
||||
/// <summary>
|
||||
/// Last 8-bit attr val read from attribute memory+1
|
||||
/// (Floating bus implementation)
|
||||
/// </summary>
|
||||
protected int lastAttrValuePlusOne;
|
||||
|
||||
/// <summary>
|
||||
/// Used to create the non-border display area
|
||||
/// </summary>
|
||||
protected int TtateAtLeft;
|
||||
protected int TstateWidth;
|
||||
protected int TstateAtTop;
|
||||
protected int TstateHeight;
|
||||
protected int TstateAtRight;
|
||||
protected int TstateAtBottom;
|
||||
|
||||
/// <summary>
|
||||
/// Total T-States in one scanline
|
||||
/// </summary>
|
||||
protected int TstatesPerScanline;
|
||||
/// <summary>
|
||||
/// Total pixels in one scanline
|
||||
/// </summary>
|
||||
protected int ScanLineWidth;
|
||||
/// <summary>
|
||||
/// Total chars in one PRINT row
|
||||
/// </summary>
|
||||
protected int CharRows;
|
||||
/// <summary>
|
||||
/// Total chars in one PRINT column
|
||||
/// </summary>
|
||||
protected int CharCols;
|
||||
/// <summary>
|
||||
/// Total pixels in one display row
|
||||
/// </summary>
|
||||
protected int ScreenWidth;
|
||||
/// <summary>
|
||||
/// Total pixels in one display column
|
||||
/// </summary>
|
||||
protected int ScreenHeight;
|
||||
/// <summary>
|
||||
/// Total pixels in top border
|
||||
/// </summary>
|
||||
protected int BorderTopHeight;
|
||||
/// <summary>
|
||||
/// Total pixels in bottom border
|
||||
/// </summary>
|
||||
protected int BorderBottomHeight;
|
||||
/// <summary>
|
||||
/// Total pixels in left border width
|
||||
/// </summary>
|
||||
protected int BorderLeftWidth;
|
||||
/// <summary>
|
||||
/// Total pixels in right border width
|
||||
/// </summary>
|
||||
protected int BorderRightWidth;
|
||||
/// <summary>
|
||||
/// Memory address of display start
|
||||
/// </summary>
|
||||
protected int DisplayStart;
|
||||
/// <summary>
|
||||
/// Total number of bytes of display memory
|
||||
/// </summary>
|
||||
protected int DisplayLength;
|
||||
/// <summary>
|
||||
/// Memory address of attribute start
|
||||
/// </summary>
|
||||
protected int AttributeStart;
|
||||
/// <summary>
|
||||
/// Total number of bytes of attribute memory
|
||||
/// </summary>
|
||||
protected int AttributeLength;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when ULA has finished painting the entire screen
|
||||
/// </summary>
|
||||
public bool needsPaint = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Interrupt
|
||||
|
||||
/// <summary>
|
||||
/// The number of T-States that the INT pin is simulated to be held low
|
||||
/// </summary>
|
||||
public int InterruptPeriod;
|
||||
|
||||
/// <summary>
|
||||
/// The longest instruction cycle count
|
||||
/// </summary>
|
||||
protected int LongestOperationCycles = 23;
|
||||
|
||||
/// <summary>
|
||||
/// Signs that an interrupt has been raised in this frame.
|
||||
/// </summary>
|
||||
protected bool InterruptRaised;
|
||||
|
||||
/// <summary>
|
||||
/// Signs that the interrupt signal has been revoked
|
||||
/// </summary>
|
||||
protected bool InterruptRevoked;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the interrupt - this should happen every frame in order to raise
|
||||
/// the VBLANK interrupt in the proceding frame
|
||||
/// </summary>
|
||||
public virtual void ResetInterrupt()
|
||||
{
|
||||
InterruptRaised = false;
|
||||
InterruptRevoked = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates an interrupt in the current phase if needed
|
||||
/// </summary>
|
||||
/// <param name="currentCycle"></param>
|
||||
public virtual void CheckForInterrupt(long currentCycle)
|
||||
{
|
||||
if (InterruptRevoked)
|
||||
{
|
||||
// interrupt has already been handled
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentCycle < LongestOperationCycles)// InterruptPeriod)
|
||||
{
|
||||
// interrupt does not need to be raised yet
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentCycle >= InterruptPeriod + LongestOperationCycles)
|
||||
{
|
||||
// interrupt should have already been raised and the cpu may or
|
||||
// may not have caught it. The time has passed so revoke the signal
|
||||
InterruptRevoked = true;
|
||||
_machine.CPU.FlagI = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (InterruptRaised)
|
||||
{
|
||||
// INT is raised but not yet revoked
|
||||
// CPU has NOT handled it yet
|
||||
return;
|
||||
}
|
||||
|
||||
// Raise the interrupt
|
||||
InterruptRaised = true;
|
||||
_machine.CPU.FlagI = true;
|
||||
|
||||
// Signal the start of ULA processing
|
||||
if (_machine._render)
|
||||
ULAUpdateStart();
|
||||
|
||||
CalcFlashCounter();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction & Initialisation
|
||||
|
||||
public ULABase(SpectrumBase machine)
|
||||
{
|
||||
_machine = machine;
|
||||
borderType = _machine.Spectrum.SyncSettings.BorderType;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Resets the ULA chip
|
||||
/// </summary>
|
||||
public abstract void Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Builds the contention table for the emulated model
|
||||
/// </summary>
|
||||
public abstract void BuildContentionTable();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given memory address should be contended
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool IsContended(int addr);
|
||||
|
||||
/// <summary>
|
||||
/// Contends the machine for a given address
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public virtual void Contend(ushort addr)
|
||||
{
|
||||
if (IsContended(addr) && !(_machine is ZX128Plus3))
|
||||
{
|
||||
_machine.CPU.TotalExecutedCycles += contentionTable[CurrentTStateInFrame];
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Contend(int addr, int time, int count)
|
||||
{
|
||||
if (IsContended(addr) && !(_machine is ZX128Plus3))
|
||||
{
|
||||
for (int f = 0; f < count; f++)
|
||||
{
|
||||
_machine.CPU.TotalExecutedCycles += contentionTable[CurrentTStateInFrame] + time;
|
||||
}
|
||||
}
|
||||
else
|
||||
_machine.CPU.TotalExecutedCycles += count * time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets render state once interrupt is generated
|
||||
/// </summary>
|
||||
public void ULAUpdateStart()
|
||||
{
|
||||
ULAByteCtr = 0;
|
||||
screenByteCtr = DisplayStart;
|
||||
lastTState = actualULAStart;
|
||||
needsPaint = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flash processing
|
||||
/// </summary>
|
||||
public void CalcFlashCounter()
|
||||
{
|
||||
flashCounter++;
|
||||
|
||||
if (flashCounter > 15)
|
||||
{
|
||||
flashOn = !flashOn;
|
||||
flashCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the T-State to attribute map used with the floating bus
|
||||
/// </summary>
|
||||
public void BuildAttributeMap()
|
||||
{
|
||||
int start = DisplayStart;
|
||||
|
||||
for (int f = 0; f < DisplayLength; f++, start++)
|
||||
{
|
||||
int addrH = start >> 8; //div by 256
|
||||
int addrL = start % 256;
|
||||
|
||||
int pixelY = (addrH & 0x07);
|
||||
pixelY |= (addrL & (0xE0)) >> 2;
|
||||
pixelY |= (addrH & (0x18)) << 3;
|
||||
|
||||
int attrIndex_Y = AttributeStart + ((pixelY >> 3) << 5);// pixel/8 * 32
|
||||
|
||||
addrL = start % 256;
|
||||
int pixelX = addrL & (0x1F);
|
||||
|
||||
attr[f] = (short)(attrIndex_Y + pixelX);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the screen buffer based on the number of T-States supplied
|
||||
/// </summary>
|
||||
/// <param name="_tstates"></param>
|
||||
public virtual void UpdateScreenBuffer(long _tstates)
|
||||
{
|
||||
if (_tstates < actualULAStart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (_tstates >= FrameLength)
|
||||
{
|
||||
_tstates = FrameLength - 1;
|
||||
|
||||
needsPaint = true;
|
||||
}
|
||||
|
||||
//the additional 1 tstate is required to get correct number of bytes to output in ircontention.sna
|
||||
elapsedTStates = (_tstates + 1 - lastTState) - 1;
|
||||
|
||||
//It takes 4 tstates to write 1 byte. Or, 2 pixels per t-state.
|
||||
|
||||
long numBytes = (elapsedTStates >> 2) + ((elapsedTStates % 4) > 0 ? 1 : 0);
|
||||
|
||||
int pixelData;
|
||||
int pixel2Data = 0xff;
|
||||
int attrData;
|
||||
int attr2Data;
|
||||
int bright;
|
||||
int ink;
|
||||
int paper;
|
||||
int flash;
|
||||
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
{
|
||||
if (tstateToDisp[lastTState] > 1)
|
||||
{
|
||||
screenByteCtr = tstateToDisp[lastTState] - 16384; //adjust for actual screen offset
|
||||
|
||||
pixelData = _machine.FetchScreenMemory((ushort)screenByteCtr); //screen[screenByteCtr];
|
||||
attrData = _machine.FetchScreenMemory((ushort)(attr[screenByteCtr] - 16384)); //screen[attr[screenByteCtr] - 16384];
|
||||
|
||||
lastPixelValue = pixelData;
|
||||
lastAttrValue = attrData;
|
||||
|
||||
bright = (attrData & 0x40) >> 3;
|
||||
flash = (attrData & 0x80) >> 7;
|
||||
ink = (attrData & 0x07);
|
||||
paper = ((attrData >> 3) & 0x7);
|
||||
int paletteInk = ULAPalette[ink + bright];
|
||||
int palettePaper = ULAPalette[paper + bright];
|
||||
|
||||
if (flashOn && (flash != 0)) //swap paper and ink when flash is on
|
||||
{
|
||||
int temp = paletteInk;
|
||||
paletteInk = palettePaper;
|
||||
palettePaper = temp;
|
||||
}
|
||||
|
||||
for (int a = 0; a < 8; ++a)
|
||||
{
|
||||
if ((pixelData & 0x80) != 0)
|
||||
{
|
||||
ScreenBuffer[ULAByteCtr++] = paletteInk;
|
||||
lastAttrValue = ink;
|
||||
//pixelIsPaper = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScreenBuffer[ULAByteCtr++] = palettePaper;
|
||||
lastAttrValue = paper;
|
||||
}
|
||||
pixelData <<= 1;
|
||||
}
|
||||
}
|
||||
else if (tstateToDisp[lastTState] == 1)
|
||||
{
|
||||
int bor = ULAPalette[borderColour];
|
||||
|
||||
for (int g = 0; g < 8; g++)
|
||||
ScreenBuffer[ULAByteCtr++] = bor;
|
||||
}
|
||||
lastTState += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IVideoProvider
|
||||
|
||||
private int _virtualWidth;
|
||||
private int _virtualHeight;
|
||||
private int _bufferWidth;
|
||||
private int _bufferHeight;
|
||||
|
||||
public int BackgroundColor
|
||||
{
|
||||
get { return ULAPalette[7]; } //ULAPalette[borderColour]; }
|
||||
}
|
||||
|
||||
public int VirtualWidth
|
||||
{
|
||||
get { return _virtualWidth; }
|
||||
set { _virtualWidth = value; }
|
||||
}
|
||||
|
||||
public int VirtualHeight
|
||||
{
|
||||
get { return _virtualHeight; }
|
||||
set { _virtualHeight = value; }
|
||||
}
|
||||
|
||||
public int BufferWidth
|
||||
{
|
||||
get { return _bufferWidth; }
|
||||
set { _bufferWidth = value; }
|
||||
}
|
||||
|
||||
public int BufferHeight
|
||||
{
|
||||
get { return _bufferHeight; }
|
||||
set { _bufferHeight = value; }
|
||||
}
|
||||
|
||||
public int VsyncNumerator
|
||||
{
|
||||
get { return ClockSpeed; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public int VsyncDenominator
|
||||
{
|
||||
get { return FrameLength; }
|
||||
}
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
switch (borderType)
|
||||
{
|
||||
// Full side borders, no top or bottom border (giving *almost* 16:9 output)
|
||||
case ZXSpectrum.BorderType.Widescreen:
|
||||
// we are cropping out the top and bottom borders
|
||||
var startPixelsToCrop = ScanLineWidth * BorderTopHeight;
|
||||
var endPixelsToCrop = ScanLineWidth * BorderBottomHeight;
|
||||
int index = 0;
|
||||
for (int i = startPixelsToCrop; i < ScreenBuffer.Length - endPixelsToCrop; i++)
|
||||
{
|
||||
croppedBuffer[index++] = ScreenBuffer[i];
|
||||
}
|
||||
return croppedBuffer;
|
||||
|
||||
// The full spectrum border
|
||||
case ZXSpectrum.BorderType.Full:
|
||||
return ScreenBuffer;
|
||||
|
||||
case ZXSpectrum.BorderType.Medium:
|
||||
// all border sizes now 24
|
||||
var lR = BorderLeftWidth - 24;
|
||||
var rR = BorderRightWidth - 24;
|
||||
var tR = BorderTopHeight - 24;
|
||||
var bR = BorderBottomHeight - 24;
|
||||
var startP = ScanLineWidth * tR;
|
||||
var endP = ScanLineWidth * bR;
|
||||
|
||||
int index2 = 0;
|
||||
// line by line
|
||||
for (int i = startP; i < ScreenBuffer.Length - endP; i += ScreenWidth + BorderLeftWidth + BorderRightWidth)
|
||||
{
|
||||
// each pixel in each line
|
||||
for (int p = lR; p < ScreenWidth + BorderLeftWidth + BorderRightWidth - rR; p++)
|
||||
{
|
||||
if (index2 == croppedBuffer.Length)
|
||||
break;
|
||||
croppedBuffer[index2++] = ScreenBuffer[i + p];
|
||||
}
|
||||
}
|
||||
|
||||
return croppedBuffer;
|
||||
|
||||
case ZXSpectrum.BorderType.Small:
|
||||
// all border sizes now 24
|
||||
var lR_ = BorderLeftWidth - 10;
|
||||
var rR_ = BorderRightWidth - 10;
|
||||
var tR_ = BorderTopHeight - 10;
|
||||
var bR_ = BorderBottomHeight - 10;
|
||||
var startP_ = ScanLineWidth * tR_;
|
||||
var endP_ = ScanLineWidth * bR_;
|
||||
|
||||
int index2_ = 0;
|
||||
// line by line
|
||||
for (int i = startP_; i < ScreenBuffer.Length - endP_; i += ScreenWidth + BorderLeftWidth + BorderRightWidth)
|
||||
{
|
||||
// each pixel in each line
|
||||
for (int p = lR_; p < ScreenWidth + BorderLeftWidth + BorderRightWidth - rR_; p++)
|
||||
{
|
||||
if (index2_ == croppedBuffer.Length)
|
||||
break;
|
||||
croppedBuffer[index2_++] = ScreenBuffer[i + p];
|
||||
}
|
||||
}
|
||||
|
||||
return croppedBuffer;
|
||||
|
||||
case ZXSpectrum.BorderType.None:
|
||||
// all border sizes now 24
|
||||
var lR__ = BorderLeftWidth;
|
||||
var rR__ = BorderRightWidth;
|
||||
var tR__ = BorderTopHeight;
|
||||
var bR__ = BorderBottomHeight;
|
||||
var startP__ = ScanLineWidth * tR__;
|
||||
var endP__ = ScanLineWidth * bR__;
|
||||
|
||||
int index2__ = 0;
|
||||
// line by line
|
||||
for (int i = startP__; i < ScreenBuffer.Length - endP__; i += ScreenWidth + BorderLeftWidth + BorderRightWidth)
|
||||
{
|
||||
// each pixel in each line
|
||||
for (int p = lR__; p < ScreenWidth + BorderLeftWidth + BorderRightWidth - rR__; p++)
|
||||
{
|
||||
if (index2__ == croppedBuffer.Length)
|
||||
break;
|
||||
croppedBuffer[index2__++] = ScreenBuffer[i + p];
|
||||
}
|
||||
}
|
||||
|
||||
return croppedBuffer;
|
||||
}
|
||||
|
||||
return ScreenBuffer;
|
||||
}
|
||||
|
||||
protected void SetupScreenSize()
|
||||
{
|
||||
switch (borderType)
|
||||
{
|
||||
case ZXSpectrum.BorderType.Full:
|
||||
BufferWidth = ScreenWidth + BorderLeftWidth + BorderRightWidth;
|
||||
BufferHeight = ScreenHeight + BorderTopHeight + BorderBottomHeight;
|
||||
VirtualHeight = BufferHeight;
|
||||
VirtualWidth = BufferWidth;
|
||||
ScreenBuffer = new int[BufferWidth * BufferHeight];
|
||||
break;
|
||||
|
||||
case ZXSpectrum.BorderType.Widescreen:
|
||||
BufferWidth = ScreenWidth + BorderLeftWidth + BorderRightWidth;
|
||||
BufferHeight = ScreenHeight;
|
||||
VirtualHeight = BufferHeight;
|
||||
VirtualWidth = BufferWidth;
|
||||
croppedBuffer = new int[BufferWidth * BufferHeight];
|
||||
break;
|
||||
|
||||
case ZXSpectrum.BorderType.Medium:
|
||||
BufferWidth = ScreenWidth + (24) + (24);
|
||||
BufferHeight = ScreenHeight + (24) + (24);
|
||||
VirtualHeight = BufferHeight;
|
||||
VirtualWidth = BufferWidth;
|
||||
croppedBuffer = new int[BufferWidth * BufferHeight];
|
||||
break;
|
||||
|
||||
case ZXSpectrum.BorderType.Small:
|
||||
BufferWidth = ScreenWidth + (10) + (10);
|
||||
BufferHeight = ScreenHeight + (10) + (10);
|
||||
VirtualHeight = BufferHeight;
|
||||
VirtualWidth = BufferWidth;
|
||||
croppedBuffer = new int[BufferWidth * BufferHeight];
|
||||
break;
|
||||
|
||||
case ZXSpectrum.BorderType.None:
|
||||
BufferWidth = ScreenWidth;
|
||||
BufferHeight = ScreenHeight;
|
||||
VirtualHeight = BufferHeight;
|
||||
VirtualWidth = BufferWidth;
|
||||
croppedBuffer = new int[BufferWidth * BufferHeight];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected int[] croppedBuffer;
|
||||
|
||||
private ZXSpectrum.BorderType _borderType;
|
||||
|
||||
public ZXSpectrum.BorderType borderType
|
||||
{
|
||||
get { return _borderType; }
|
||||
set { _borderType = value; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region IStatable
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("ULA");
|
||||
ser.Sync("ScreenBuffer", ref ScreenBuffer, false);
|
||||
ser.Sync("FrameLength", ref FrameLength);
|
||||
ser.Sync("ClockSpeed", ref ClockSpeed);
|
||||
ser.Sync("LateTiming", ref LateTiming);
|
||||
ser.Sync("borderColour", ref borderColour);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Attribution
|
||||
|
||||
/*
|
||||
* Based on code from ArjunNair's Zero emulator (MIT Licensed)
|
||||
* https://github.com/ArjunNair/Zero-Emulator
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2009 Arjun Nair
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128 : SpectrumBase
|
||||
{
|
||||
/* 128k paging controlled by writes to port 0x7ffd
|
||||
*
|
||||
*
|
||||
|
||||
#7FFD (32765) - decoded as A15=0, A1=0 and /IORQ=0. Bits 0..5 are latched. Bits 0..2 select RAM bank in secton D. Bit 3 selects RAM bank to dispay screen (0 - RAM5, 1 - RAM7). Bit 4 selects ROM bank (0 - ROM0, 1 - ROM1). Bit 5, when set locks future writing to #7FFD port until reset. Reading #7FFD port is the same as writing #FF into it.
|
||||
#BFFD (49149) - write data byte into AY-3-8912 chip.
|
||||
#FFFD (65533) - select AY-3-8912 addres (D4..D7 ignored) and reading data byte.
|
||||
|
||||
* 0xffff +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
| Bank 0 | Bank 1 | Bank 2 | Bank 3 | Bank 4 | Bank 5 | Bank 6 | Bank 7 |
|
||||
| | |(also at| | |(also at| | |
|
||||
| | | 0x8000)| | | 0x4000)| | |
|
||||
| | | | | | screen | | screen |
|
||||
0xc000 +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
| Bank 2 | Any one of these pages may be switched in.
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
0x8000 +--------+
|
||||
| Bank 5 |
|
||||
| |
|
||||
| |
|
||||
| screen |
|
||||
0x4000 +--------+--------+
|
||||
| ROM 0 | ROM 1 | Either ROM may be switched in.
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
0x0000 +--------+--------+
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading from the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
byte result = 0xff;
|
||||
|
||||
switch (divisor)
|
||||
{
|
||||
// ROM 0x000
|
||||
case 0:
|
||||
TestForTapeTraps(addr % 0x4000);
|
||||
|
||||
if (ROMPaged == 0)
|
||||
result = ROM0[addr % 0x4000];
|
||||
else
|
||||
result = ROM1[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0x4000 (RAM5 - Bank5)
|
||||
case 1:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0x8000 (RAM2 - Bank2)
|
||||
case 2:
|
||||
result = RAM2[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
|
||||
case 3:
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
result = RAM1[addr % 0x4000];
|
||||
break;
|
||||
case 2:
|
||||
result = RAM2[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = RAM3[addr % 0x4000];
|
||||
break;
|
||||
case 4:
|
||||
result = RAM4[addr % 0x4000];
|
||||
break;
|
||||
case 5:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
case 6:
|
||||
result = RAM6[addr % 0x4000];
|
||||
break;
|
||||
case 7:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates writing to the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
|
||||
switch (divisor)
|
||||
{
|
||||
// ROM 0x000
|
||||
case 0:
|
||||
// cannot write to ROMs
|
||||
/*
|
||||
if (ROMPaged == 0)
|
||||
ROM0[addr % 0x4000] = value;
|
||||
else
|
||||
ROM1[addr % 0x4000] = value;
|
||||
*/
|
||||
break;
|
||||
|
||||
// RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7)
|
||||
case 1:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
|
||||
// RAM 0x8000 (RAM2 - Bank2)
|
||||
case 2:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
|
||||
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
|
||||
case 3:
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 0:
|
||||
RAM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
RAM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 2:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
RAM3[addr % 0x4000] = value;
|
||||
break;
|
||||
case 4:
|
||||
RAM4[addr % 0x4000] = value;
|
||||
break;
|
||||
case 5:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
case 6:
|
||||
RAM6[addr % 0x4000] = value;
|
||||
break;
|
||||
case 7:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
/// Will read RAM5 (screen0) by default, unless RAM7 (screen1) is selected as output
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte FetchScreenMemory(ushort addr)
|
||||
{
|
||||
byte value = new byte();
|
||||
|
||||
if (SHADOWPaged && !PagingDisabled)
|
||||
{
|
||||
// shadow screen should be outputted
|
||||
// this lives in RAM7
|
||||
value = RAM7[addr & 0x3FFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
// shadow screen is not set to display or paging is disabled (probably in 48k mode)
|
||||
// (use screen0 at RAM5)
|
||||
value = RAM5[addr & 0x3FFF];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="startAddress"></param>
|
||||
public override void InitROM(RomData romData)
|
||||
{
|
||||
RomData = romData;
|
||||
// 128k uses ROM0 and ROM1
|
||||
// 128k loader is in ROM0, and fallback 48k rom is in ROM1
|
||||
for (int i = 0; i < 0x4000; i++)
|
||||
{
|
||||
ROM0[i] = RomData.RomBytes[i];
|
||||
if (RomData.RomBytes.Length > 0x4000)
|
||||
ROM1[i] = RomData.RomBytes[i + 0x4000];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128 : SpectrumBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadPort(ushort port)
|
||||
{
|
||||
bool deviceAddressed = true;
|
||||
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
// check AY
|
||||
if (AYDevice.ReadPort(port, ref result))
|
||||
return (byte)result;
|
||||
|
||||
// Kempston joystick input takes priority over all other input
|
||||
// if this is detected just return the kempston byte
|
||||
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
|
||||
{
|
||||
if (LocateUniqueJoystick(JoystickType.Kempston) != null)
|
||||
return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
|
||||
|
||||
InputRead = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (KeyboardDevice.ReadPort(port, ref result))
|
||||
{
|
||||
// not a lagframe
|
||||
InputRead = true;
|
||||
|
||||
// process tape INs
|
||||
TapeDevice.ReadPort(port, ref result);
|
||||
}
|
||||
else
|
||||
deviceAddressed = false;
|
||||
}
|
||||
|
||||
if (!deviceAddressed)
|
||||
{
|
||||
// If this is an unused port the floating memory bus should be returned
|
||||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ULADevice.floatingBusTable[_tStates] < 0)
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// Check whether the low bit is reset
|
||||
// Technically the ULA should respond to every even I/O address
|
||||
bool lowBitReset = (port & 0x0001) == 0;
|
||||
|
||||
// Kempston joystick input takes priority over all other input
|
||||
// if this is detected just return the kempston byte
|
||||
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
|
||||
{
|
||||
if (LocateUniqueJoystick(JoystickType.Kempston) != null)
|
||||
return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
|
||||
|
||||
InputRead = true;
|
||||
}
|
||||
else if (lowBitReset)
|
||||
{
|
||||
// Even I/O address so get input from keyboard
|
||||
KeyboardDevice.ReadPort(port, ref result);
|
||||
|
||||
// not a lagframe
|
||||
InputRead = true;
|
||||
|
||||
// tape loading monitor cycle
|
||||
TapeDevice.MonitorRead();
|
||||
|
||||
// process tape INs
|
||||
TapeDevice.ReadPort(port, ref result);
|
||||
}
|
||||
else if ((port & 0xc002) == 0xc000)
|
||||
{
|
||||
// AY sound chip
|
||||
result = (int)AYDevice.PortRead();
|
||||
}
|
||||
else
|
||||
{
|
||||
// devices other than the ULA will respond here
|
||||
|
||||
// Kempston Mouse (not implemented yet)
|
||||
|
||||
|
||||
// If this is an unused port the floating memory bus should be returned
|
||||
// Floating bus is read on the previous cycle
|
||||
int _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ULADevice.floatingBusTable[_tStates] < 0)
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return (byte)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
// get a BitArray of the port
|
||||
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
|
||||
// get a BitArray of the value byte
|
||||
BitArray bits = new BitArray(new byte[] { value });
|
||||
|
||||
long currT = CPU.TotalExecutedCycles;
|
||||
|
||||
AYDevice.WritePort(port, value);
|
||||
|
||||
// paging
|
||||
if (port == 0x7ffd)
|
||||
{
|
||||
//if (PagingDisabled)
|
||||
//return;
|
||||
|
||||
// Bits 0, 1, 2 select the RAM page
|
||||
var rp = value & 0x07;
|
||||
if (rp < 8)
|
||||
RAMPaged = rp;
|
||||
|
||||
// bit 3 controls shadow screen
|
||||
SHADOWPaged = bits[3];
|
||||
|
||||
if (SHADOWPaged == false)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ROM page
|
||||
if (bits[4])
|
||||
{
|
||||
// 48k basic rom
|
||||
ROMPaged = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 128k editor and menu system
|
||||
ROMPaged = 0;
|
||||
}
|
||||
|
||||
// Bit 5 set signifies that paging is disabled until next reboot
|
||||
PagingDisabled = bits[5];
|
||||
}
|
||||
|
||||
// Check whether the low bit is reset
|
||||
// Technically the ULA should respond to every even I/O address
|
||||
bool lowBitReset = !portBits[0]; // (port & 0x01) == 0;
|
||||
|
||||
// Only even addresses address the ULA
|
||||
if (lowBitReset)
|
||||
{
|
||||
// store the last OUT byte
|
||||
LastULAOutByte = value;
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
/*
|
||||
Bit 7 6 5 4 3 2 1 0
|
||||
+-------------------------------+
|
||||
| | | | E | M | Border |
|
||||
+-------------------------------+
|
||||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
|
||||
TapeDevice.WritePort(port, value);
|
||||
|
||||
// Tape
|
||||
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
|
||||
|
||||
}
|
||||
/*
|
||||
// Active AY Register
|
||||
if ((port & 0xc002) == 0xc000)
|
||||
{
|
||||
var reg = value & 0x0f;
|
||||
AYDevice.SelectedRegister = reg;
|
||||
CPU.TotalExecutedCycles += 3;
|
||||
}
|
||||
|
||||
// AY Write
|
||||
if ((port & 0xc002) == 0x8000)
|
||||
{
|
||||
AYDevice.PortWrite(value);
|
||||
CPU.TotalExecutedCycles += 3;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
class ULA128 : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
public ULA128(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 36;
|
||||
LongestOperationCycles = 64 + 2;
|
||||
FrameLength = 70908;
|
||||
ClockSpeed = 3546900;
|
||||
|
||||
contentionTable = new byte[70930];
|
||||
floatingBusTable = new short[70930];
|
||||
for (int f = 0; f < 70930; f++)
|
||||
floatingBusTable[f] = -1;
|
||||
|
||||
CharRows = 24;
|
||||
CharCols = 32;
|
||||
ScreenWidth = 256;
|
||||
ScreenHeight = 192;
|
||||
BorderTopHeight = 48;
|
||||
BorderBottomHeight = 56;
|
||||
BorderLeftWidth = 48;
|
||||
BorderRightWidth = 48;
|
||||
DisplayStart = 16384;
|
||||
DisplayLength = 6144;
|
||||
AttributeStart = 22528;
|
||||
AttributeLength = 768;
|
||||
borderColour = 7;
|
||||
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
|
||||
|
||||
TstatesPerScanline = 228;
|
||||
TstateAtTop = BorderTopHeight * TstatesPerScanline;
|
||||
TstateAtBottom = BorderBottomHeight * TstatesPerScanline;
|
||||
tstateToDisp = new short[FrameLength];
|
||||
|
||||
ScreenBuffer = new int[ScanLineWidth * BorderTopHeight //48 lines of border
|
||||
+ ScanLineWidth * ScreenHeight //border + main + border of 192 lines
|
||||
+ ScanLineWidth * BorderBottomHeight]; //56 lines of border
|
||||
|
||||
attr = new short[DisplayLength]; //6144 bytes of display memory will be mapped
|
||||
|
||||
SetupScreenSize();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Operations
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
contentionStartPeriod = 14361; // + LateTiming;
|
||||
contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
|
||||
screen = _machine.RAM5;
|
||||
screenByteCtr = DisplayStart;
|
||||
ULAByteCtr = 0;
|
||||
actualULAStart = 14366 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
|
||||
lastTState = actualULAStart;
|
||||
BuildAttributeMap();
|
||||
BuildContentionTable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contention Methods
|
||||
|
||||
public override bool IsContended(int addr)
|
||||
{
|
||||
addr = addr & 0xc000;
|
||||
|
||||
if (addr == 0x4000)
|
||||
{
|
||||
// low port contention
|
||||
return true;
|
||||
}
|
||||
|
||||
if (addr == 0xc000)
|
||||
{
|
||||
// high port contention - check for contended bank paged in
|
||||
switch (_machine.RAMPaged)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void BuildContentionTable()
|
||||
{
|
||||
int t = contentionStartPeriod;
|
||||
while (t < contentionEndPeriod)
|
||||
{
|
||||
//for 128 t-states
|
||||
for (int i = 0; i < 128; i += 8)
|
||||
{
|
||||
contentionTable[t++] = 6;
|
||||
contentionTable[t++] = 5;
|
||||
contentionTable[t++] = 4;
|
||||
contentionTable[t++] = 3;
|
||||
contentionTable[t++] = 2;
|
||||
contentionTable[t++] = 1;
|
||||
contentionTable[t++] = 0;
|
||||
contentionTable[t++] = 0;
|
||||
}
|
||||
t += (TstatesPerScanline - 128);
|
||||
}
|
||||
|
||||
//build top half of tstateToDisp table
|
||||
//vertical retrace period
|
||||
for (t = 0; t < actualULAStart; t++)
|
||||
tstateToDisp[t] = 0;
|
||||
|
||||
//next 48 are actual border
|
||||
while (t < actualULAStart + (TstateAtTop))
|
||||
{
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
//build middle half
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
int scrval = 2;
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline))
|
||||
{
|
||||
for (int g = 0; g < 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 24; g < 24 + 128; g++)
|
||||
{
|
||||
//Map screenaddr to tstate
|
||||
if (g % 4 == 0)
|
||||
{
|
||||
scrval = (((((_y & 0xc0) >> 3) | (_y & 0x07) | (0x40)) << 8)) | (((_x >> 3) & 0x1f) | ((_y & 0x38) << 2));
|
||||
_x += 8;
|
||||
}
|
||||
tstateToDisp[t++] = (short)scrval;
|
||||
}
|
||||
_y++;
|
||||
|
||||
for (int g = 24 + 128; g < 24 + 128 + 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 24 + 128 + 24; g < 24 + 128 + 24 + 52; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
int h = contentionStartPeriod + 3;
|
||||
while (h < contentionEndPeriod + 3)
|
||||
{
|
||||
for (int j = 0; j < 128; j += 8)
|
||||
{
|
||||
floatingBusTable[h] = tstateToDisp[h + 2];
|
||||
floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)];
|
||||
floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4];
|
||||
floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)];
|
||||
h += 8;
|
||||
}
|
||||
h += TstatesPerScanline - 128;
|
||||
}
|
||||
|
||||
//build bottom half
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
|
||||
{
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128 : SpectrumBase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX128(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> joysticks)
|
||||
{
|
||||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
ROMPaged = 0;
|
||||
SHADOWPaged = false;
|
||||
RAMPaged = 0;
|
||||
PagingDisabled = false;
|
||||
|
||||
ULADevice = new ULA128(this);
|
||||
|
||||
BuzzerDevice = new Buzzer(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
AYDevice = new AYChip(this);
|
||||
AYDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
KeyboardDevice = new StandardKeyboard(this);
|
||||
|
||||
InitJoysticks(joysticks);
|
||||
|
||||
TapeDevice = new DatacorderDevice();
|
||||
TapeDevice.Init(this);
|
||||
|
||||
InitializeMedia(files);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The +2 is almost identical to the 128k from an emulation point of view
|
||||
/// There are just a few small changes in the ROMs
|
||||
/// </summary>
|
||||
public partial class ZX128Plus2 : ZX128
|
||||
{
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX128Plus2(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> joysticks)
|
||||
: base(spectrum, cpu, borderType, files, joysticks)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,429 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128Plus2a : SpectrumBase
|
||||
{
|
||||
/* http://www.worldofspectrum.org/faq/reference/128kreference.htm
|
||||
*
|
||||
* Port 0x7ffd behaves in the almost exactly the same way as on the 128K/+2, with two exceptions:
|
||||
|
||||
Bit 4 is now the low bit of the ROM selection.
|
||||
The partial decoding used is now slightly different: the hardware will respond only to those port addresses with bit 1 reset, bit 14 set and bit 15 reset (as opposed to just bits 1 and 15 reset on the 128K/+2).
|
||||
The extra paging features of the +2A/+3 are controlled by port 0x1ffd (again, partial decoding applies here: the hardware will respond to all port addresses with bit 1 reset, bit 12 set and bits 13, 14 and 15 reset). This port is also write-only, and its last value should be saved at 0x5b67 (23399).
|
||||
|
||||
Port 0x1ffd responds as follows:
|
||||
|
||||
Bit 0: Paging mode. 0=normal, 1=special
|
||||
Bit 1: In normal mode, ignored.
|
||||
Bit 2: In normal mode, high bit of ROM selection. The four ROMs are:
|
||||
ROM 0: 128k editor, menu system and self-test program
|
||||
ROM 1: 128k syntax checker
|
||||
ROM 2: +3DOS
|
||||
ROM 3: 48 BASIC
|
||||
Bit 3: Disk motor; 1=on, 0=off
|
||||
Bit 4: Printer port strobe.
|
||||
When special mode is selected, the memory map changes to one of four configurations specified in bits 1 and 2 of port 0x1ffd:
|
||||
Bit 2 =0 Bit 2 =0 Bit 2 =1 Bit 2 =1
|
||||
Bit 1 =0 Bit 1 =1 Bit 1 =0 Bit 1 =1
|
||||
0xffff +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 3 | | Bank 7 | | Bank 3 | | Bank 3 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | screen | | | | |
|
||||
0xc000 +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 2 | | Bank 6 | | Bank 6 | | Bank 6 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
0x8000 +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 1 | | Bank 5 | | Bank 5 | | Bank 7 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | screen | | screen | | screen |
|
||||
0x4000 +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 0 | | Bank 4 | | Bank 4 | | Bank 4 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
0x0000 +--------+ +--------+ +--------+ +--------+
|
||||
RAM banks 1,3,4 and 6 are used for the disc cache and RAMdisc, while Bank 7 contains editor scratchpads and +3DOS workspace.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading from the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
byte result = 0xff;
|
||||
|
||||
// special paging
|
||||
if (SpecialPagingMode)
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
result = RAM4[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
result = RAM1[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
result = RAM6[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3:
|
||||
result = RAM3[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
// ROM 0x000
|
||||
case 0:
|
||||
switch (_ROMpaged)
|
||||
{
|
||||
case 0:
|
||||
result = ROM0[addr % 0x4000];
|
||||
TestForTapeTraps(addr % 0x4000);
|
||||
break;
|
||||
case 1:
|
||||
result = ROM1[addr % 0x4000];
|
||||
TestForTapeTraps(addr % 0x4000);
|
||||
break;
|
||||
case 2:
|
||||
result = ROM2[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = ROM3[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// RAM 0x4000 (RAM5 - Bank5 always)
|
||||
case 1:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0x8000 (RAM2 - Bank2)
|
||||
case 2:
|
||||
result = RAM2[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
|
||||
case 3:
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
result = RAM1[addr % 0x4000];
|
||||
break;
|
||||
case 2:
|
||||
result = RAM2[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = RAM3[addr % 0x4000];
|
||||
break;
|
||||
case 4:
|
||||
result = RAM4[addr % 0x4000];
|
||||
break;
|
||||
case 5:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
case 6:
|
||||
result = RAM6[addr % 0x4000];
|
||||
break;
|
||||
case 7:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates writing to the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
|
||||
// special paging
|
||||
if (SpecialPagingMode)
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
RAM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
RAM4[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
RAM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
RAM6[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3:
|
||||
RAM3[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
// ROM 0x000
|
||||
case 0:
|
||||
/*
|
||||
switch (_ROMpaged)
|
||||
{
|
||||
// cannot write to ROMs
|
||||
case 0:
|
||||
ROM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
ROM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 2:
|
||||
ROM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
ROM3[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
|
||||
// RAM 0x4000 (RAM5 - Bank5 only)
|
||||
case 1:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
|
||||
// RAM 0x8000 (RAM2 - Bank2)
|
||||
case 2:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
|
||||
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
|
||||
case 3:
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 0:
|
||||
RAM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
RAM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 2:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
RAM3[addr % 0x4000] = value;
|
||||
break;
|
||||
case 4:
|
||||
RAM4[addr % 0x4000] = value;
|
||||
break;
|
||||
case 5:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
case 6:
|
||||
RAM6[addr % 0x4000] = value;
|
||||
break;
|
||||
case 7:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
/// Will read RAM5 (screen0) by default, unless RAM7 (screen1) is selected as output
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte FetchScreenMemory(ushort addr)
|
||||
{
|
||||
byte value = new byte();
|
||||
|
||||
if (SHADOWPaged && !PagingDisabled)
|
||||
{
|
||||
// shadow screen should be outputted
|
||||
// this lives in RAM7
|
||||
value = RAM7[addr & 0x3FFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
// shadow screen is not set to display or paging is disabled (probably in 48k mode)
|
||||
// (use screen0 at RAM5)
|
||||
value = RAM5[addr & 0x3FFF];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="startAddress"></param>
|
||||
public override void InitROM(RomData romData)
|
||||
{
|
||||
RomData = romData;
|
||||
// +3 uses ROM0, ROM1, ROM2 & ROM3
|
||||
/* ROM 0: 128k editor, menu system and self-test program
|
||||
ROM 1: 128k syntax checker
|
||||
ROM 2: +3DOS
|
||||
ROM 3: 48 BASIC
|
||||
*/
|
||||
Stream stream = new MemoryStream(RomData.RomBytes);
|
||||
stream.Read(ROM0, 0, 16384);
|
||||
stream.Read(ROM1, 0, 16384);
|
||||
stream.Read(ROM2, 0, 16384);
|
||||
stream.Read(ROM3, 0, 16384);
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128Plus2a : SpectrumBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadPort(ushort port)
|
||||
{
|
||||
bool deviceAddressed = true;
|
||||
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
// check AY
|
||||
if (AYDevice.ReadPort(port, ref result))
|
||||
return (byte)result;
|
||||
|
||||
// Kempston joystick input takes priority over all other input
|
||||
// if this is detected just return the kempston byte
|
||||
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
|
||||
{
|
||||
if (LocateUniqueJoystick(JoystickType.Kempston) != null)
|
||||
return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
|
||||
|
||||
InputRead = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (KeyboardDevice.ReadPort(port, ref result))
|
||||
{
|
||||
// not a lagframe
|
||||
InputRead = true;
|
||||
|
||||
// process tape INs
|
||||
TapeDevice.ReadPort(port, ref result);
|
||||
}
|
||||
else
|
||||
deviceAddressed = false;
|
||||
}
|
||||
|
||||
if (!deviceAddressed)
|
||||
{
|
||||
// If this is an unused port the floating memory bus should be returned
|
||||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ULADevice.floatingBusTable[_tStates] < 0)
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Check whether the low bit is reset
|
||||
// Technically the ULA should respond to every even I/O address
|
||||
bool lowBitReset = (port & 0x0001) == 0;
|
||||
|
||||
// Kempston joystick input takes priority over all other input
|
||||
// if this is detected just return the kempston byte
|
||||
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
|
||||
{
|
||||
if (LocateUniqueJoystick(JoystickType.Kempston) != null)
|
||||
return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
|
||||
|
||||
InputRead = true;
|
||||
}
|
||||
else if (lowBitReset)
|
||||
{
|
||||
// Even I/O address so get input from keyboard
|
||||
KeyboardDevice.ReadPort(port, ref result);
|
||||
|
||||
TapeDevice.MonitorRead();
|
||||
|
||||
// not a lagframe
|
||||
InputRead = true;
|
||||
|
||||
// tape loading monitor cycle
|
||||
//TapeDevice.MonitorRead();
|
||||
|
||||
// process tape INs
|
||||
TapeDevice.ReadPort(port, ref result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// devices other than the ULA will respond here
|
||||
// (e.g. the AY sound chip in a 128k spectrum
|
||||
|
||||
// AY register activate - on +3/2a both FFFD and BFFD active AY
|
||||
if ((port & 0xc002) == 0xc000)
|
||||
{
|
||||
result = (int)AYDevice.PortRead();
|
||||
}
|
||||
else if ((port & 0xc002) == 0x8000)
|
||||
{
|
||||
result = (int)AYDevice.PortRead();
|
||||
}
|
||||
|
||||
// Kempston Mouse
|
||||
|
||||
/*
|
||||
else if ((port & 0xF002) == 0x2000) //Is bit 12 set and bits 13,14,15 and 1 reset?
|
||||
{
|
||||
//result = udpDrive.DiskStatusRead();
|
||||
|
||||
// disk drive is not yet implemented - return a max status byte for the menu to load
|
||||
result = 255;
|
||||
}
|
||||
else if ((port & 0xF002) == 0x3000)
|
||||
{
|
||||
//result = udpDrive.DiskReadByte();
|
||||
result = 0;
|
||||
}
|
||||
|
||||
else if ((port & 0xF002) == 0x0)
|
||||
{
|
||||
if (PagingDisabled)
|
||||
result = 0x1;
|
||||
else
|
||||
result = 0xff;
|
||||
}
|
||||
*//*
|
||||
|
||||
// if unused port the floating memory bus should be returned (still todo)
|
||||
}
|
||||
*/
|
||||
|
||||
return (byte)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
// get a BitArray of the port
|
||||
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
|
||||
// get a BitArray of the value byte
|
||||
BitArray bits = new BitArray(new byte[] { value });
|
||||
|
||||
// Check whether the low bit is reset
|
||||
bool lowBitReset = !portBits[0]; // (port & 0x01) == 0;
|
||||
|
||||
AYDevice.WritePort(port, value);
|
||||
|
||||
// port 0x7ffd - hardware should only respond when bits 1 & 15 are reset and bit 14 is set
|
||||
if (port == 0x7ffd)
|
||||
{
|
||||
if (!PagingDisabled)
|
||||
{
|
||||
// bits 0, 1, 2 select the RAM page
|
||||
var rp = value & 0x07;
|
||||
if (rp < 8)
|
||||
RAMPaged = rp;
|
||||
|
||||
// bit 3 controls shadow screen
|
||||
SHADOWPaged = bits[3];
|
||||
|
||||
// Bit 5 set signifies that paging is disabled until next reboot
|
||||
PagingDisabled = bits[5];
|
||||
|
||||
// portbit 4 is the LOW BIT of the ROM selection
|
||||
ROMlow = bits[4];
|
||||
}
|
||||
}
|
||||
// port 0x1ffd - hardware should only respond when bits 1, 13, 14 & 15 are reset and bit 12 is set
|
||||
if (port == 0x1ffd)
|
||||
{
|
||||
if (!PagingDisabled)
|
||||
{
|
||||
if (!bits[0])
|
||||
{
|
||||
// special paging is not enabled - get the ROMpage high byte
|
||||
ROMhigh = bits[2];
|
||||
|
||||
// set the special paging mode flag
|
||||
SpecialPagingMode = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// special paging is enabled
|
||||
// this is decided based on combinations of bits 1 & 2
|
||||
// Config 0 = Bit1-0 Bit2-0
|
||||
// Config 1 = Bit1-1 Bit2-0
|
||||
// Config 2 = Bit1-0 Bit2-1
|
||||
// Config 3 = Bit1-1 Bit2-1
|
||||
BitArray confHalfNibble = new BitArray(2);
|
||||
confHalfNibble[0] = bits[1];
|
||||
confHalfNibble[1] = bits[2];
|
||||
|
||||
// set special paging configuration
|
||||
PagingConfiguration = ZXSpectrum.GetIntFromBitArray(confHalfNibble);
|
||||
|
||||
// set the special paging mode flag
|
||||
SpecialPagingMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
// bit 3 controls the disk motor (1=on, 0=off)
|
||||
DiskMotorState = bits[3];
|
||||
|
||||
// bit 4 is the printer port strobe
|
||||
PrinterPortStrobe = bits[4];
|
||||
}
|
||||
|
||||
// Only even addresses address the ULA
|
||||
if (lowBitReset)
|
||||
{
|
||||
// store the last OUT byte
|
||||
LastULAOutByte = value;
|
||||
|
||||
/*
|
||||
Bit 7 6 5 4 3 2 1 0
|
||||
+-------------------------------+
|
||||
| | | | E | M | Border |
|
||||
+-------------------------------+
|
||||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
|
||||
|
||||
// Tape
|
||||
TapeDevice.WritePort(port, value);
|
||||
|
||||
// Tape
|
||||
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
|
||||
}
|
||||
|
||||
|
||||
LastULAOutByte = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// +3 and 2a overidden method
|
||||
/// </summary>
|
||||
public override int _ROMpaged
|
||||
{
|
||||
get
|
||||
{
|
||||
// calculate the ROMpage from the high and low bits
|
||||
var rp = ZXSpectrum.GetIntFromBitArray(new BitArray(new bool[] { ROMlow, ROMhigh }));
|
||||
|
||||
if (rp != 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return rp;
|
||||
}
|
||||
set { ROMPaged = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override port contention
|
||||
/// +3/2a does not have the same ULA IO contention
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override void ContendPortAddress(ushort addr)
|
||||
{
|
||||
CPU.TotalExecutedCycles += 4;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
class ULAPlus2a : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
public ULAPlus2a(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 36;
|
||||
LongestOperationCycles = 64 + 2;
|
||||
FrameLength = 70908;
|
||||
ClockSpeed = 3546900;
|
||||
|
||||
contentionTable = new byte[70930];
|
||||
floatingBusTable = new short[70930];
|
||||
for (int f = 0; f < 70930; f++)
|
||||
floatingBusTable[f] = -1;
|
||||
|
||||
CharRows = 24;
|
||||
CharCols = 32;
|
||||
ScreenWidth = 256;
|
||||
ScreenHeight = 192;
|
||||
BorderTopHeight = 48;
|
||||
BorderBottomHeight = 56;
|
||||
BorderLeftWidth = 48;
|
||||
BorderRightWidth = 48;
|
||||
DisplayStart = 16384;
|
||||
DisplayLength = 6144;
|
||||
AttributeStart = 22528;
|
||||
AttributeLength = 768;
|
||||
borderColour = 7;
|
||||
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
|
||||
|
||||
TstatesPerScanline = 228;
|
||||
TstateAtTop = BorderTopHeight * TstatesPerScanline;
|
||||
TstateAtBottom = BorderBottomHeight * TstatesPerScanline;
|
||||
tstateToDisp = new short[FrameLength];
|
||||
|
||||
ScreenBuffer = new int[ScanLineWidth * BorderTopHeight //48 lines of border
|
||||
+ ScanLineWidth * ScreenHeight //border + main + border of 192 lines
|
||||
+ ScanLineWidth * BorderBottomHeight]; //56 lines of border
|
||||
|
||||
attr = new short[DisplayLength]; //6144 bytes of display memory will be mapped
|
||||
|
||||
SetupScreenSize();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Operations
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
contentionStartPeriod = 14361; // + LateTiming;
|
||||
contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
|
||||
screen = _machine.RAM5;
|
||||
screenByteCtr = DisplayStart;
|
||||
ULAByteCtr = 0;
|
||||
actualULAStart = 14365 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
|
||||
lastTState = actualULAStart;
|
||||
BuildAttributeMap();
|
||||
BuildContentionTable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contention Methods
|
||||
|
||||
public override bool IsContended(int addr)
|
||||
{
|
||||
addr = addr & 0xc000;
|
||||
|
||||
if (addr == 0x4000)
|
||||
{
|
||||
// low port contention
|
||||
return true;
|
||||
}
|
||||
|
||||
if (addr == 0xc000)
|
||||
{
|
||||
// high port contention - check for contended bank paged in
|
||||
switch (_machine.RAMPaged)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void BuildContentionTable()
|
||||
{
|
||||
int t = contentionStartPeriod;
|
||||
while (t < contentionEndPeriod)
|
||||
{
|
||||
contentionTable[t++] = 1;
|
||||
contentionTable[t++] = 0;
|
||||
|
||||
//for 128 t-states
|
||||
for (int i = 0; i < 128; i += 8)
|
||||
{
|
||||
contentionTable[t++] = 7;
|
||||
contentionTable[t++] = 6;
|
||||
contentionTable[t++] = 5;
|
||||
contentionTable[t++] = 4;
|
||||
contentionTable[t++] = 3;
|
||||
contentionTable[t++] = 2;
|
||||
contentionTable[t++] = 1;
|
||||
contentionTable[t++] = 0;
|
||||
}
|
||||
t += (TstatesPerScanline - 128) - 2;
|
||||
}
|
||||
|
||||
//build top half of tstateToDisp table
|
||||
//vertical retrace period
|
||||
for (t = 0; t < actualULAStart; t++)
|
||||
tstateToDisp[t] = 0;
|
||||
|
||||
//next 48 are actual border
|
||||
while (t < actualULAStart + (TstateAtTop))
|
||||
{
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
//build middle half
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
int scrval = 2;
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline))
|
||||
{
|
||||
for (int g = 0; g < 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 24; g < 24 + 128; g++)
|
||||
{
|
||||
//Map screenaddr to tstate
|
||||
if (g % 4 == 0)
|
||||
{
|
||||
scrval = (((((_y & 0xc0) >> 3) | (_y & 0x07) | (0x40)) << 8)) | (((_x >> 3) & 0x1f) | ((_y & 0x38) << 2));
|
||||
_x += 8;
|
||||
}
|
||||
tstateToDisp[t++] = (short)scrval;
|
||||
}
|
||||
|
||||
_y++;
|
||||
|
||||
for (int g = 24 + 128; g < 24 + 128 + 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 24 + 128 + 24; g < 24 + 128 + 24 + 52; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
int h = contentionStartPeriod + 3;
|
||||
while (h < contentionEndPeriod + 3)
|
||||
{
|
||||
for (int j = 0; j < 128; j += 8)
|
||||
{
|
||||
floatingBusTable[h] = tstateToDisp[h + 2];
|
||||
floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)];
|
||||
floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4];
|
||||
floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)];
|
||||
h += 8;
|
||||
}
|
||||
h += TstatesPerScanline - 128;
|
||||
}
|
||||
|
||||
//build bottom half
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
|
||||
{
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128Plus2a : SpectrumBase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX128Plus2a(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> joysticks)
|
||||
{
|
||||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
ROMPaged = 0;
|
||||
SHADOWPaged = false;
|
||||
RAMPaged = 0;
|
||||
PagingDisabled = false;
|
||||
|
||||
ULADevice = new ULAPlus2a(this);
|
||||
|
||||
BuzzerDevice = new Buzzer(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
AYDevice = new AYChip(this);
|
||||
AYDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
KeyboardDevice = new StandardKeyboard(this);
|
||||
|
||||
InitJoysticks(joysticks);
|
||||
|
||||
TapeDevice = new DatacorderDevice();
|
||||
TapeDevice.Init(this);
|
||||
|
||||
InitializeMedia(files);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,429 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128Plus3 : SpectrumBase
|
||||
{
|
||||
/* http://www.worldofspectrum.org/faq/reference/128kreference.htm
|
||||
*
|
||||
* Port 0x7ffd behaves in the almost exactly the same way as on the 128K/+2, with two exceptions:
|
||||
|
||||
Bit 4 is now the low bit of the ROM selection.
|
||||
The partial decoding used is now slightly different: the hardware will respond only to those port addresses with bit 1 reset, bit 14 set and bit 15 reset (as opposed to just bits 1 and 15 reset on the 128K/+2).
|
||||
The extra paging features of the +2A/+3 are controlled by port 0x1ffd (again, partial decoding applies here: the hardware will respond to all port addresses with bit 1 reset, bit 12 set and bits 13, 14 and 15 reset). This port is also write-only, and its last value should be saved at 0x5b67 (23399).
|
||||
|
||||
Port 0x1ffd responds as follows:
|
||||
|
||||
Bit 0: Paging mode. 0=normal, 1=special
|
||||
Bit 1: In normal mode, ignored.
|
||||
Bit 2: In normal mode, high bit of ROM selection. The four ROMs are:
|
||||
ROM 0: 128k editor, menu system and self-test program
|
||||
ROM 1: 128k syntax checker
|
||||
ROM 2: +3DOS
|
||||
ROM 3: 48 BASIC
|
||||
Bit 3: Disk motor; 1=on, 0=off
|
||||
Bit 4: Printer port strobe.
|
||||
When special mode is selected, the memory map changes to one of four configurations specified in bits 1 and 2 of port 0x1ffd:
|
||||
Bit 2 =0 Bit 2 =0 Bit 2 =1 Bit 2 =1
|
||||
Bit 1 =0 Bit 1 =1 Bit 1 =0 Bit 1 =1
|
||||
0xffff +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 3 | | Bank 7 | | Bank 3 | | Bank 3 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | screen | | | | |
|
||||
0xc000 +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 2 | | Bank 6 | | Bank 6 | | Bank 6 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
0x8000 +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 1 | | Bank 5 | | Bank 5 | | Bank 7 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | screen | | screen | | screen |
|
||||
0x4000 +--------+ +--------+ +--------+ +--------+
|
||||
| Bank 0 | | Bank 4 | | Bank 4 | | Bank 4 |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
0x0000 +--------+ +--------+ +--------+ +--------+
|
||||
RAM banks 1,3,4 and 6 are used for the disc cache and RAMdisc, while Bank 7 contains editor scratchpads and +3DOS workspace.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading from the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
byte result = 0xff;
|
||||
|
||||
// special paging
|
||||
if (SpecialPagingMode)
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
result = RAM4[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
result = RAM1[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
result = RAM6[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3:
|
||||
result = RAM3[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
// ROM 0x000
|
||||
case 0:
|
||||
switch (_ROMpaged)
|
||||
{
|
||||
case 0:
|
||||
result = ROM0[addr % 0x4000];
|
||||
TestForTapeTraps(addr % 0x4000);
|
||||
break;
|
||||
case 1:
|
||||
result = ROM1[addr % 0x4000];
|
||||
TestForTapeTraps(addr % 0x4000);
|
||||
break;
|
||||
case 2:
|
||||
result = ROM2[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = ROM3[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// RAM 0x4000 (RAM5 - Bank5 always)
|
||||
case 1:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0x8000 (RAM2 - Bank2)
|
||||
case 2:
|
||||
result = RAM2[addr % 0x4000];
|
||||
break;
|
||||
|
||||
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
|
||||
case 3:
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 0:
|
||||
result = RAM0[addr % 0x4000];
|
||||
break;
|
||||
case 1:
|
||||
result = RAM1[addr % 0x4000];
|
||||
break;
|
||||
case 2:
|
||||
result = RAM2[addr % 0x4000];
|
||||
break;
|
||||
case 3:
|
||||
result = RAM3[addr % 0x4000];
|
||||
break;
|
||||
case 4:
|
||||
result = RAM4[addr % 0x4000];
|
||||
break;
|
||||
case 5:
|
||||
result = RAM5[addr % 0x4000];
|
||||
break;
|
||||
case 6:
|
||||
result = RAM6[addr % 0x4000];
|
||||
break;
|
||||
case 7:
|
||||
result = RAM7[addr % 0x4000];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates writing to the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
|
||||
// special paging
|
||||
if (SpecialPagingMode)
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
RAM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
RAM4[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
RAM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
RAM6[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3:
|
||||
RAM3[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (divisor)
|
||||
{
|
||||
// ROM 0x000
|
||||
case 0:
|
||||
/*
|
||||
switch (_ROMpaged)
|
||||
{
|
||||
// cannot write to ROMs
|
||||
case 0:
|
||||
ROM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
ROM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 2:
|
||||
ROM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
ROM3[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
|
||||
// RAM 0x4000 (RAM5 - Bank5 only)
|
||||
case 1:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
|
||||
// RAM 0x8000 (RAM2 - Bank2)
|
||||
case 2:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
|
||||
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
|
||||
case 3:
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 0:
|
||||
RAM0[addr % 0x4000] = value;
|
||||
break;
|
||||
case 1:
|
||||
RAM1[addr % 0x4000] = value;
|
||||
break;
|
||||
case 2:
|
||||
RAM2[addr % 0x4000] = value;
|
||||
break;
|
||||
case 3:
|
||||
RAM3[addr % 0x4000] = value;
|
||||
break;
|
||||
case 4:
|
||||
RAM4[addr % 0x4000] = value;
|
||||
break;
|
||||
case 5:
|
||||
RAM5[addr % 0x4000] = value;
|
||||
break;
|
||||
case 6:
|
||||
RAM6[addr % 0x4000] = value;
|
||||
break;
|
||||
case 7:
|
||||
RAM7[addr % 0x4000] = value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
/// Will read RAM5 (screen0) by default, unless RAM7 (screen1) is selected as output
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte FetchScreenMemory(ushort addr)
|
||||
{
|
||||
byte value = new byte();
|
||||
|
||||
if (SHADOWPaged && !PagingDisabled)
|
||||
{
|
||||
// shadow screen should be outputted
|
||||
// this lives in RAM7
|
||||
value = RAM7[addr & 0x3FFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
// shadow screen is not set to display or paging is disabled (probably in 48k mode)
|
||||
// (use screen0 at RAM5)
|
||||
value = RAM5[addr & 0x3FFF];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="startAddress"></param>
|
||||
public override void InitROM(RomData romData)
|
||||
{
|
||||
RomData = romData;
|
||||
// +3 uses ROM0, ROM1, ROM2 & ROM3
|
||||
/* ROM 0: 128k editor, menu system and self-test program
|
||||
ROM 1: 128k syntax checker
|
||||
ROM 2: +3DOS
|
||||
ROM 3: 48 BASIC
|
||||
*/
|
||||
Stream stream = new MemoryStream(RomData.RomBytes);
|
||||
stream.Read(ROM0, 0, 16384);
|
||||
stream.Read(ROM1, 0, 16384);
|
||||
stream.Read(ROM2, 0, 16384);
|
||||
stream.Read(ROM3, 0, 16384);
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128Plus3 : SpectrumBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadPort(ushort port)
|
||||
{
|
||||
bool deviceAddressed = true;
|
||||
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
// check AY
|
||||
if (AYDevice.ReadPort(port, ref result))
|
||||
return (byte)result;
|
||||
|
||||
// Kempston joystick input takes priority over all other input
|
||||
// if this is detected just return the kempston byte
|
||||
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
|
||||
{
|
||||
if (LocateUniqueJoystick(JoystickType.Kempston) != null)
|
||||
return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
|
||||
|
||||
InputRead = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (KeyboardDevice.ReadPort(port, ref result))
|
||||
{
|
||||
// not a lagframe
|
||||
InputRead = true;
|
||||
|
||||
// process tape INs
|
||||
TapeDevice.ReadPort(port, ref result);
|
||||
}
|
||||
else
|
||||
deviceAddressed = false;
|
||||
}
|
||||
|
||||
if (!deviceAddressed)
|
||||
{
|
||||
// If this is an unused port the floating memory bus should be returned
|
||||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ULADevice.floatingBusTable[_tStates] < 0)
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
// get a BitArray of the port
|
||||
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
|
||||
// get a BitArray of the value byte
|
||||
BitArray bits = new BitArray(new byte[] { value });
|
||||
|
||||
// Check whether the low bit is reset
|
||||
bool lowBitReset = !portBits[0]; // (port & 0x01) == 0;
|
||||
|
||||
AYDevice.WritePort(port, value);
|
||||
|
||||
// port 0x7ffd - hardware should only respond when bits 1 & 15 are reset and bit 14 is set
|
||||
if (port == 0x7ffd)
|
||||
{
|
||||
if (!PagingDisabled)
|
||||
{
|
||||
// bits 0, 1, 2 select the RAM page
|
||||
var rp = value & 0x07;
|
||||
if (rp < 8)
|
||||
RAMPaged = rp;
|
||||
|
||||
// bit 3 controls shadow screen
|
||||
SHADOWPaged = bits[3];
|
||||
|
||||
// Bit 5 set signifies that paging is disabled until next reboot
|
||||
PagingDisabled = bits[5];
|
||||
|
||||
// portbit 4 is the LOW BIT of the ROM selection
|
||||
ROMlow = bits[4];
|
||||
}
|
||||
}
|
||||
// port 0x1ffd - hardware should only respond when bits 1, 13, 14 & 15 are reset and bit 12 is set
|
||||
if (port == 0x1ffd)
|
||||
{
|
||||
if (!PagingDisabled)
|
||||
{
|
||||
if (!bits[0])
|
||||
{
|
||||
// special paging is not enabled - get the ROMpage high byte
|
||||
ROMhigh = bits[2];
|
||||
|
||||
// set the special paging mode flag
|
||||
SpecialPagingMode = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// special paging is enabled
|
||||
// this is decided based on combinations of bits 1 & 2
|
||||
// Config 0 = Bit1-0 Bit2-0
|
||||
// Config 1 = Bit1-1 Bit2-0
|
||||
// Config 2 = Bit1-0 Bit2-1
|
||||
// Config 3 = Bit1-1 Bit2-1
|
||||
BitArray confHalfNibble = new BitArray(2);
|
||||
confHalfNibble[0] = bits[1];
|
||||
confHalfNibble[1] = bits[2];
|
||||
|
||||
// set special paging configuration
|
||||
PagingConfiguration = ZXSpectrum.GetIntFromBitArray(confHalfNibble);
|
||||
|
||||
// set the special paging mode flag
|
||||
SpecialPagingMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
// bit 3 controls the disk motor (1=on, 0=off)
|
||||
DiskMotorState = bits[3];
|
||||
|
||||
// bit 4 is the printer port strobe
|
||||
PrinterPortStrobe = bits[4];
|
||||
}
|
||||
|
||||
// Only even addresses address the ULA
|
||||
if (lowBitReset)
|
||||
{
|
||||
// store the last OUT byte
|
||||
LastULAOutByte = value;
|
||||
|
||||
/*
|
||||
Bit 7 6 5 4 3 2 1 0
|
||||
+-------------------------------+
|
||||
| | | | E | M | Border |
|
||||
+-------------------------------+
|
||||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
|
||||
|
||||
// Tape
|
||||
TapeDevice.WritePort(port, value);
|
||||
|
||||
// Tape
|
||||
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
|
||||
}
|
||||
|
||||
|
||||
LastULAOutByte = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// +3 and 2a overidden method
|
||||
/// </summary>
|
||||
public override int _ROMpaged
|
||||
{
|
||||
get
|
||||
{
|
||||
// calculate the ROMpage from the high and low bits
|
||||
var rp = ZXSpectrum.GetIntFromBitArray(new BitArray(new bool[] { ROMlow, ROMhigh }));
|
||||
|
||||
if (rp != 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return rp;
|
||||
}
|
||||
set { ROMPaged = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override port contention
|
||||
/// +3/2a does not have the same ULA IO contention
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override void ContendPortAddress(ushort addr)
|
||||
{
|
||||
CPU.TotalExecutedCycles += 4;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
class ULAPlus3 : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
public ULAPlus3(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 36;
|
||||
LongestOperationCycles = 64 + 2;
|
||||
FrameLength = 70908;
|
||||
ClockSpeed = 3546900;
|
||||
|
||||
contentionTable = new byte[70930];
|
||||
floatingBusTable = new short[70930];
|
||||
for (int f = 0; f < 70930; f++)
|
||||
floatingBusTable[f] = -1;
|
||||
|
||||
CharRows = 24;
|
||||
CharCols = 32;
|
||||
ScreenWidth = 256;
|
||||
ScreenHeight = 192;
|
||||
BorderTopHeight = 48;
|
||||
BorderBottomHeight = 56;
|
||||
BorderLeftWidth = 48;
|
||||
BorderRightWidth = 48;
|
||||
DisplayStart = 16384;
|
||||
DisplayLength = 6144;
|
||||
AttributeStart = 22528;
|
||||
AttributeLength = 768;
|
||||
borderColour = 7;
|
||||
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
|
||||
|
||||
TstatesPerScanline = 228;
|
||||
TstateAtTop = BorderTopHeight * TstatesPerScanline;
|
||||
TstateAtBottom = BorderBottomHeight * TstatesPerScanline;
|
||||
tstateToDisp = new short[FrameLength];
|
||||
|
||||
ScreenBuffer = new int[ScanLineWidth * BorderTopHeight //48 lines of border
|
||||
+ ScanLineWidth * ScreenHeight //border + main + border of 192 lines
|
||||
+ ScanLineWidth * BorderBottomHeight]; //56 lines of border
|
||||
|
||||
attr = new short[DisplayLength]; //6144 bytes of display memory will be mapped
|
||||
|
||||
SetupScreenSize();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Operations
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
contentionStartPeriod = 14361; // + LateTiming;
|
||||
contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
|
||||
screen = _machine.RAM5;
|
||||
screenByteCtr = DisplayStart;
|
||||
ULAByteCtr = 0;
|
||||
actualULAStart = 14365 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
|
||||
lastTState = actualULAStart;
|
||||
BuildAttributeMap();
|
||||
BuildContentionTable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contention Methods
|
||||
|
||||
public override bool IsContended(int addr)
|
||||
{
|
||||
addr = addr & 0xc000;
|
||||
|
||||
if (addr == 0x4000)
|
||||
{
|
||||
// low port contention
|
||||
return true;
|
||||
}
|
||||
|
||||
if (addr == 0xc000)
|
||||
{
|
||||
// high port contention - check for contended bank paged in
|
||||
switch (_machine.RAMPaged)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void BuildContentionTable()
|
||||
{
|
||||
int t = contentionStartPeriod;
|
||||
while (t < contentionEndPeriod)
|
||||
{
|
||||
contentionTable[t++] = 1;
|
||||
contentionTable[t++] = 0;
|
||||
|
||||
//for 128 t-states
|
||||
for (int i = 0; i < 128; i += 8)
|
||||
{
|
||||
contentionTable[t++] = 7;
|
||||
contentionTable[t++] = 6;
|
||||
contentionTable[t++] = 5;
|
||||
contentionTable[t++] = 4;
|
||||
contentionTable[t++] = 3;
|
||||
contentionTable[t++] = 2;
|
||||
contentionTable[t++] = 1;
|
||||
contentionTable[t++] = 0;
|
||||
}
|
||||
t += (TstatesPerScanline - 128) - 2;
|
||||
}
|
||||
|
||||
//build top half of tstateToDisp table
|
||||
//vertical retrace period
|
||||
for (t = 0; t < actualULAStart; t++)
|
||||
tstateToDisp[t] = 0;
|
||||
|
||||
//next 48 are actual border
|
||||
while (t < actualULAStart + (TstateAtTop))
|
||||
{
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
//build middle half
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
int scrval = 2;
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline))
|
||||
{
|
||||
for (int g = 0; g < 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 24; g < 24 + 128; g++)
|
||||
{
|
||||
//Map screenaddr to tstate
|
||||
if (g % 4 == 0)
|
||||
{
|
||||
scrval = (((((_y & 0xc0) >> 3) | (_y & 0x07) | (0x40)) << 8)) | (((_x >> 3) & 0x1f) | ((_y & 0x38) << 2));
|
||||
_x += 8;
|
||||
}
|
||||
tstateToDisp[t++] = (short)scrval;
|
||||
}
|
||||
|
||||
_y++;
|
||||
|
||||
for (int g = 24 + 128; g < 24 + 128 + 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 24 + 128 + 24; g < 24 + 128 + 24 + 52; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
int h = contentionStartPeriod + 3;
|
||||
while (h < contentionEndPeriod + 3)
|
||||
{
|
||||
for (int j = 0; j < 128; j += 8)
|
||||
{
|
||||
floatingBusTable[h] = tstateToDisp[h + 2];
|
||||
floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)];
|
||||
floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4];
|
||||
floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)];
|
||||
h += 8;
|
||||
}
|
||||
h += TstatesPerScanline - 128;
|
||||
}
|
||||
|
||||
//build bottom half
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
|
||||
{
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX128Plus3 : SpectrumBase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX128Plus3(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> joysticks)
|
||||
{
|
||||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
ROMPaged = 0;
|
||||
SHADOWPaged = false;
|
||||
RAMPaged = 0;
|
||||
PagingDisabled = false;
|
||||
|
||||
ULADevice = new ULAPlus3(this);
|
||||
|
||||
BuzzerDevice = new Buzzer(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
AYDevice = new AYChip(this);
|
||||
AYDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
KeyboardDevice = new StandardKeyboard(this);
|
||||
|
||||
InitJoysticks(joysticks);
|
||||
|
||||
TapeDevice = new DatacorderDevice();
|
||||
TapeDevice.Init(this);
|
||||
|
||||
InitializeMedia(files);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public class ZX16 : ZX48
|
||||
{
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX16(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> joysticks)
|
||||
: base(spectrum, cpu, borderType, files, joysticks)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Memory
|
||||
|
||||
/* 48K Spectrum has NO memory paging
|
||||
*
|
||||
*
|
||||
| Bank 0 |
|
||||
| |
|
||||
| |
|
||||
| screen |
|
||||
0x4000 +--------+
|
||||
| ROM 0 |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
0x0000 +--------+
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading from the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
var index = addr % 0x4000;
|
||||
|
||||
// paging logic goes here
|
||||
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
TestForTapeTraps(addr % 0x4000);
|
||||
return ROM0[index];
|
||||
case 1: return RAM0[index];
|
||||
default:
|
||||
// memory does not exist
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates writing to the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
var index = addr % 0x4000;
|
||||
|
||||
// paging logic goes here
|
||||
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
// cannot write to ROM
|
||||
break;
|
||||
case 1:
|
||||
RAM0[index] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="startAddress"></param>
|
||||
public override void InitROM(RomData romData)
|
||||
{
|
||||
RomData = romData;
|
||||
// for 16/48k machines only ROM0 is used (no paging)
|
||||
RomData.RomBytes?.CopyTo(ROM0, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX48 : SpectrumBase
|
||||
{
|
||||
/* 48K Spectrum has NO memory paging
|
||||
*
|
||||
* 0xffff +--------+
|
||||
| Bank 2 |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
0xc000 +--------+
|
||||
| Bank 1 |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
0x8000 +--------+
|
||||
| Bank 0 |
|
||||
| |
|
||||
| |
|
||||
| screen |
|
||||
0x4000 +--------+
|
||||
| ROM 0 |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
0x0000 +--------+
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading from the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
var index = addr % 0x4000;
|
||||
|
||||
// paging logic goes here
|
||||
|
||||
switch (divisor)
|
||||
{
|
||||
case 0: return ROM0[index];
|
||||
case 1: return RAM0[index];
|
||||
case 2: return RAM1[index];
|
||||
case 3: return RAM2[index];
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates writing to the bus (no contention)
|
||||
/// Paging should be handled here
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
int divisor = addr / 0x4000;
|
||||
var index = addr % 0x4000;
|
||||
|
||||
// paging logic goes here
|
||||
|
||||
switch (divisor)
|
||||
{
|
||||
case 0:
|
||||
// cannot write to ROM
|
||||
break;
|
||||
case 1:
|
||||
RAM0[index] = value;
|
||||
break;
|
||||
case 2:
|
||||
RAM1[index] = value;
|
||||
break;
|
||||
case 3:
|
||||
RAM2[index] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified memory address
|
||||
/// (with memory contention if appropriate)
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="startAddress"></param>
|
||||
public override void InitROM(RomData romData)
|
||||
{
|
||||
RomData = romData;
|
||||
// for 16/48k machines only ROM0 is used (no paging)
|
||||
RomData.RomBytes?.CopyTo(ROM0, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX48 : SpectrumBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public override byte ReadPort(ushort port)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
// Check whether the low bit is reset
|
||||
// Technically the ULA should respond to every even I/O address
|
||||
bool lowBitReset = (port & 0x0001) == 0;
|
||||
|
||||
// Kempston joystick input takes priority over all other input
|
||||
// if this is detected just return the kempston byte
|
||||
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
|
||||
{
|
||||
if (LocateUniqueJoystick(JoystickType.Kempston) != null)
|
||||
return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
|
||||
|
||||
// not a lag frame
|
||||
InputRead = true;
|
||||
}
|
||||
else if (lowBitReset)
|
||||
{
|
||||
// Even I/O address so get input from keyboard
|
||||
KeyboardDevice.ReadPort(port, ref result);
|
||||
|
||||
// not a lagframe
|
||||
InputRead = true;
|
||||
|
||||
// process tape INs
|
||||
TapeDevice.ReadPort(port, ref result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// devices other than the ULA will respond here
|
||||
// (e.g. the AY sound chip in a 128k spectrum
|
||||
|
||||
// AY register activate - no AY chip in a 48k spectrum
|
||||
|
||||
// Kemptson Mouse (not implemented yet)
|
||||
|
||||
|
||||
// If this is an unused port the floating memory bus should be returned
|
||||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ULADevice.floatingBusTable[_tStates] < 0)
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data to a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <param name="value"></param>
|
||||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
|
||||
// Check whether the low bit is reset
|
||||
// Technically the ULA should respond to every even I/O address
|
||||
if ((port & 0x0001) != 0)
|
||||
return;
|
||||
|
||||
// store the last OUT byte
|
||||
LastULAOutByte = value;
|
||||
|
||||
/*
|
||||
Bit 7 6 5 4 3 2 1 0
|
||||
+-------------------------------+
|
||||
| | | | E | M | Border |
|
||||
+-------------------------------+
|
||||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
{
|
||||
// border value has changed - update the screen buffer
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
|
||||
|
||||
// Tape
|
||||
TapeDevice.WritePort(port, value);
|
||||
|
||||
// Tape mic processing (not implemented yet)
|
||||
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
class ULA48 : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
public ULA48(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 32;
|
||||
LongestOperationCycles = 64;
|
||||
FrameLength = 69888;
|
||||
ClockSpeed = 3500000;
|
||||
|
||||
contentionTable = new byte[70930];
|
||||
floatingBusTable = new short[70930];
|
||||
for (int f = 0; f < 70930; f++)
|
||||
floatingBusTable[f] = -1;
|
||||
|
||||
CharRows = 24;
|
||||
CharCols = 32;
|
||||
ScreenWidth = 256;
|
||||
ScreenHeight = 192;
|
||||
BorderTopHeight = 48;
|
||||
BorderBottomHeight = 56;
|
||||
BorderLeftWidth = 48;
|
||||
BorderRightWidth = 48;
|
||||
DisplayStart = 16384;
|
||||
DisplayLength = 6144;
|
||||
AttributeStart = 22528;
|
||||
AttributeLength = 768;
|
||||
borderColour = 7;
|
||||
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
|
||||
|
||||
TstatesPerScanline = 224;
|
||||
TstateAtTop = BorderTopHeight * TstatesPerScanline;
|
||||
TstateAtBottom = BorderBottomHeight * TstatesPerScanline;
|
||||
tstateToDisp = new short[FrameLength];
|
||||
|
||||
ScreenBuffer = new int[ScanLineWidth * BorderTopHeight //48 lines of border
|
||||
+ ScanLineWidth * ScreenHeight //border + main + border of 192 lines
|
||||
+ ScanLineWidth * BorderBottomHeight]; //56 lines of border
|
||||
|
||||
attr = new short[DisplayLength]; //6144 bytes of display memory will be mapped
|
||||
|
||||
SetupScreenSize();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Operations
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
contentionStartPeriod = 14335; // + LateTiming;
|
||||
contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
|
||||
screen = _machine.RAM0;
|
||||
screenByteCtr = DisplayStart;
|
||||
ULAByteCtr = 0;
|
||||
actualULAStart = 14340 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
|
||||
lastTState = actualULAStart;
|
||||
BuildAttributeMap();
|
||||
BuildContentionTable();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Contention Methods
|
||||
|
||||
public override bool IsContended(int addr)
|
||||
{
|
||||
if ((addr & 49152) == 16384)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void BuildContentionTable()
|
||||
{
|
||||
int t = contentionStartPeriod;
|
||||
while (t < contentionEndPeriod)
|
||||
{
|
||||
//for 128 t-states
|
||||
for (int i = 0; i < 128; i += 8)
|
||||
{
|
||||
contentionTable[t++] = 6;
|
||||
contentionTable[t++] = 5;
|
||||
contentionTable[t++] = 4;
|
||||
contentionTable[t++] = 3;
|
||||
contentionTable[t++] = 2;
|
||||
contentionTable[t++] = 1;
|
||||
contentionTable[t++] = 0;
|
||||
contentionTable[t++] = 0;
|
||||
}
|
||||
t += (TstatesPerScanline - 128); //24 tstates of right border + left border + 48 tstates of retrace
|
||||
}
|
||||
|
||||
//build top half of tstateToDisp table
|
||||
//vertical retrace period
|
||||
for (t = 0; t < actualULAStart; t++)
|
||||
tstateToDisp[t] = 0;
|
||||
|
||||
//next 48 are actual border
|
||||
while (t < actualULAStart + (TstateAtTop))
|
||||
{
|
||||
//border(24t) + screen (128t) + border(24t) = 176 tstates
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
//horizontal retrace
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
//build middle half of display
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
int scrval = 2;
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline))
|
||||
{
|
||||
//left border
|
||||
for (int g = 0; g < 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
//screen
|
||||
for (int g = 24; g < 24 + 128; g++)
|
||||
{
|
||||
//Map screenaddr to tstate
|
||||
if (g % 4 == 0)
|
||||
{
|
||||
scrval = (((((_y & 0xc0) >> 3) | (_y & 0x07) | (0x40)) << 8)) | (((_x >> 3) & 0x1f) | ((_y & 0x38) << 2));
|
||||
_x += 8;
|
||||
}
|
||||
tstateToDisp[t++] = (short)scrval;
|
||||
}
|
||||
_y++;
|
||||
|
||||
//right border
|
||||
for (int g = 24 + 128; g < 24 + 128 + 24; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
//horizontal retrace
|
||||
for (int g = 24 + 128 + 24; g < 24 + 128 + 24 + 48; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
|
||||
int h = contentionStartPeriod + 3;
|
||||
while (h < contentionEndPeriod + 3)
|
||||
{
|
||||
for (int j = 0; j < 128; j += 8)
|
||||
{
|
||||
floatingBusTable[h] = tstateToDisp[h + 2]; //screen address
|
||||
floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)]; //attr address
|
||||
floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4]; //screen address + 1
|
||||
floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)]; //attr address + 1
|
||||
h += 8;
|
||||
}
|
||||
h += TstatesPerScanline - 128;
|
||||
}
|
||||
|
||||
//build bottom border
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
|
||||
{
|
||||
//border(24t) + screen (128t) + border(24t) = 176 tstates
|
||||
for (int g = 0; g < 176; g++)
|
||||
tstateToDisp[t++] = 1;
|
||||
|
||||
//horizontal retrace
|
||||
for (int g = 176; g < TstatesPerScanline; g++)
|
||||
tstateToDisp[t++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZX48 : SpectrumBase
|
||||
{
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX48(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> joysticks)
|
||||
{
|
||||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
ULADevice = new ULA48(this);
|
||||
|
||||
BuzzerDevice = new Buzzer(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
||||
KeyboardDevice = new StandardKeyboard(this);
|
||||
|
||||
InitJoysticks(joysticks);
|
||||
|
||||
TapeDevice = new DatacorderDevice();
|
||||
TapeDevice.Init(this);
|
||||
|
||||
InitializeMedia(files);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the different types of media serializer avaiable
|
||||
/// </summary>
|
||||
public enum MediaSerializationType
|
||||
{
|
||||
NONE,
|
||||
TZX,
|
||||
TAP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Abtract class that represents all Media Serializers
|
||||
/// </summary>
|
||||
public abstract class MediaSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of serializer
|
||||
/// </summary>
|
||||
public abstract MediaSerializationType FormatType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether this class can be used to serialize
|
||||
/// </summary>
|
||||
public virtual bool IsSerializer
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether this class can be used to de-serialize
|
||||
/// </summary>
|
||||
public virtual bool IsDeSerializer
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialization method
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public virtual void Serialize(byte[] data)
|
||||
{
|
||||
throw new NotImplementedException(this.GetType().ToString() +
|
||||
"Serialize operation is not implemented for this serializer");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DeSerialization method
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public virtual void DeSerialize(byte[] data)
|
||||
{
|
||||
throw new NotImplementedException(this.GetType().ToString() +
|
||||
"DeSerialize operation is not implemented for this serializer");
|
||||
}
|
||||
|
||||
#region Static Tools
|
||||
|
||||
/// <summary>
|
||||
/// Converts an int32 value into a byte array
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected static byte[] GetBytes(int value)
|
||||
{
|
||||
byte[] buf = new byte[4];
|
||||
buf[0] = (byte)value;
|
||||
buf[1] = (byte)(value >> 8);
|
||||
buf[2] = (byte)(value >> 16);
|
||||
buf[3] = (byte)(value >> 24);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an int32 from a byte array based on offset
|
||||
/// </summary>
|
||||
/// <param name="buf"></param>
|
||||
/// <param name="offsetIndex"></param>
|
||||
/// <returns></returns>
|
||||
protected static int GetInt32(byte[] buf, int offsetIndex)
|
||||
{
|
||||
return buf[offsetIndex] | buf[offsetIndex + 1] << 8 | buf[offsetIndex + 2] << 16 | buf[offsetIndex + 3] << 24;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an uint16 from a byte array based on offset
|
||||
/// </summary>
|
||||
/// <param name="buf"></param>
|
||||
/// <param name="offsetIndex"></param>
|
||||
/// <returns></returns>
|
||||
protected static ushort GetWordValue(byte[] buf, int offsetIndex)
|
||||
{
|
||||
return (ushort)(buf[offsetIndex] | buf[offsetIndex + 1] << 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a byte array with a uint16 value based on offset
|
||||
/// </summary>
|
||||
/// <param name="buf"></param>
|
||||
/// <param name="offsetIndex"></param>
|
||||
/// <param name="value"></param>
|
||||
protected static void SetWordValue(byte[] buf, int offsetIndex, ushort value)
|
||||
{
|
||||
buf[offsetIndex] = (byte)value;
|
||||
buf[offsetIndex + 1] = (byte)(value >> 8);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Reponsible for TAP format serializaton
|
||||
/// </summary>
|
||||
public class TapSerializer : MediaSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of serializer
|
||||
/// </summary>
|
||||
private MediaSerializationType _formatType = MediaSerializationType.TAP;
|
||||
public override MediaSerializationType FormatType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _formatType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether this class can be used to serialize
|
||||
/// </summary>
|
||||
public override bool IsSerializer { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Signs whether this class can be used to de-serialize
|
||||
/// </summary>
|
||||
public override bool IsDeSerializer { get { return true; } }
|
||||
|
||||
#region Construction
|
||||
|
||||
private DatacorderDevice _datacorder;
|
||||
|
||||
public TapSerializer(DatacorderDevice _tapeDevice)
|
||||
{
|
||||
_datacorder = _tapeDevice;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region TAP Format Constants
|
||||
|
||||
/// <summary>
|
||||
/// Pilot pulse length
|
||||
/// </summary>
|
||||
public const int PILOT_PL = 2168;
|
||||
|
||||
/// <summary>
|
||||
/// Pilot pulses in the ROM header block
|
||||
/// </summary>
|
||||
public const int HEADER_PILOT_COUNT = 8063;
|
||||
|
||||
/// <summary>
|
||||
/// Pilot pulses in the ROM data block
|
||||
/// </summary>
|
||||
public const int DATA_PILOT_COUNT = 3223;
|
||||
|
||||
/// <summary>
|
||||
/// Sync 1 pulse length
|
||||
/// </summary>
|
||||
public const int SYNC_1_PL = 667;
|
||||
|
||||
/// <summary>
|
||||
/// Sync 2 pulse lenth
|
||||
/// </summary>
|
||||
public const int SYNC_2_PL = 735;
|
||||
|
||||
/// <summary>
|
||||
/// Bit 0 pulse length
|
||||
/// </summary>
|
||||
public const int BIT_0_PL = 855;
|
||||
|
||||
/// <summary>
|
||||
/// Bit 1 pulse length
|
||||
/// </summary>
|
||||
public const int BIT_1_PL = 1710;
|
||||
|
||||
/// <summary>
|
||||
/// End sync pulse length
|
||||
/// </summary>
|
||||
public const int TERM_SYNC = 947;
|
||||
|
||||
/// <summary>
|
||||
/// 1 millisecond pause
|
||||
/// </summary>
|
||||
public const int PAUSE_MS = 3500;
|
||||
|
||||
/// <summary>
|
||||
/// Used bit count in last byte
|
||||
/// </summary>
|
||||
public const int BIT_COUNT_IN_LAST = 8;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// DeSerialization method
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public override void DeSerialize(byte[] data)
|
||||
{
|
||||
/*
|
||||
The .TAP files contain blocks of tape-saved data. All blocks start with two bytes specifying how many bytes will follow (not counting the two length bytes). Then raw tape data follows, including the flag and checksum bytes. The checksum is the bitwise XOR of all bytes including the flag byte. For example, when you execute the line SAVE "ROM" CODE 0,2 this will result:
|
||||
|
||||
|------ Spectrum-generated data -------| |---------|
|
||||
|
||||
13 00 00 03 52 4f 4d 7x20 02 00 00 00 00 80 f1 04 00 ff f3 af a3
|
||||
|
||||
^^^^^...... first block is 19 bytes (17 bytes+flag+checksum)
|
||||
^^... flag byte (A reg, 00 for headers, ff for data blocks)
|
||||
^^ first byte of header, indicating a code block
|
||||
|
||||
file name ..^^^^^^^^^^^^^
|
||||
header info ..............^^^^^^^^^^^^^^^^^
|
||||
checksum of header .........................^^
|
||||
length of second block ........................^^^^^
|
||||
flag byte ............................................^^
|
||||
first two bytes of rom .................................^^^^^
|
||||
checksum (checkbittoggle would be a better name!).............^^
|
||||
*/
|
||||
|
||||
// clear existing tape blocks
|
||||
_datacorder.DataBlocks.Clear();
|
||||
|
||||
// convert bytearray to memory stream
|
||||
MemoryStream stream = new MemoryStream(data);
|
||||
|
||||
// the first 2 bytes of the TAP file designate the length of the first data block
|
||||
// this (I think) should always be 17 bytes (as this is the tape header)
|
||||
byte[] blockLengthData = new byte[2];
|
||||
|
||||
// we are now going to stream through the entire file processing a block at a time
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
// read and calculate the length of the block
|
||||
stream.Read(blockLengthData, 0, 2);
|
||||
int blockSize = BitConverter.ToUInt16(blockLengthData, 0);
|
||||
if (blockSize == 0)
|
||||
{
|
||||
// block size is 0 - this is probably invalid (but I guess could be EoF in some situations)
|
||||
break;
|
||||
}
|
||||
|
||||
// copy the entire block into a new bytearray
|
||||
byte[] blockdata = new byte[blockSize];
|
||||
stream.Read(blockdata, 0, blockSize);
|
||||
|
||||
// create and populate a new tapedatablock object
|
||||
TapeDataBlock tdb = new TapeDataBlock();
|
||||
|
||||
// ascertain the block description
|
||||
string description = string.Empty;
|
||||
byte crc = 0;
|
||||
byte crcValue = 0;
|
||||
byte crcFile = 0;
|
||||
byte[] programData = new byte[10];
|
||||
|
||||
// calculate block checksum value
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
crc ^= blockdata[i];
|
||||
if (i < blockSize - 1)
|
||||
{
|
||||
crcValue = crc;
|
||||
}
|
||||
else
|
||||
{
|
||||
crcFile = blockdata[i];
|
||||
}
|
||||
}
|
||||
|
||||
// process the type byte
|
||||
/* (The type is 0,1,2 or 3 for a Program, Number array, Character array or Code file.
|
||||
A SCREEN$ file is regarded as a Code file with start address 16384 and length 6912 decimal.
|
||||
If the file is a Program file, parameter 1 holds the autostart line number (or a number >=32768 if no LINE parameter was given)
|
||||
and parameter 2 holds the start of the variable area relative to the start of the program. If it's a Code file, parameter 1 holds
|
||||
the start of the code block when saved, and parameter 2 holds 32768. For data files finally, the byte at position 14 decimal holds the variable name.)
|
||||
*/
|
||||
|
||||
if (blockdata[0] == 0x00 && blockSize == 19 && (blockdata[1] == 0x00) || blockdata[1] == 3)
|
||||
{
|
||||
// This is the PROGRAM header
|
||||
// take the 10 filename bytes (that start at offset 2)
|
||||
programData = blockdata.Skip(2).Take(10).ToArray();
|
||||
|
||||
// get the filename as a string (with padding removed)
|
||||
string fileName = Encoding.ASCII.GetString(programData).Trim();
|
||||
|
||||
// get the type
|
||||
string type = "";
|
||||
if (blockdata[0] == 0x00)
|
||||
{
|
||||
type = "Program";
|
||||
}
|
||||
else
|
||||
{
|
||||
type = "Bytes";
|
||||
}
|
||||
|
||||
// now build the description string
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(type + ": ");
|
||||
sb.Append(fileName + " ");
|
||||
sb.Append(GetWordValue(blockdata, 14));
|
||||
sb.Append(":");
|
||||
sb.Append(GetWordValue(blockdata, 12));
|
||||
description = sb.ToString();
|
||||
}
|
||||
else if (blockdata[0] == 0xFF)
|
||||
{
|
||||
// this is a data block
|
||||
description = "Data Block " + (blockSize - 2) + "bytes";
|
||||
}
|
||||
else
|
||||
{
|
||||
// other type
|
||||
description = string.Format("#{0} block, {1} bytes", blockdata[0].ToString("X2"), blockSize - 2);
|
||||
description += string.Format(", crc {0}", ((crc != 0) ? string.Format("bad (#{0:X2}!=#{1:X2})", crcFile, crcValue) : "ok"));
|
||||
}
|
||||
|
||||
tdb.BlockDescription = BlockType.Standard_Speed_Data_Block;
|
||||
|
||||
// calculate the data periods for this block
|
||||
int pilotLength = 0;
|
||||
|
||||
// work out pilot length
|
||||
if (blockdata[0] < 4)
|
||||
{
|
||||
pilotLength = 8064;
|
||||
}
|
||||
else
|
||||
{
|
||||
pilotLength = 3220;
|
||||
}
|
||||
|
||||
// create a list to hold the data periods
|
||||
List<int> dataPeriods = new List<int>();
|
||||
|
||||
// generate pilot pulses
|
||||
for (int i = 0; i < pilotLength; i++)
|
||||
{
|
||||
dataPeriods.Add(PILOT_PL);
|
||||
}
|
||||
|
||||
// add syncro pulses
|
||||
dataPeriods.Add(SYNC_1_PL);
|
||||
dataPeriods.Add(SYNC_2_PL);
|
||||
|
||||
int pos = 0;
|
||||
|
||||
// add bit0 and bit1 periods
|
||||
for (int i = 0; i < blockSize - 1; i++, pos++)
|
||||
{
|
||||
for (byte b = 0x80; b != 0; b >>= 1)
|
||||
{
|
||||
if ((blockdata[i] & b) != 0)
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
else
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
if ((blockdata[i] & b) != 0)
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
else
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
}
|
||||
}
|
||||
|
||||
// add the last byte
|
||||
for (byte c = 0x80; c != (byte)(0x80 >> BIT_COUNT_IN_LAST); c >>= 1)
|
||||
{
|
||||
if ((blockdata[pos] & c) != 0)
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
else
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
if ((blockdata[pos] & c) != 0)
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
else
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
}
|
||||
|
||||
// add block pause
|
||||
int actualPause = PAUSE_MS * 1000;
|
||||
dataPeriods.Add(actualPause);
|
||||
|
||||
// add to the tapedatablock object
|
||||
tdb.DataPeriods = dataPeriods;
|
||||
|
||||
// add the raw data
|
||||
tdb.BlockData = blockdata;
|
||||
|
||||
// add block to the tape
|
||||
_datacorder.DataBlocks.Add(tdb);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the possible commands that can be raised from each tape block
|
||||
/// </summary>
|
||||
public enum TapeCommand
|
||||
{
|
||||
NONE,
|
||||
STOP_THE_TAPE,
|
||||
STOP_THE_TAPE_48K,
|
||||
BEGIN_GROUP,
|
||||
END_GROUP,
|
||||
SHOW_MESSAGE,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
using BizHawk.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a tape block
|
||||
/// </summary>
|
||||
public class TapeDataBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Either the TZX block ID, or -1 in the case of non-tzx blocks
|
||||
/// </summary>
|
||||
private int _blockID = -1;
|
||||
public int BlockID
|
||||
{
|
||||
get { return _blockID; }
|
||||
set {
|
||||
_blockID = value;
|
||||
|
||||
if (MetaData == null)
|
||||
MetaData = new Dictionary<BlockDescriptorTitle, string>();
|
||||
|
||||
AddMetaData(BlockDescriptorTitle.Block_ID, value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The block type
|
||||
/// </summary>
|
||||
private BlockType _blockType;
|
||||
public BlockType BlockDescription
|
||||
{
|
||||
get { return _blockType; }
|
||||
set {
|
||||
_blockType = value;
|
||||
if (MetaData == null)
|
||||
MetaData = new Dictionary<BlockDescriptorTitle, string>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Byte array containing the raw block data
|
||||
/// </summary>
|
||||
private byte[] _blockData;
|
||||
public byte[] BlockData
|
||||
{
|
||||
get { return _blockData; }
|
||||
set { _blockData = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An array of bytearray encoded strings (stored in this format for easy Bizhawk serialization)
|
||||
/// Its basically tape information
|
||||
/// </summary>
|
||||
private byte[][] _tapeDescriptionData;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Tape Description Data in a human readable format
|
||||
/// </summary>
|
||||
public List<string> TapeDescriptionData
|
||||
{
|
||||
get
|
||||
{
|
||||
List<string> data = new List<string>();
|
||||
|
||||
foreach (byte[] b in _tapeDescriptionData)
|
||||
{
|
||||
data.Add(Encoding.ASCII.GetString(b));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Block Meta Data
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of block related data
|
||||
/// </summary>
|
||||
public Dictionary<BlockDescriptorTitle, string> MetaData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a single metadata item to the Dictionary
|
||||
/// </summary>
|
||||
/// <param name="descriptor"></param>
|
||||
/// <param name="data"></param>
|
||||
public void AddMetaData(BlockDescriptorTitle descriptor, string data)
|
||||
{
|
||||
// check whether entry already exists
|
||||
bool check = MetaData.ContainsKey(descriptor);
|
||||
if (check)
|
||||
{
|
||||
// already exists - update
|
||||
MetaData[descriptor] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new
|
||||
MetaData.Add(descriptor, data);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// List containing the pulse timing values
|
||||
/// </summary>
|
||||
public List<int> DataPeriods = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Command that is raised by this data block
|
||||
/// (that may or may not need to be acted on)
|
||||
/// </summary>
|
||||
private TapeCommand _command = TapeCommand.NONE;
|
||||
public TapeCommand Command
|
||||
{
|
||||
get { return _command; }
|
||||
set { _command = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data periods as an array
|
||||
/// (primarily to aid in bizhawk state serialization)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int[] GetDataPeriodsArray()
|
||||
{
|
||||
return DataPeriods.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accepts an array of data periods and updates the DataPeriods list accordingly
|
||||
/// (primarily to aid in bizhawk state serialization)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void SetDataPeriodsArray(int[] periodArray)
|
||||
{
|
||||
DataPeriods = new List<int>();
|
||||
|
||||
if (periodArray == null)
|
||||
return;
|
||||
|
||||
DataPeriods = periodArray.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bizhawk state serialization
|
||||
/// </summary>
|
||||
/// <param name="ser"></param>
|
||||
public void SyncState(Serializer ser, int blockPosition)
|
||||
{
|
||||
ser.BeginSection("DataBlock" + blockPosition);
|
||||
|
||||
ser.Sync("_blockID", ref _blockID);
|
||||
//ser.SyncFixedString("_blockDescription", ref _blockDescription, 200);
|
||||
ser.SyncEnum("_blockType", ref _blockType);
|
||||
ser.Sync("_blockData", ref _blockData, true);
|
||||
ser.SyncEnum("_command", ref _command);
|
||||
|
||||
int[] tempArray = null;
|
||||
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
tempArray = GetDataPeriodsArray();
|
||||
ser.Sync("_periods", ref tempArray, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ser.Sync("_periods", ref tempArray, true);
|
||||
SetDataPeriodsArray(tempArray);
|
||||
}
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The types of TZX blocks
|
||||
/// </summary>
|
||||
public enum BlockType
|
||||
{
|
||||
Standard_Speed_Data_Block = 0x10,
|
||||
Turbo_Speed_Data_Block = 0x11,
|
||||
Pure_Tone = 0x12,
|
||||
Pulse_Sequence = 0x13,
|
||||
Pure_Data_Block = 0x14,
|
||||
Direct_Recording = 0x15,
|
||||
CSW_Recording = 0x18,
|
||||
Generalized_Data_Block = 0x19,
|
||||
Pause_or_Stop_the_Tape = 0x20,
|
||||
Group_Start = 0x21,
|
||||
Group_End = 0x22,
|
||||
Jump_to_Block = 0x23,
|
||||
Loop_Start = 0x24,
|
||||
Loop_End = 0x25,
|
||||
Call_Sequence = 0x26,
|
||||
Return_From_Sequence = 0x27,
|
||||
Select_Block = 0x28,
|
||||
Stop_the_Tape_48K = 0x2A,
|
||||
Set_Signal_Level = 0x2B,
|
||||
Text_Description = 0x30,
|
||||
Message_Block = 0x31,
|
||||
Archive_Info = 0x32,
|
||||
Hardware_Type = 0x33,
|
||||
Custom_Info_Block = 0x35,
|
||||
Glue_Block = 0x5A,
|
||||
|
||||
// depreciated blocks
|
||||
C64_ROM_Type_Data_Block = 0x16,
|
||||
C64_Turbo_Tape_Data_Block = 0x17,
|
||||
Emulation_Info = 0x34,
|
||||
Snapshot_Block = 0x40,
|
||||
|
||||
// unsupported / undetected
|
||||
Unsupported
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Different title possibilities
|
||||
/// </summary>
|
||||
public enum BlockDescriptorTitle
|
||||
{
|
||||
Undefined,
|
||||
Block_ID,
|
||||
Program,
|
||||
Data_Bytes,
|
||||
Bytes,
|
||||
|
||||
Pilot_Pulse_Length,
|
||||
Pilot_Pulse_Count,
|
||||
First_Sync_Length,
|
||||
Second_Sync_Length,
|
||||
Zero_Bit_Length,
|
||||
One_Bit_Length,
|
||||
Data_Length,
|
||||
Bits_In_Last_Byte,
|
||||
Pause_After_Data,
|
||||
|
||||
Pulse_Length,
|
||||
Pulse_Count,
|
||||
|
||||
Text_Description,
|
||||
Title,
|
||||
Publisher,
|
||||
Author,
|
||||
Year,
|
||||
Language,
|
||||
Type,
|
||||
Price,
|
||||
Protection,
|
||||
Origin,
|
||||
Comments,
|
||||
|
||||
Needs_Parsing
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,288 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// My attempt at mixing multiple ISoundProvider sources together and outputting another ISoundProvider
|
||||
/// Currently only supports SyncSoundMode.Sync
|
||||
/// Attached ISoundProvider sources must already be stereo 44.1khz and ideally sound buffers should be the same length
|
||||
/// </summary>
|
||||
internal sealed class SoundProviderMixer : ISoundProvider
|
||||
{
|
||||
private class Provider
|
||||
{
|
||||
public ISoundProvider SoundProvider { get; set; }
|
||||
public int MaxVolume { get; set; }
|
||||
public short[] Buffer { get; set; }
|
||||
public int NSamp { get; set; }
|
||||
}
|
||||
|
||||
private bool _stereo = true;
|
||||
public bool Stereo
|
||||
{
|
||||
get { return _stereo; }
|
||||
set { _stereo = value; }
|
||||
}
|
||||
|
||||
private readonly List<Provider> SoundProviders;
|
||||
|
||||
public SoundProviderMixer(params ISoundProvider[] soundProviders)
|
||||
{
|
||||
SoundProviders = new List<Provider>();
|
||||
|
||||
foreach (var s in soundProviders)
|
||||
{
|
||||
SoundProviders.Add(new Provider
|
||||
{
|
||||
SoundProvider = s,
|
||||
MaxVolume = short.MaxValue,
|
||||
});
|
||||
}
|
||||
|
||||
EqualizeVolumes();
|
||||
}
|
||||
|
||||
public SoundProviderMixer(short maxVolume, params ISoundProvider[] soundProviders)
|
||||
{
|
||||
SoundProviders = new List<Provider>();
|
||||
|
||||
foreach (var s in soundProviders)
|
||||
{
|
||||
SoundProviders.Add(new Provider
|
||||
{
|
||||
SoundProvider = s,
|
||||
MaxVolume = maxVolume,
|
||||
});
|
||||
}
|
||||
|
||||
EqualizeVolumes();
|
||||
}
|
||||
|
||||
public void AddSource(ISoundProvider source)
|
||||
{
|
||||
SoundProviders.Add(new Provider
|
||||
{
|
||||
SoundProvider = source,
|
||||
MaxVolume = short.MaxValue
|
||||
});
|
||||
|
||||
EqualizeVolumes();
|
||||
}
|
||||
|
||||
public void AddSource(ISoundProvider source, short maxVolume)
|
||||
{
|
||||
SoundProviders.Add(new Provider
|
||||
{
|
||||
SoundProvider = source,
|
||||
MaxVolume = maxVolume
|
||||
});
|
||||
|
||||
EqualizeVolumes();
|
||||
}
|
||||
|
||||
public void DisableSource(ISoundProvider source)
|
||||
{
|
||||
var sp = SoundProviders.Where(a => a.SoundProvider == source);
|
||||
if (sp.Count() == 1)
|
||||
SoundProviders.Remove(sp.First());
|
||||
else if (sp.Count() > 1)
|
||||
foreach (var s in sp)
|
||||
SoundProviders.Remove(s);
|
||||
|
||||
EqualizeVolumes();
|
||||
}
|
||||
|
||||
public void EqualizeVolumes()
|
||||
{
|
||||
if (SoundProviders.Count < 1)
|
||||
return;
|
||||
|
||||
int eachVolume = short.MaxValue / SoundProviders.Count;
|
||||
foreach (var source in SoundProviders)
|
||||
{
|
||||
source.MaxVolume = eachVolume;
|
||||
}
|
||||
}
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
foreach (var soundSource in SoundProviders)
|
||||
{
|
||||
soundSource.SoundProvider.DiscardSamples();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
samples = null;
|
||||
nsamp = 0;
|
||||
|
||||
// get samples from all the providers
|
||||
foreach (var sp in SoundProviders)
|
||||
{
|
||||
int sampCount;
|
||||
short[] samp;
|
||||
sp.SoundProvider.GetSamplesSync(out samp, out sampCount);
|
||||
sp.NSamp = sampCount;
|
||||
sp.Buffer = samp;
|
||||
}
|
||||
|
||||
// are all the sample lengths the same?
|
||||
var firstEntry = SoundProviders.First();
|
||||
bool sameCount = SoundProviders.All(s => s.NSamp == firstEntry.NSamp);
|
||||
|
||||
|
||||
if (sameCount)
|
||||
{
|
||||
nsamp = firstEntry.NSamp;
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
if (_stereo)
|
||||
{
|
||||
for (int i = 0; i < samples.Length; i++)
|
||||
{
|
||||
short sectorVal = 0;
|
||||
foreach (var sp in SoundProviders)
|
||||
{
|
||||
if (sp.Buffer[i] > sp.MaxVolume)
|
||||
sectorVal += (short)sp.MaxVolume;
|
||||
else
|
||||
{
|
||||
sectorVal += sp.Buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
samples[i] = sectorVal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// convert to mono
|
||||
for (int i = 0; i < samples.Length; i += 2)
|
||||
{
|
||||
short s = 0;
|
||||
foreach (var sp in SoundProviders)
|
||||
{
|
||||
s += (short)((sp.Buffer[i] + sp.Buffer[i + 1]) / 2);
|
||||
}
|
||||
|
||||
samples[i] = s;
|
||||
samples[i + 1] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (!sameCount)
|
||||
{
|
||||
// this is a pretty poor implementation that doesnt work very well
|
||||
// ideally soundproviders should ensure that their number of samples is identical
|
||||
int divisor = 1;
|
||||
int highestCount = 0;
|
||||
|
||||
// get the lowest divisor of all the soundprovider nsamps
|
||||
for (int d = 2; d < 999; d++)
|
||||
{
|
||||
bool divFound = false;
|
||||
foreach (var sp in SoundProviders)
|
||||
{
|
||||
if (sp.NSamp > highestCount)
|
||||
highestCount = sp.NSamp;
|
||||
|
||||
if (sp.NSamp % d == 0)
|
||||
divFound = true;
|
||||
else
|
||||
divFound = false;
|
||||
}
|
||||
|
||||
if (divFound)
|
||||
{
|
||||
divisor = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// now we have the largest current number of samples among the providers
|
||||
// along with a common divisor for all of them
|
||||
nsamp = highestCount * divisor;
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
// take a pass at populating the samples array for each provider
|
||||
foreach (var sp in SoundProviders)
|
||||
{
|
||||
short sectorVal = 0;
|
||||
int pos = 0;
|
||||
for (int i = 0; i < sp.Buffer.Length; i++)
|
||||
{
|
||||
if (sp.Buffer[i] > sp.MaxVolume)
|
||||
sectorVal = (short)sp.MaxVolume;
|
||||
else
|
||||
sectorVal = sp.Buffer[i];
|
||||
|
||||
for (int s = 0; s < divisor; s++)
|
||||
{
|
||||
samples[pos++] += sectorVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// get the highest number of samples
|
||||
int max = SoundProviders.Aggregate((i, j) => i.Buffer.Length > j.Buffer.Length ? i : j).Buffer.Length;
|
||||
|
||||
nsamp = max;
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
// take a pass at populating the samples array for each provider
|
||||
foreach (var sp in SoundProviders)
|
||||
{
|
||||
short sectorVal = 0;
|
||||
int pos = 0;
|
||||
for (int i = 0; i < sp.Buffer.Length; i++)
|
||||
{
|
||||
if (sp.Buffer[i] > sp.MaxVolume)
|
||||
sectorVal = (short)sp.MaxVolume;
|
||||
else
|
||||
{
|
||||
if (sp.SoundProvider is AY38912)
|
||||
{
|
||||
// boost audio
|
||||
sectorVal += (short)(sp.Buffer[i] * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
sectorVal += sp.Buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
samples[pos++] += sectorVal;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum
|
||||
{
|
||||
/// <summary>
|
||||
/// The one ZX Hawk ControllerDefinition
|
||||
/// </summary>
|
||||
public ControllerDefinition ZXSpectrumControllerDefinition
|
||||
{
|
||||
get
|
||||
{
|
||||
ControllerDefinition definition = new ControllerDefinition();
|
||||
definition.Name = "ZXSpectrum Controller";
|
||||
|
||||
// joysticks
|
||||
List<string> joys1 = new List<string>
|
||||
{
|
||||
// P1 Joystick
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
|
||||
};
|
||||
|
||||
foreach (var s in joys1)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "J1 (" + ((ZXSpectrumSyncSettings)SyncSettings as ZXSpectrumSyncSettings).JoystickType1.ToString() + ")";
|
||||
}
|
||||
|
||||
List<string> joys2 = new List<string>
|
||||
{
|
||||
// P2 Joystick
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button",
|
||||
};
|
||||
|
||||
foreach (var s in joys2)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "J2 (" + ((ZXSpectrumSyncSettings)SyncSettings as ZXSpectrumSyncSettings).JoystickType2.ToString() + ")";
|
||||
}
|
||||
|
||||
List<string> joys3 = new List<string>
|
||||
{
|
||||
// P3 Joystick
|
||||
"P3 Up", "P3 Down", "P3 Left", "P3 Right", "P3 Button",
|
||||
};
|
||||
|
||||
foreach (var s in joys3)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "J3 (" + ((ZXSpectrumSyncSettings)SyncSettings as ZXSpectrumSyncSettings).JoystickType3.ToString() + ")";
|
||||
}
|
||||
|
||||
// keyboard
|
||||
List<string> keys = new List<string>
|
||||
{
|
||||
/// Controller mapping includes all keyboard keys from the following models:
|
||||
/// https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/ZXSpectrum48k.jpg/1200px-ZXSpectrum48k.jpg
|
||||
/// https://upload.wikimedia.org/wikipedia/commons/c/ca/ZX_Spectrum%2B.jpg
|
||||
|
||||
// Keyboard - row 1
|
||||
"Key True Video", "Key Inv Video", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Key 0", "Key Break",
|
||||
// Keyboard - row 2
|
||||
"Key Delete", "Key Graph", "Key Q", "Key W", "Key E", "Key R", "Key T", "Key Y", "Key U", "Key I", "Key O", "Key P",
|
||||
// Keyboard - row 3
|
||||
"Key Extend Mode", "Key Edit", "Key A", "Key S", "Key D", "Key F", "Key G", "Key H", "Key J", "Key K", "Key L", "Key Return",
|
||||
// Keyboard - row 4
|
||||
"Key Caps Shift", "Key Caps Lock", "Key Z", "Key X", "Key C", "Key V", "Key B", "Key N", "Key M", "Key Period",
|
||||
// Keyboard - row 5
|
||||
"Key Symbol Shift", "Key Semi-Colon", "Key Quote", "Key Left Cursor", "Key Right Cursor", "Key Space", "Key Up Cursor", "Key Down Cursor", "Key Comma",
|
||||
};
|
||||
|
||||
foreach (var s in keys)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Keyboard";
|
||||
}
|
||||
|
||||
// Datacorder (tape device)
|
||||
List<string> power = new List<string>
|
||||
{
|
||||
// Tape functions
|
||||
"Soft Reset", "Hard Reset"
|
||||
};
|
||||
|
||||
foreach (var s in power)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Power";
|
||||
}
|
||||
|
||||
// Datacorder (tape device)
|
||||
List<string> tape = new List<string>
|
||||
{
|
||||
// Tape functions
|
||||
"Play Tape", "Stop Tape", "RTZ Tape", "Record Tape", "Insert Next Tape",
|
||||
"Insert Previous Tape", "Next Tape Block", "Prev Tape Block", "Get Tape Status"
|
||||
};
|
||||
|
||||
foreach (var s in tape)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Datacorder";
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Controller mapping includes all keyboard keys from the following models:
|
||||
/// https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/ZXSpectrum48k.jpg/1200px-ZXSpectrum48k.jpg
|
||||
/// https://upload.wikimedia.org/wikipedia/commons/c/ca/ZX_Spectrum%2B.jpg
|
||||
/// </summary>
|
||||
public static readonly ControllerDefinition ZXSpectrumControllerDefinition = new ControllerDefinition
|
||||
{
|
||||
Name = "ZXSpectrum Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// Kempston Joystick (P1)
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button",
|
||||
// Keyboard - row 1
|
||||
"Key True Video", "Key Inv Video", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Key 0", "Key Break",
|
||||
// Keyboard - row 2
|
||||
"Key Delete", "Key Graph", "Key Q", "Key W", "Key E", "Key R", "Key T", "Key Y", "Key U", "Key I", "Key O", "Key P",
|
||||
// Keyboard - row 3
|
||||
"Key Extend Mode", "Key Edit", "Key A", "Key S", "Key D", "Key F", "Key G", "Key H", "Key J", "Key K", "Key L", "Key Return",
|
||||
// Keyboard - row 4
|
||||
"Key Caps Shift", "Key Caps Lock", "Key Z", "Key X", "Key C", "Key V", "Key B", "Key N", "Key M", "Key Period",
|
||||
// Keyboard - row 5
|
||||
"Key Symbol Shift", "Key Semi-Colon", "Key Quote", "Key Left Cursor", "Key Right Cursor", "Key Space", "Key Up Cursor", "Key Down Cursor", "Key Comma",
|
||||
// Tape functions
|
||||
"Play Tape", "Stop Tape", "RTZ Tape", "Record Tape", "Insert Next Tape", "Insert Previous Tape", "Next Tape Block", "Prev Tape Block"
|
||||
}
|
||||
};
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The possible joystick types
|
||||
/// </summary>
|
||||
public enum JoystickType
|
||||
{
|
||||
NULL,
|
||||
Kempston,
|
||||
SinclairLEFT,
|
||||
SinclairRIGHT,
|
||||
Cursor
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = _cpu.Regs[_cpu.A],
|
||||
["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8),
|
||||
["B"] = _cpu.Regs[_cpu.B],
|
||||
["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8),
|
||||
["C"] = _cpu.Regs[_cpu.C],
|
||||
["D"] = _cpu.Regs[_cpu.D],
|
||||
["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8),
|
||||
["E"] = _cpu.Regs[_cpu.E],
|
||||
["F"] = _cpu.Regs[_cpu.F],
|
||||
["H"] = _cpu.Regs[_cpu.H],
|
||||
["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8),
|
||||
["I"] = _cpu.Regs[_cpu.I],
|
||||
["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8),
|
||||
["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
|
||||
["L"] = _cpu.Regs[_cpu.L],
|
||||
["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8),
|
||||
["R"] = _cpu.Regs[_cpu.R],
|
||||
["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8),
|
||||
["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8),
|
||||
["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8),
|
||||
["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8),
|
||||
["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8),
|
||||
["Flag C"] = _cpu.FlagC,
|
||||
["Flag N"] = _cpu.FlagN,
|
||||
["Flag P/V"] = _cpu.FlagP,
|
||||
["Flag 3rd"] = _cpu.Flag3,
|
||||
["Flag H"] = _cpu.FlagH,
|
||||
["Flag 5th"] = _cpu.Flag5,
|
||||
["Flag Z"] = _cpu.FlagZ,
|
||||
["Flag S"] = _cpu.FlagS
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.Regs[_cpu.A] = (ushort)value;
|
||||
break;
|
||||
case "AF":
|
||||
_cpu.Regs[_cpu.F] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "B":
|
||||
_cpu.Regs[_cpu.B] = (ushort)value;
|
||||
break;
|
||||
case "BC":
|
||||
_cpu.Regs[_cpu.C] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "C":
|
||||
_cpu.Regs[_cpu.C] = (ushort)value;
|
||||
break;
|
||||
case "D":
|
||||
_cpu.Regs[_cpu.D] = (ushort)value;
|
||||
break;
|
||||
case "DE":
|
||||
_cpu.Regs[_cpu.E] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "E":
|
||||
_cpu.Regs[_cpu.E] = (ushort)value;
|
||||
break;
|
||||
case "F":
|
||||
_cpu.Regs[_cpu.F] = (ushort)value;
|
||||
break;
|
||||
case "H":
|
||||
_cpu.Regs[_cpu.H] = (ushort)value;
|
||||
break;
|
||||
case "HL":
|
||||
_cpu.Regs[_cpu.L] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "I":
|
||||
_cpu.Regs[_cpu.I] = (ushort)value;
|
||||
break;
|
||||
case "IX":
|
||||
_cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "IY":
|
||||
_cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "L":
|
||||
_cpu.Regs[_cpu.L] = (ushort)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "R":
|
||||
_cpu.Regs[_cpu.R] = (ushort)value;
|
||||
break;
|
||||
case "Shadow AF":
|
||||
_cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow BC":
|
||||
_cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow DE":
|
||||
_cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow HL":
|
||||
_cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "SP":
|
||||
_cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; }
|
||||
|
||||
public bool CanStep(StepType type) => false;
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles => (int)_cpu.TotalExecutedCycles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum : IEmulator
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition { get; set; }
|
||||
|
||||
public void FrameAdvance(IController controller, bool render, bool renderSound)
|
||||
{
|
||||
_controller = controller;
|
||||
|
||||
bool ren = render;
|
||||
bool renSound = renderSound;
|
||||
|
||||
if (DeterministicEmulation)
|
||||
{
|
||||
ren = true;
|
||||
renSound = true;
|
||||
}
|
||||
|
||||
_isLag = true;
|
||||
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
_cpu.TraceCallback = s => _tracer.Put(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpu.TraceCallback = null;
|
||||
}
|
||||
|
||||
_machine.ExecuteFrame(ren, renSound);
|
||||
|
||||
if (_isLag)
|
||||
{
|
||||
_lagCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public int Frame
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_machine == null)
|
||||
return 0;
|
||||
else
|
||||
return _machine.FrameCount;
|
||||
}
|
||||
}
|
||||
|
||||
public string SystemId => "ZXSpectrum";
|
||||
|
||||
private bool deterministicEmulation;
|
||||
public bool DeterministicEmulation
|
||||
{
|
||||
get { return deterministicEmulation; }
|
||||
}
|
||||
|
||||
//public bool DeterministicEmulation => true;
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_machine.FrameCount = 0;
|
||||
_lagCount = 0;
|
||||
_isLag = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_machine != null)
|
||||
{
|
||||
_machine = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum : IInputPollable
|
||||
{
|
||||
public int LagCount
|
||||
{
|
||||
get { return _lagCount; }
|
||||
set { _lagCount = value; }
|
||||
}
|
||||
|
||||
public bool IsLagFrame
|
||||
{
|
||||
get { return _isLag; }
|
||||
set { _isLag = value; }
|
||||
}
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; }
|
||||
|
||||
private int _lagCount = 0;
|
||||
private bool _isLag = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum //: IMemoryDomains
|
||||
{
|
||||
internal IMemoryDomains memoryDomains;
|
||||
private readonly Dictionary<string, MemoryDomainByteArray> _byteArrayDomains = new Dictionary<string, MemoryDomainByteArray>();
|
||||
private bool _memoryDomainsInit = false;
|
||||
|
||||
private void SetupMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Little,
|
||||
(addr) =>
|
||||
{
|
||||
if (addr < 0 || addr >= 65536)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
return _machine.ReadBus((ushort)addr);
|
||||
},
|
||||
(addr, value) =>
|
||||
{
|
||||
if (addr < 0 || addr >= 65536)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
_machine.WriteBus((ushort)addr, value);
|
||||
}, 1)
|
||||
};
|
||||
|
||||
SyncAllByteArrayDomains();
|
||||
|
||||
memoryDomains = new MemoryDomainList(_byteArrayDomains.Values.Concat(domains).ToList());
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(memoryDomains);
|
||||
|
||||
_memoryDomainsInit = true;
|
||||
}
|
||||
|
||||
private void SyncAllByteArrayDomains()
|
||||
{
|
||||
SyncByteArrayDomain("ROM0", _machine.ROM0);
|
||||
SyncByteArrayDomain("ROM1", _machine.ROM1);
|
||||
SyncByteArrayDomain("ROM2", _machine.ROM2);
|
||||
SyncByteArrayDomain("ROM3", _machine.ROM3);
|
||||
SyncByteArrayDomain("RAM0", _machine.RAM0);
|
||||
SyncByteArrayDomain("RAM1", _machine.RAM1);
|
||||
SyncByteArrayDomain("RAM2", _machine.RAM2);
|
||||
SyncByteArrayDomain("RAM3", _machine.RAM3);
|
||||
SyncByteArrayDomain("RAM4", _machine.RAM4);
|
||||
SyncByteArrayDomain("RAM5", _machine.RAM5);
|
||||
SyncByteArrayDomain("RAM6", _machine.RAM6);
|
||||
SyncByteArrayDomain("RAM7", _machine.RAM7);
|
||||
}
|
||||
|
||||
private void SyncByteArrayDomain(string name, byte[] data)
|
||||
{
|
||||
|
||||
if (_memoryDomainsInit || _byteArrayDomains.ContainsKey(name))
|
||||
{
|
||||
var m = _byteArrayDomains[name];
|
||||
m.Data = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
var m = new MemoryDomainByteArray(name, MemoryDomain.Endian.Little, data, true, 1);
|
||||
_byteArrayDomains.Add(name, m);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum : ISettable<ZXSpectrum.ZXSpectrumSettings, ZXSpectrum.ZXSpectrumSyncSettings>
|
||||
{
|
||||
internal ZXSpectrumSettings Settings = new ZXSpectrumSettings();
|
||||
internal ZXSpectrumSyncSettings SyncSettings = new ZXSpectrumSyncSettings();
|
||||
|
||||
public ZXSpectrumSettings GetSettings()
|
||||
{
|
||||
return Settings.Clone();
|
||||
}
|
||||
|
||||
public ZXSpectrumSyncSettings GetSyncSettings()
|
||||
{
|
||||
return SyncSettings.Clone();
|
||||
}
|
||||
|
||||
public bool PutSettings(ZXSpectrumSettings o)
|
||||
{
|
||||
//if (SoundMixer != null)
|
||||
//SoundMixer.Stereo = o.StereoSound;
|
||||
|
||||
if (_machine != null && _machine.AYDevice != null && _machine.AYDevice.GetType() == typeof(AYChip))
|
||||
{
|
||||
((AYChip)_machine.AYDevice as AYChip).PanningConfiguration = o.AYPanConfig;
|
||||
}
|
||||
|
||||
Settings = o;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool PutSyncSettings(ZXSpectrumSyncSettings o)
|
||||
{
|
||||
bool ret = ZXSpectrumSyncSettings.NeedsReboot(SyncSettings, o);
|
||||
SyncSettings = o;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class ZXSpectrumSettings
|
||||
{
|
||||
[DisplayName("Auto-load/stop tape")]
|
||||
[Description("Auto or manual tape operation. Auto will attempt to detect CPU tape traps and automatically Stop/Start the tape")]
|
||||
[DefaultValue(true)]
|
||||
public bool AutoLoadTape { get; set; }
|
||||
|
||||
/*
|
||||
[DisplayName("Stereo Sound")]
|
||||
[Description("Turn stereo sound on or off")]
|
||||
[DefaultValue(true)]
|
||||
public bool StereoSound { get; set; }
|
||||
*/
|
||||
|
||||
[DisplayName("AY-3-8912 Panning Config")]
|
||||
[Description("Set the PSG panning configuration.\nThe chip has 3 audio channels that can be outputed in different configurations")]
|
||||
[DefaultValue(AYChip.AYPanConfig.ABC)]
|
||||
public AYChip.AYPanConfig AYPanConfig { get; set; }
|
||||
|
||||
[DisplayName("Core OSD Message Verbosity")]
|
||||
[Description("Full: Display all GUI messages\nMedium: Display only emulator/device generated messages\nNone: Show no messages")]
|
||||
[DefaultValue(OSDVerbosity.Medium)]
|
||||
public OSDVerbosity OSDMessageVerbosity { get; set; }
|
||||
|
||||
|
||||
public ZXSpectrumSettings Clone()
|
||||
{
|
||||
return (ZXSpectrumSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public ZXSpectrumSettings()
|
||||
{
|
||||
BizHawk.Common.SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class ZXSpectrumSyncSettings
|
||||
{
|
||||
[DisplayName("Deterministic Emulation")]
|
||||
[Description("If true, the core agrees to behave in a completely deterministic manner")]
|
||||
[DefaultValue(true)]
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
[DisplayName("Spectrum model")]
|
||||
[Description("The model of spectrum to be emulated")]
|
||||
[DefaultValue(MachineType.ZXSpectrum48)]
|
||||
public MachineType MachineType { get; set; }
|
||||
|
||||
[DisplayName("Border type")]
|
||||
[Description("Select how to show the border area")]
|
||||
[DefaultValue(BorderType.Full)]
|
||||
public BorderType BorderType { get; set; }
|
||||
|
||||
[DisplayName("Tape Load Speed")]
|
||||
[Description("Select how fast the spectrum loads the game from tape")]
|
||||
[DefaultValue(TapeLoadSpeed.Accurate)]
|
||||
public TapeLoadSpeed TapeLoadSpeed { get; set; }
|
||||
|
||||
[DisplayName("Joystick 1")]
|
||||
[Description("The emulated joystick assigned to P1 (SHOULD BE UNIQUE TYPE!)")]
|
||||
[DefaultValue(JoystickType.Kempston)]
|
||||
public JoystickType JoystickType1 { get; set; }
|
||||
|
||||
[DisplayName("Joystick 2")]
|
||||
[Description("The emulated joystick assigned to P2 (SHOULD BE UNIQUE TYPE!)")]
|
||||
[DefaultValue(JoystickType.SinclairLEFT)]
|
||||
public JoystickType JoystickType2 { get; set; }
|
||||
|
||||
[DisplayName("Joystick 3")]
|
||||
[Description("The emulated joystick assigned to P3 (SHOULD BE UNIQUE TYPE!)")]
|
||||
[DefaultValue(JoystickType.SinclairRIGHT)]
|
||||
public JoystickType JoystickType3 { get; set; }
|
||||
|
||||
|
||||
public ZXSpectrumSyncSettings Clone()
|
||||
{
|
||||
return (ZXSpectrumSyncSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public ZXSpectrumSyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
|
||||
public static bool NeedsReboot(ZXSpectrumSyncSettings x, ZXSpectrumSyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public enum OSDVerbosity
|
||||
{
|
||||
/// <summary>
|
||||
/// Show all OSD messages
|
||||
/// </summary>
|
||||
Full,
|
||||
/// <summary>
|
||||
/// Only show machine/device generated messages
|
||||
/// </summary>
|
||||
Medium,
|
||||
/// <summary>
|
||||
/// No core-driven OSD messages
|
||||
/// </summary>
|
||||
None
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The size of the Spectrum border
|
||||
/// </summary>
|
||||
public enum BorderType
|
||||
{
|
||||
/// <summary>
|
||||
/// How it was originally back in the day
|
||||
/// </summary>
|
||||
Full,
|
||||
|
||||
/// <summary>
|
||||
/// All borders 24px
|
||||
/// </summary>
|
||||
Medium,
|
||||
|
||||
/// <summary>
|
||||
/// All borders 10px
|
||||
/// </summary>
|
||||
Small,
|
||||
|
||||
/// <summary>
|
||||
/// No border at all
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Top and bottom border removed so that the result is *almost* 16:9
|
||||
/// </summary>
|
||||
Widescreen,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The speed at which the tape is loaded
|
||||
/// NOT IN USE YET
|
||||
/// </summary>
|
||||
public enum TapeLoadSpeed
|
||||
{
|
||||
Accurate,
|
||||
//Fast,
|
||||
//Fastest
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides information on each emulated machine
|
||||
/// </summary>
|
||||
public class ZXMachineMetaData
|
||||
{
|
||||
public MachineType MachineType { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Released { get; set; }
|
||||
public string CPU { get; set; }
|
||||
public string Memory { get; set; }
|
||||
public string Video { get; set; }
|
||||
public string Audio { get; set; }
|
||||
public string Media { get; set; }
|
||||
public string OtherMisc { get; set; }
|
||||
|
||||
|
||||
public static ZXMachineMetaData GetMetaObject(MachineType type)
|
||||
{
|
||||
ZXMachineMetaData m = new ZXMachineMetaData();
|
||||
m.MachineType = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MachineType.ZXSpectrum16:
|
||||
m.Name = "Sinclair ZX Spectrum 16K";
|
||||
m.Description = "The original ZX Spectrum 16K RAM version. Aside from available RAM this machine is technically identical to the 48K machine that was released at the same time. ";
|
||||
m.Description += "Due to the small amount of RAM, very few games were actually made to run on this model.";
|
||||
m.Released = "1982";
|
||||
m.CPU = "Zilog Z80A @ 3.5MHz";
|
||||
m.Memory = "16KB ROM / 16KB RAM";
|
||||
m.Video = "ULA @ 7MHz - PAL (50.08Hz Interrupt)";
|
||||
m.Audio = "Beeper (HW 1ch. / 10oct.) - Internal Speaker";
|
||||
m.Media = "Cassette Tape (via 3rd party external tape player)";
|
||||
break;
|
||||
case MachineType.ZXSpectrum48:
|
||||
m.Name = "Sinclair ZX Spectrum 48K / 48K+";
|
||||
m.Description = "The original ZX Spectrum 48K RAM version. 2 years later a 'plus' version was released that had a better keyboard. ";
|
||||
m.Description += "Electronically both the 48K and + are identical, so ZXHawk treats them as the same emulated machine. ";
|
||||
m.Description += "These machines dominated the UK 8-bit home computer market throughout the 1980's so most non-128k only games are compatible.";
|
||||
m.Released = "1982 (48K) / 1984 (48K+)";
|
||||
m.CPU = "Zilog Z80A @ 3.5MHz";
|
||||
m.Memory = "16KB ROM / 48KB RAM";
|
||||
m.Video = "ULA @ 7MHz - PAL (50.08Hz Interrupt)";
|
||||
m.Audio = "Beeper (HW 1ch. / 10oct.) - Internal Speaker";
|
||||
m.Media = "Cassette Tape (via 3rd party external tape player)";
|
||||
break;
|
||||
case MachineType.ZXSpectrum128:
|
||||
m.Name = "Sinclair ZX Spectrum 128";
|
||||
m.Description = "The first Spectrum 128K machine released in Spain in 1985 and later UK in 1986. ";
|
||||
m.Description += "With an updated ROM and new memory paging system to work around the Z80's 16-bit address bus. ";
|
||||
m.Description += "The 128 shipped with a copy of the 48k ROM (that is paged in when required) and a new startup menu with the option of dropping into a '48k mode'. ";
|
||||
m.Description += "Even so, there were some compatibility issues with older Spectrum games that were written to utilise some of the previous model's intricacies. ";
|
||||
m.Description += "Many games released after 1985 supported the new AY-3-8912 PSG chip making for far superior audio. The extra memory also enabled many games to be loaded in all at once (rather than loading each level from tape when needed).";
|
||||
m.Released = "1985 / 1986";
|
||||
m.CPU = "Zilog Z80A @ 3.5469 MHz";
|
||||
m.Memory = "32KB ROM / 128KB RAM";
|
||||
m.Video = "ULA @ 7.0938MHz - PAL (50.01Hz Interrupt)";
|
||||
m.Audio = "Beeper (HW 1ch. / 10oct.) & General Instruments AY-3-8912 PSG (3ch) - RF Output";
|
||||
m.Media = "Cassette Tape (via 3rd party external tape player)";
|
||||
break;
|
||||
case MachineType.ZXSpectrum128Plus2:
|
||||
m.Name = "Sinclair ZX Spectrum +2";
|
||||
m.Description = "The first Sinclair Spectrum 128K machine that was released after Amstrad purchased Sinclair in 1986. ";
|
||||
m.Description += "Electronically it was almost identical to the 128, but with the addition of a built-in tape deck and 2 Sinclair Joystick ports.";
|
||||
m.Released = "1986";
|
||||
m.CPU = "Zilog Z80A @ 3.5469 MHz";
|
||||
m.Memory = "32KB ROM / 128KB RAM";
|
||||
m.Video = "ULA @ 7.0938MHz - PAL (50.01Hz Interrupt)";
|
||||
m.Audio = "Beeper (HW 1ch. / 10oct.) & General Instruments AY-3-8912 PSG (3ch) - RF Output";
|
||||
m.Media = "Cassette Tape (via built-in Datacorder)";
|
||||
break;
|
||||
case MachineType.ZXSpectrum128Plus2a:
|
||||
m.Name = "Sinclair ZX Spectrum +2a";
|
||||
m.Description = "The +2a looks almost identical to the +2 but is a variant of the +3 machine that was released the same year (except with the same built-in datacorder that the +2 had rather than a floppy drive). ";
|
||||
m.Description += "Memory paging again changed significantly and this (along with memory contention timing changes) caused more compatibility issues with some older games. ";
|
||||
m.Description += "Although functionally identical to the +3, it does not contain floppy disk controller.";
|
||||
m.Released = "1987";
|
||||
m.CPU = "Zilog Z80A @ 3.5469 MHz";
|
||||
m.Memory = "64KB ROM / 128KB RAM";
|
||||
m.Video = "ULA @ 7.0938MHz - PAL (50.01Hz Interrupt)";
|
||||
m.Audio = "Beeper (HW 1ch. / 10oct.) & General Instruments AY-3-8912 PSG (3ch) - RF Output";
|
||||
m.Media = "Cassette Tape (via built-in Datacorder)";
|
||||
break;
|
||||
case MachineType.ZXSpectrum128Plus3:
|
||||
m.Name = "Sinclair ZX Spectrum +3";
|
||||
m.Description = "Amstrad released the +3 the same year as the +2a, but it featured a built-in floppy drive rather than a datacorder. An external cassette player could still be connected though as in the older 48k models. ";
|
||||
m.Description += "Memory paging again changed significantly and this (along with memory contention timing changes) caused more compatibility issues with some older games. ";
|
||||
m.Description += "Currently ZXHawk does not emulate the floppy drive or floppy controller so the machine reports as a +2a on boot.";
|
||||
m.Released = "1987";
|
||||
m.CPU = "Zilog Z80A @ 3.5469 MHz";
|
||||
m.Memory = "64KB ROM / 128KB RAM";
|
||||
m.Video = "ULA @ 7.0938MHz - PAL (50.01Hz Interrupt)";
|
||||
m.Audio = "Beeper (HW 1ch. / 10oct.) & General Instruments AY-3-8912 PSG (3ch) - RF Output";
|
||||
m.Media = "3\" Floppy Disk (via built-in Floppy Drive)";
|
||||
break;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public static string GetMetaString(MachineType type)
|
||||
{
|
||||
var m = GetMetaObject(type);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append(m.Name);
|
||||
sb.Append("\n");
|
||||
sb.Append("-----------------------------------------------------------------\n");
|
||||
// Release
|
||||
sb.Append("Released:");
|
||||
sb.Append(" ");
|
||||
sb.Append(m.Released);
|
||||
sb.Append("\n");
|
||||
// CPU
|
||||
sb.Append("CPU:");
|
||||
sb.Append(" ");
|
||||
sb.Append(m.CPU);
|
||||
sb.Append("\n");
|
||||
// Memory
|
||||
sb.Append("Memory:");
|
||||
sb.Append(" ");
|
||||
sb.Append(m.Memory);
|
||||
sb.Append("\n");
|
||||
// Video
|
||||
sb.Append("Video:");
|
||||
sb.Append(" ");
|
||||
sb.Append(m.Video);
|
||||
sb.Append("\n");
|
||||
// Audio
|
||||
sb.Append("Audio:");
|
||||
sb.Append(" ");
|
||||
sb.Append(m.Audio);
|
||||
sb.Append("\n");
|
||||
// Audio
|
||||
sb.Append("Media:");
|
||||
sb.Append(" ");
|
||||
sb.Append(m.Media);
|
||||
sb.Append("\n");
|
||||
|
||||
sb.Append("-----------------------------------------------------------------\n");
|
||||
// description
|
||||
sb.Append(m.Description);
|
||||
if (m.OtherMisc != null)
|
||||
sb.Append("\n" + m.OtherMisc);
|
||||
|
||||
return sb.ToString();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public partial class ZXSpectrum : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
SyncState(new Serializer(writer));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
SyncState(new Serializer(reader));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
ser.SyncEnum("_machineType", ref _machineType);
|
||||
|
||||
_cpu.SyncState(ser);
|
||||
ser.BeginSection("ZXSpectrum");
|
||||
_machine.SyncState(ser);
|
||||
ser.Sync("Frame", ref _machine.FrameCount);
|
||||
ser.Sync("LagCount", ref _lagCount);
|
||||
ser.Sync("IsLag", ref _isLag);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
if (ser.IsReader)
|
||||
{
|
||||
var tmpM = _machineType;
|
||||
ser.SyncEnum("_machineType", ref _machineType);
|
||||
if (tmpM != _machineType && _machineType.ToString() != "72")
|
||||
{
|
||||
string msg = "SAVESTATE FAILED TO LOAD!!\n\n";
|
||||
msg += "Current Configuration: " + tmpM.ToString();
|
||||
msg += "\n";
|
||||
msg += "Saved Configuration: " + _machineType.ToString();
|
||||
msg += "\n\n";
|
||||
msg += "If you wish to load this SaveState ensure that you have the correct machine configuration selected, reboot the core, then try again.";
|
||||
CoreComm.ShowMessage(msg);
|
||||
_machineType = tmpM;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpu.SyncState(ser);
|
||||
ser.BeginSection("ZXSpectrum");
|
||||
_machine.SyncState(ser);
|
||||
ser.Sync("Frame", ref _machine.FrameCount);
|
||||
ser.Sync("LagCount", ref _lagCount);
|
||||
ser.Sync("IsLag", ref _isLag);
|
||||
ser.EndSection();
|
||||
|
||||
SyncAllByteArrayDomains();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue