Merge branch 'master' into domainedmemoryhooks
This commit is contained in:
commit
ebcd237858
Binary file not shown.
|
@ -743,6 +743,34 @@
|
|||
"P2 B1": "",
|
||||
"P2 B2": ""
|
||||
},
|
||||
"SMS Paddle Controller": {
|
||||
"P1 Left": "LeftArrow, J1 POV1L",
|
||||
"P1 Right": "RightArrow, J1 POV1R",
|
||||
"P1 B1": "Z, J1 B1, X1 X",
|
||||
"Reset": "J1 B9, X1 Back",
|
||||
"Pause": "J1 B10, X1 Start"
|
||||
},
|
||||
"SMS Light Phaser Controller": {
|
||||
"P1 Trigger": "Z, J1 B1, X1 X, WMouse L",
|
||||
"Reset": "J1 B9, X1 Back",
|
||||
"Pause": "J1 B10, X1 Start"
|
||||
},
|
||||
"SMS Sports Pad Controller": {
|
||||
"P1 Up": "UpArrow, J1 POV1U",
|
||||
"P1 Down": "DownArrow, J1 POV1D",
|
||||
"P1 Left": "LeftArrow, J1 POV1L",
|
||||
"P1 Right": "RightArrow, J1 POV1R",
|
||||
"P1 B1": "Z, J1 B1, X1 X",
|
||||
"P1 B2": "X, J1 B2, X1 A",
|
||||
"Reset": "J1 B9, X1 Back",
|
||||
"Pause": "J1 B10, X1 Start",
|
||||
"P2 Up": "",
|
||||
"P2 Down": "",
|
||||
"P2 Left": "",
|
||||
"P2 Right": "",
|
||||
"P2 B1": "",
|
||||
"P2 B2": ""
|
||||
},
|
||||
"GG Controller": {
|
||||
"P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp",
|
||||
"P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown",
|
||||
|
@ -1567,6 +1595,47 @@
|
|||
"Mult": 1.0,
|
||||
"Deadzone": 0.1
|
||||
}
|
||||
},
|
||||
"SMS Paddle Controller": {
|
||||
"P1 Paddle": {
|
||||
"Value": "X1 LeftThumbX",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.1
|
||||
}
|
||||
},
|
||||
"SMS Light Phaser Controller": {
|
||||
"P1 X": {
|
||||
"Value": "WMouse X",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Y": {
|
||||
"Value": "WMouse Y",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
}
|
||||
},
|
||||
"SMS Sports Pad Controller": {
|
||||
"P1 X": {
|
||||
"Value": "X1 LeftThumbX",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.1
|
||||
},
|
||||
"P1 Y": {
|
||||
"Value": "X1 LeftThumbY",
|
||||
"Mult": -1.0,
|
||||
"Deadzone": 0.1
|
||||
},
|
||||
"P2 X": {
|
||||
"Value": "X2 LeftThumbX",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.1
|
||||
},
|
||||
"P2 Y": {
|
||||
"Value": "X2 LeftThumbY",
|
||||
"Mult": -1.0,
|
||||
"Deadzone": 0.1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -231,7 +231,7 @@ B19256C6716147A9744F5BD528F14450 Magic Knight Rayearth 2 - Making of Magic Knig
|
|||
846D48D0F4024C8094117599D0E1EEF1 Magic Knight Rayearth (J) GG SRAM=8192 Japan
|
||||
E496FF2196C372F4D6111538950D25CA Magical Puzzle Popils (W) (En,Ja) GG Puzzle SRAM=8192 World
|
||||
3AF0C6DDF5F00A493E1F159FCEDC0933 Magical Taruruuto-kun (J) GG Japan
|
||||
B0C35BC53AB7C184D34E5624F69AAD24 The Majors Pro Baseball (U) GG Sports;Baseball SRAM=128;GGLink USA
|
||||
B0C35BC53AB7C184D34E5624F69AAD24 The Majors Pro Baseball (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA
|
||||
A15C5219F766D516D1B8D9A09B9A2BB4 Mappy (J) GG Japan
|
||||
B83F36FD113A8F75F1A29652ACB641FC Marble Madness (UE) GG Arcade USA;Europe
|
||||
BA846684A66E90372C3C234955EE28BC Marko's Magic Football (E) (En,Fr,De,Es) GG Europe
|
||||
|
@ -461,9 +461,9 @@ A23E89266DDAD3C856E7401D04A49C6C Woody Pop (W) (Rev 1) GG World
|
|||
13F72ACFEA47587F9AA9F655BF98653C World Class Leader Board Golf (UE) GG Sports;Golf USA;Europe
|
||||
D95D381C6AFFB8345EE5457655E393D1 World Cup USA 94 (UE) (En,Fr,De,Es,It,Nl,Pt,Sv) GG Sports;Soccer USA;Europe
|
||||
D8939B64458FAF174CDC1241F777CB59 World Derby (J) GG GGLink Japan
|
||||
E7EABBFC7A1F1339C4720249AEA92A32 World Series Baseball '95 (U) GG Sports;Baseball SRAM=128;GGLink USA
|
||||
59359FC38865CFF00C90D6EB148DDC2F World Series Baseball (U) GG Sports;Baseball SRAM=128;GGLink USA
|
||||
05CAC33029F0CAAC27774504C1AA8597 World Series Baseball (U) (Rev 1) GG Sports;Baseball SRAM=128;GGLink USA
|
||||
E7EABBFC7A1F1339C4720249AEA92A32 World Series Baseball '95 (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA
|
||||
59359FC38865CFF00C90D6EB148DDC2F World Series Baseball (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA
|
||||
05CAC33029F0CAAC27774504C1AA8597 World Series Baseball (U) (Rev 1) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA
|
||||
D810E851AD60ED5BA50B6246C2CE12F2 WWF Raw (UE) GG Sports;Wrestling USA;Europe
|
||||
571AC03B80E3075C699CD583BF8651FD X-Men - Gamemaster's Legacy (UE) GG Marvel USA;Europe
|
||||
CA15F2BA2507EBD836C42D9D10231EB1 X-Men - Mojo World (UE) GG Marvel USA;Europe
|
||||
|
|
|
@ -106,7 +106,7 @@ F2535DF9BDC3A84221303FA62D61AD6E Back to the Future Part II (E) SMS Europe
|
|||
3D24A52E98E6C85D7C059386451CE749 Back to the Future Part III (E) SMS PAL Europe
|
||||
8A94DED3D95AA46DAE8800B92E66D3EE Baku Baku (B) SMS Brazil
|
||||
7A5D3B9963E316CB7F73BBDC2A7311C6 Bank Panic (E) SMS Europe
|
||||
26DF4404950CB8DA47235833C0C101C6 Bart vs. the Space Mutants (E) SMS Europe
|
||||
26DF4404950CB8DA47235833C0C101C6 Bart vs. the Space Mutants (E) SMS PAL Europe
|
||||
CBA2EC2940619956359801618E7AAB17 Bart vs. the World (E) SMS Europe
|
||||
0069B1BD9C5B6B88ACE6324D7E61539F Basketball Nightmare (E) SMS Sports;Basketball Europe
|
||||
215876A62D3CA48D28E98CD8A2C70A15 Batman Returns (E) SMS Europe
|
||||
|
|
|
@ -32,9 +32,6 @@ namespace BizHawk.Client.ApiHawk
|
|||
return CoreSystem.Atari2600;
|
||||
|
||||
case "A78":
|
||||
return CoreSystem.Atari2600;
|
||||
|
||||
case "A7800":
|
||||
return CoreSystem.Atari7800;
|
||||
|
||||
case "Coleco":
|
||||
|
|
|
@ -266,6 +266,12 @@ namespace BizHawk.Client.Common
|
|||
|
||||
return Path.Combine(MakeAbsolutePath(pathEntry.Path, game.System), name) + ".SaveRAM";
|
||||
}
|
||||
|
||||
public static string AutoSaveRamPath(GameInfo game)
|
||||
{
|
||||
var path = SaveRamPath(game);
|
||||
return path.Insert(path.Length - 8, ".AutoSaveRAM");
|
||||
}
|
||||
|
||||
public static string RetroSaveRAMDirectory(GameInfo game)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,6 @@ using BizHawk.Emulation.Common;
|
|||
using BizHawk.Emulation.Cores;
|
||||
using BizHawk.Emulation.Cores.Libretro;
|
||||
using BizHawk.Emulation.Cores.Atari.A7800Hawk;
|
||||
using BizHawk.Emulation.Cores.Atari.Atari7800;
|
||||
using BizHawk.Emulation.Cores.Calculators;
|
||||
using BizHawk.Emulation.Cores.Computers.AppleII;
|
||||
using BizHawk.Emulation.Cores.Computers.Commodore64;
|
||||
|
@ -471,7 +470,7 @@ namespace BizHawk.Client.Common
|
|||
System = "PSX"
|
||||
};
|
||||
}
|
||||
else if (ext == ".iso" || ext == ".cue" || ext == ".ccd")
|
||||
else if (ext == ".iso" || ext == ".cue" || ext == ".ccd" || ext == ".mds")
|
||||
{
|
||||
if (file.IsArchive)
|
||||
{
|
||||
|
@ -495,7 +494,7 @@ namespace BizHawk.Client.Common
|
|||
throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log);
|
||||
}
|
||||
|
||||
var disc = discMountJob.OUT_Disc;
|
||||
var disc = discMountJob.OUT_Disc;
|
||||
|
||||
// -----------
|
||||
// TODO - use more sophisticated IDer
|
||||
|
@ -515,7 +514,9 @@ namespace BizHawk.Client.Common
|
|||
// try to use our wizard methods
|
||||
game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name), Hash = discHash };
|
||||
|
||||
switch (new DiscIdentifier(disc).DetectDiscType())
|
||||
var dt = new DiscIdentifier(disc).DetectDiscType();
|
||||
|
||||
switch (dt)
|
||||
{
|
||||
case DiscType.SegaSaturn:
|
||||
game.System = "SAT";
|
||||
|
@ -533,9 +534,23 @@ namespace BizHawk.Client.Common
|
|||
case DiscType.PCFX:
|
||||
game.System = "PCFX";
|
||||
break;
|
||||
case DiscType.TurboCD:
|
||||
game.System = "PCECD";
|
||||
break;
|
||||
|
||||
case DiscType.Amiga:
|
||||
case DiscType.CDi:
|
||||
case DiscType.Dreamcast:
|
||||
case DiscType.GameCube:
|
||||
case DiscType.NeoGeoCD:
|
||||
case DiscType.Panasonic3DO:
|
||||
case DiscType.Playdia:
|
||||
case DiscType.Wii:
|
||||
// no supported emulator core for these (yet)
|
||||
game.System = dt.ToString();
|
||||
throw new NoAvailableCoreException(dt.ToString());
|
||||
|
||||
case DiscType.AudioDisc:
|
||||
case DiscType.TurboCD:
|
||||
case DiscType.UnknownCDFS:
|
||||
case DiscType.UnknownFormat:
|
||||
if (PreferredPlatformIsDefined(ext))
|
||||
|
@ -544,7 +559,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
game.System = "PCECD";
|
||||
game.System = "NULL"; // "PCECD";
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -553,6 +568,9 @@ namespace BizHawk.Client.Common
|
|||
|
||||
switch (game.System)
|
||||
{
|
||||
case "NULL":
|
||||
nextEmulator = null;
|
||||
break;
|
||||
case "GEN":
|
||||
var genesis = new GPGX(nextComm, null, new[] { disc }, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>());
|
||||
nextEmulator = genesis;
|
||||
|
@ -938,19 +956,8 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
break;
|
||||
case "A78":
|
||||
var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "EMU7800.csv");
|
||||
|
||||
if (!VersionInfo.DeveloperBuild)
|
||||
{
|
||||
nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath); // Don't expose A7800Hawk in releases yet
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEmulator = Global.Config.A78_UseEmu7800
|
||||
? nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath)
|
||||
: nextEmulator = new A7800Hawk(nextComm, game, rom.RomData, gamedbpath, GetCoreSettings<A7800Hawk>(), GetCoreSyncSettings<A7800Hawk>());
|
||||
}
|
||||
|
||||
var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb_a7800.csv");
|
||||
nextEmulator = new A7800Hawk(nextComm, game, rom.RomData, gamedbpath, GetCoreSettings<A7800Hawk>(), GetCoreSyncSettings<A7800Hawk>());
|
||||
break;
|
||||
case "C64":
|
||||
var c64 = new C64(nextComm, Enumerable.Repeat(rom.RomData, 1), rom.GameInfo, GetCoreSettings<C64>(), GetCoreSyncSettings<C64>());
|
||||
|
@ -1041,7 +1048,14 @@ namespace BizHawk.Client.Common
|
|||
DoMessageCallback("Failed to load a GB rom in SGB mode. Disabling SGB Mode.");
|
||||
return LoadRom(path, nextComm, false, recursiveCount + 1);
|
||||
}
|
||||
else
|
||||
|
||||
// handle exceptions thrown by the new detected systems that bizhawk does not have cores for
|
||||
else if (ex is NoAvailableCoreException)
|
||||
{
|
||||
DoLoadErrorCallback(ex.Message + "\n\n" + ex, system);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system);
|
||||
}
|
||||
|
|
|
@ -113,7 +113,6 @@ namespace BizHawk.Client.Common
|
|||
public bool InputConfigAutoTab = true;
|
||||
public bool ShowLogWindow = false;
|
||||
public bool BackupSavestates = true;
|
||||
public bool BackupSaveram = true;
|
||||
public bool SaveScreenshotWithStates = true;
|
||||
public int BigScreenshotSize = 128 * 1024;
|
||||
public bool NoLowResLargeScreenshotWithStates = false;
|
||||
|
@ -134,6 +133,21 @@ namespace BizHawk.Client.Common
|
|||
public string Update_IgnoreVersion = "";
|
||||
public bool CDLAutoSave = true, CDLAutoStart = true;
|
||||
|
||||
/// <summary>
|
||||
/// Makes a .bak file before any saveram-writing operation (could be extended to make timestamped backups)
|
||||
/// </summary>
|
||||
public bool BackupSaveram = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to make AutoSave files at periodic intervals
|
||||
/// </summary>
|
||||
public bool AutosaveSaveRAM;
|
||||
|
||||
/// <summary>
|
||||
/// Intervals at which to make AutoSave files
|
||||
/// </summary>
|
||||
public int FlushSaveRamFrames;
|
||||
|
||||
//check CurrentDomain_AssemblyResolve if you change the defaults or name of this key
|
||||
public bool UseNLua = true; // Whether or not to use a good, reliable, memory-leak-free lua interface that is slower than the original luainterface
|
||||
|
||||
|
@ -542,7 +556,6 @@ namespace BizHawk.Client.Common
|
|||
public bool NES_InQuickNES = true;
|
||||
public bool SNES_InSnes9x = true;
|
||||
public bool GBA_UsemGBA = true;
|
||||
public bool A78_UseEmu7800 = true;
|
||||
public bool SGB_UseBsnes = false;
|
||||
public bool CoreForcingViaGameDB = true;
|
||||
public string LibretroCore;
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.ComponentModel;
|
|||
using NLua;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
|
@ -108,6 +109,37 @@ namespace BizHawk.Client.Common
|
|||
return false;
|
||||
}
|
||||
|
||||
[LuaMethod("hash_region", "Returns a hash as a string of a region of memory, starting from addr, through count bytes. If the domain is unspecified, it uses the current region.")]
|
||||
public string HashRegion(int addr, int count, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
|
||||
// checks
|
||||
if (addr < 0 || addr >= d.Size)
|
||||
{
|
||||
string error = $"Address {addr} is outside the bounds of domain {d.Name}";
|
||||
Log(error);
|
||||
throw new ArgumentOutOfRangeException(error);
|
||||
}
|
||||
if (addr + count > d.Size)
|
||||
{
|
||||
string error = $"Address {addr} + count {count} is outside the bounds of domain {d.Name}";
|
||||
Log(error);
|
||||
throw new ArgumentOutOfRangeException(error);
|
||||
}
|
||||
|
||||
byte[] data = new byte[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
data[i] = d.PeekByte(addr + i);
|
||||
}
|
||||
|
||||
using (var hasher = System.Security.Cryptography.SHA256.Create())
|
||||
{
|
||||
return hasher.ComputeHash(data).BytesToHexString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Common Special and Legacy Methods
|
||||
|
|
|
@ -8,7 +8,6 @@ using BizHawk.Emulation.Cores.Nintendo.SNES9X;
|
|||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
||||
using BizHawk.Emulation.Cores.Atari.A7800Hawk;
|
||||
using BizHawk.Emulation.Cores.Atari.Atari7800;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
|
@ -465,7 +464,6 @@ namespace BizHawk.Client.Common
|
|||
public bool? PreviousNES_InQuickNES { get; set; }
|
||||
public bool? PreviousSNES_InSnes9x { get; set; }
|
||||
public bool? PreviousGBA_UsemGBA { get; set; }
|
||||
public bool? PreviousA78_UseEmu7800 { get; set; }
|
||||
|
||||
public void QueueNewMovie(IMovie movie, bool record, IEmulator emulator)
|
||||
{
|
||||
|
@ -533,22 +531,6 @@ namespace BizHawk.Client.Common
|
|||
Global.Config.GBA_UsemGBA = false;
|
||||
}
|
||||
}
|
||||
else if (!record && emulator.SystemId == "A78") // meh, copy pasta one more time, last time, I promise
|
||||
{
|
||||
var atari7800HawkName = ((CoreAttribute)Attribute.GetCustomAttribute(typeof(A7800Hawk), typeof(CoreAttribute))).CoreName;
|
||||
var emu7800HawkName = ((CoreAttribute)Attribute.GetCustomAttribute(typeof(Atari7800), typeof(CoreAttribute))).CoreName;
|
||||
|
||||
if (movie.Core == atari7800HawkName)
|
||||
{
|
||||
PreviousA78_UseEmu7800 = Global.Config.A78_UseEmu7800;
|
||||
Global.Config.A78_UseEmu7800 = true;
|
||||
}
|
||||
else if (movie.Core == emu7800HawkName)
|
||||
{
|
||||
PreviousA78_UseEmu7800 = Global.Config.A78_UseEmu7800;
|
||||
Global.Config.A78_UseEmu7800 = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (record) // This is a hack really, we need to set the movie to its propert state so that it will be considered active later
|
||||
{
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace BizHawk.Client.Common
|
|||
bool? PreviousNES_InQuickNES { get; set; }
|
||||
bool? PreviousSNES_InSnes9x { get; set; }
|
||||
bool? PreviousGBA_UsemGBA { get; set; }
|
||||
bool? PreviousA78_UseEmu7800 { get; set; }
|
||||
|
||||
void HandleMovieOnFrameLoop();
|
||||
void HandleMovieAfterFrameLoop();
|
||||
|
|
|
@ -514,14 +514,14 @@ namespace BizHawk.Client.Common
|
|||
|
||||
Log?.Dispose();
|
||||
Log = branch.InputLog.Clone();
|
||||
////_changes = true;
|
||||
|
||||
_lagLog.FromLagLog(branch.LagLog);
|
||||
|
||||
// if there are branch states, they will be loaded anyway
|
||||
// but if there's none, or only *after* divergent point, don't invalidate the entire movie anymore
|
||||
if (divergentPoint.HasValue)
|
||||
{
|
||||
_stateManager.Invalidate(divergentPoint.Value);
|
||||
_lagLog.FromLagLog(branch.LagLog); // don't truncate LagLog if the branch's one is shorter, but input is the same
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -530,8 +530,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
_stateManager.LoadBranch(Branches.IndexOf(branch));
|
||||
_stateManager.SetState(branch.Frame, branch.CoreData);
|
||||
|
||||
////ChangeLog = branch.ChangeLog;
|
||||
|
||||
if (BindMarkersToInput) // pretty critical not to erase them
|
||||
{
|
||||
Markers = branch.Markers;
|
||||
|
|
|
@ -284,29 +284,61 @@ namespace BizHawk.Client.Common
|
|||
case WatchSize.Byte:
|
||||
return (byte?)_val;
|
||||
case WatchSize.Word:
|
||||
if (addr == _watch.Address)
|
||||
if (_watch.BigEndian)
|
||||
{
|
||||
if (addr == _watch.Address)
|
||||
{
|
||||
return (byte)(_val & 0xFF);
|
||||
}
|
||||
return (byte)(_val >> 8);
|
||||
}
|
||||
|
||||
return (byte)(_val & 0xFF);
|
||||
case WatchSize.DWord:
|
||||
if (addr == _watch.Address)
|
||||
else
|
||||
{
|
||||
if (addr == _watch.Address)
|
||||
{
|
||||
return (byte)(_val >> 8);
|
||||
}
|
||||
return (byte)(_val & 0xFF);
|
||||
}
|
||||
case WatchSize.DWord:
|
||||
if (_watch.BigEndian)
|
||||
{
|
||||
if (addr == _watch.Address)
|
||||
{
|
||||
return (byte)((_val >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
if (addr == _watch.Address + 1)
|
||||
{
|
||||
return (byte)((_val >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
if (addr == _watch.Address + 2)
|
||||
{
|
||||
return (byte)((_val >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
return (byte)(_val & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addr == _watch.Address)
|
||||
{
|
||||
return (byte)(_val & 0xFF);
|
||||
}
|
||||
|
||||
if (addr == _watch.Address + 1)
|
||||
{
|
||||
return (byte)((_val >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
if (addr == _watch.Address + 2)
|
||||
{
|
||||
return (byte)((_val >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
return (byte)((_val >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
if (addr == _watch.Address + 1)
|
||||
{
|
||||
return (byte)((_val >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
if (addr == _watch.Address + 2)
|
||||
{
|
||||
return (byte)((_val >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
return (byte)(_val & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace BizHawk.Client.DiscoHawk
|
|||
foreach (string str in files)
|
||||
{
|
||||
string ext = Path.GetExtension(str).ToUpper();
|
||||
if(!ext.In(new string[]{".CUE",".ISO",".CCD"}))
|
||||
if(!ext.In(new string[]{".CUE",".ISO",".CCD", ".MDS"}))
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
cmdRom = arg;
|
||||
cmdRom = args[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -822,6 +822,12 @@
|
|||
<Compile Include="tools\GB\GBGPUView.Designer.cs">
|
||||
<DependentUpon>GBGPUView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="tools\GB\GBPrinterView.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="tools\GB\GBPrinterView.Designer.cs">
|
||||
<DependentUpon>GBPrinterView.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="tools\Genesis\GenDbgWind.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -1167,7 +1173,6 @@
|
|||
</Compile>
|
||||
<Compile Include="tools\VirtualPads\schema\A26Schema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\A78Schema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\A7800HawkSchema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\AppleIISchema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\C64Schema.cs" />
|
||||
<Compile Include="tools\VirtualPads\schema\ColecoSchema.cs" />
|
||||
|
@ -1317,7 +1322,7 @@
|
|||
<EmbeddedResource Include="config\A7800\A7800ControllerSettings.resx">
|
||||
<DependentUpon>A7800ControllerSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="config\A7800\A7800FilterSettings.resx">
|
||||
<EmbeddedResource Include="config\A7800\A7800FilterSettings.resx">
|
||||
<DependentUpon>A7800FilterSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="config\INTV\IntvControllerSettings.resx">
|
||||
|
@ -1490,6 +1495,9 @@
|
|||
<EmbeddedResource Include="tools\GB\GBGPUView.resx">
|
||||
<DependentUpon>GBGPUView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="tools\GB\GBPrinterView.resx">
|
||||
<DependentUpon>GBPrinterView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="tools\Genesis\GenDbgWind.resx">
|
||||
<DependentUpon>GenDbgWind.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
@ -2085,7 +2093,6 @@
|
|||
<None Include="images\checkbox.png" />
|
||||
<None Include="images\Erase.png" />
|
||||
<None Include="images\bsnes.png" />
|
||||
<None Include="images\emu7800.png" />
|
||||
<None Include="images\genplus.png" />
|
||||
<None Include="images\gambatte.png" />
|
||||
<None Include="images\dual.png" />
|
||||
|
|
|
@ -586,6 +586,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
};
|
||||
var filterProgram = UpdateSourceInternal(job);
|
||||
|
||||
//this only happens when we're forcing the client to size itself with autoload and the core says 0x0....
|
||||
//we need some other more sensible client size.
|
||||
if (filterProgram == null)
|
||||
{
|
||||
return new Size(256, 192);
|
||||
}
|
||||
|
||||
var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size;
|
||||
|
||||
return size;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
|
||||
using BizHawk.Emulation.Cores.Atari.Atari7800;
|
||||
using BizHawk.Emulation.Cores.Nintendo.GBA;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
|
@ -36,10 +35,6 @@ namespace BizHawk.Client.EmuHawk.CoreExtensions
|
|||
{
|
||||
return Properties.Resources.bsnes;
|
||||
}
|
||||
else if (core is Atari7800)
|
||||
{
|
||||
return Properties.Resources.emu7800;
|
||||
}
|
||||
else if (core is GPGX)
|
||||
{
|
||||
return Properties.Resources.genplus;
|
||||
|
|
|
@ -51,11 +51,11 @@ 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"
|
||||
".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS"
|
||||
};
|
||||
}
|
||||
|
||||
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", ".32X" };
|
||||
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", ".32X", ".MDS" };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,8 +192,6 @@
|
|||
this.GbaCoreSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.VbaNextCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MgbaCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.Atari7800CoreSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.Emu7800CoreMenuItem = 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();
|
||||
|
@ -238,8 +236,9 @@
|
|||
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.NESPPUViewerMenuItem = 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.NESNametableViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.NESGameGenieCodesMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.musicRipperToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -307,7 +306,8 @@
|
|||
this.LoadGBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator28 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.GBGPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGameGenieMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBPrinterViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.GBGameGenieMenuItem = 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();
|
||||
|
@ -329,7 +329,6 @@
|
|||
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.N64SubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.N64PluginSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -443,7 +442,12 @@
|
|||
this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.timerMouseIdle = new System.Windows.Forms.Timer(this.components);
|
||||
this.MainformMenu.SuspendLayout();
|
||||
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.MainformMenu.SuspendLayout();
|
||||
this.MainStatusBar.SuspendLayout();
|
||||
this.MainFormContextMenu.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
|
@ -902,26 +906,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.FlushSaveRAMSubMenu_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
|
||||
|
@ -1805,7 +1809,6 @@
|
|||
this.NesCoreSubMenu,
|
||||
this.CoreSNESSubMenu,
|
||||
this.GbaCoreSubMenu,
|
||||
this.Atari7800CoreSubMenu,
|
||||
this.SGBCoreSubmenu,
|
||||
this.GBInSGBMenuItem,
|
||||
this.toolStripMenuItem16,
|
||||
|
@ -1890,29 +1893,11 @@
|
|||
this.MgbaCoreMenuItem.Text = "mGBA";
|
||||
this.MgbaCoreMenuItem.Click += new System.EventHandler(this.GbaCorePick_Click);
|
||||
//
|
||||
// Atari7800CoreSubMenu
|
||||
//
|
||||
this.Atari7800CoreSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.Emu7800CoreMenuItem,
|
||||
this.Atari7800HawkCoreMenuItem});
|
||||
this.Atari7800CoreSubMenu.Name = "Atari7800CoreSubMenu";
|
||||
this.Atari7800CoreSubMenu.Size = new System.Drawing.Size(239, 22);
|
||||
this.Atari7800CoreSubMenu.Text = "Atari 7800";
|
||||
this.Atari7800CoreSubMenu.DropDownOpened += new System.EventHandler(this.Atari7800CoreSubMenu_DropDownOpened);
|
||||
//
|
||||
// Emu7800CoreMenuItem
|
||||
//
|
||||
this.Emu7800CoreMenuItem.Name = "Emu7800CoreMenuItem";
|
||||
this.Emu7800CoreMenuItem.Size = new System.Drawing.Size(153, 22);
|
||||
this.Emu7800CoreMenuItem.Text = "EMU7800";
|
||||
this.Emu7800CoreMenuItem.Click += new System.EventHandler(this.Atari7800CorePick_Click);
|
||||
//
|
||||
// Atari7800HawkCoreMenuItem
|
||||
//
|
||||
this.Atari7800HawkCoreMenuItem.Name = "Atari7800HawkCoreMenuItem";
|
||||
this.Atari7800HawkCoreMenuItem.Size = new System.Drawing.Size(153, 22);
|
||||
this.Atari7800HawkCoreMenuItem.Text = "Atari7800Hawk";
|
||||
this.Atari7800HawkCoreMenuItem.Click += new System.EventHandler(this.Atari7800CorePick_Click);
|
||||
//
|
||||
// SGBCoreSubmenu
|
||||
//
|
||||
|
@ -2495,7 +2480,8 @@
|
|||
this.SMSSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.SMSregionToolStripMenuItem,
|
||||
this.SMSdisplayToolStripMenuItem,
|
||||
this.SMStoolStripMenuItem2,
|
||||
this.SMSControllerToolStripMenuItem,
|
||||
this.SMStoolStripMenuItem2,
|
||||
this.SMSenableBIOSToolStripMenuItem,
|
||||
this.SMSEnableFMChipMenuItem,
|
||||
this.SMSOverclockMenuItem,
|
||||
|
@ -2562,9 +2548,44 @@
|
|||
this.SMSdisplayNtscToolStripMenuItem.Text = "NTSC";
|
||||
this.SMSdisplayNtscToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayNTSC_Click);
|
||||
//
|
||||
// SMSdisplayPalToolStripMenuItem
|
||||
// SMSControllerToolStripMenuItem
|
||||
//
|
||||
this.SMSdisplayPalToolStripMenuItem.Name = "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});
|
||||
//
|
||||
// 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);
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
@ -2765,7 +2786,8 @@
|
|||
this.LoadGBInSGBMenuItem,
|
||||
this.toolStripSeparator28,
|
||||
this.GBGPUViewerMenuItem,
|
||||
this.GBGameGenieMenuItem});
|
||||
this.GBGameGenieMenuItem,
|
||||
this.GBPrinterViewerMenuItem});
|
||||
this.GBSubMenu.Name = "GBSubMenu";
|
||||
this.GBSubMenu.Size = new System.Drawing.Size(34, 19);
|
||||
this.GBSubMenu.Text = "&GB";
|
||||
|
@ -2803,10 +2825,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);
|
||||
//
|
||||
// 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,
|
||||
|
@ -4176,6 +4205,7 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem SaveMovieContextMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem VirtualPadMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBGPUViewerMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBPrinterViewerMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem AudioThrottleMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator27;
|
||||
private System.Windows.Forms.ToolStripMenuItem VsyncEnabledMenuItem;
|
||||
|
@ -4309,6 +4339,7 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem quickNESToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem nesHawkToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator34;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator35;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBACoreSelectionSubMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBAmGBAMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBAVBANextMenuItem;
|
||||
|
@ -4358,7 +4389,6 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem IntvSubMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem IntVControllerSettingsMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SNESControllerConfigurationMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator35;
|
||||
private System.Windows.Forms.ToolStripMenuItem C64DisksSubMenu;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator36;
|
||||
private System.Windows.Forms.ToolStripMenuItem sNESToolStripMenuItem;
|
||||
|
@ -4373,13 +4403,16 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem GbaCoreSubMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem VbaNextCoreMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem MgbaCoreMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem Atari7800CoreSubMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem Emu7800CoreMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem Atari7800HawkCoreMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SGBCoreSubmenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem SgbBsnesMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SgbSameBoyMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem pCFXToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem preferencesToolStripMenuItem3;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerStandardToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerPaddleToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem SMSControllerSportsPadToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ using System.Windows.Forms;
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
using BizHawk.Emulation.Cores.Atari.A7800Hawk;
|
||||
using BizHawk.Emulation.Cores.Atari.Atari7800;
|
||||
using BizHawk.Emulation.Cores.Calculators;
|
||||
using BizHawk.Emulation.Cores.ColecoVision;
|
||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||
|
@ -226,9 +225,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
private void FlushSaveRAMSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
private void SaveRAMSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
FlushSaveRAMMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Flush SRAM"].Bindings;
|
||||
FlushSaveRAMMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Flush SaveRAM"].Bindings;
|
||||
}
|
||||
|
||||
private void MovieSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
|
@ -1187,7 +1186,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void CoresSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
Atari7800CoreSubMenu.Visible = VersionInfo.DeveloperBuild;
|
||||
GBInSGBMenuItem.Checked = Global.Config.GB_AsSGB;
|
||||
|
||||
allowGameDBCoreOverridesToolStripMenuItem.Checked = Global.Config.CoreForcingViaGameDB;
|
||||
|
@ -1240,21 +1238,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
private void Atari7800CoreSubMenu_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
Emu7800CoreMenuItem.Checked = Global.Config.A78_UseEmu7800;
|
||||
Atari7800HawkCoreMenuItem.Checked = !Global.Config.A78_UseEmu7800;
|
||||
}
|
||||
|
||||
private void Atari7800CorePick_Click(object sender, EventArgs e)
|
||||
{
|
||||
Global.Config.A78_UseEmu7800 ^= true;
|
||||
if (Emulator.SystemId == "A78")
|
||||
{
|
||||
FlagNeedsReboot();
|
||||
}
|
||||
}
|
||||
|
||||
private void SGBCoreSubmenu_DropDownOpened(object sender, EventArgs e)
|
||||
{
|
||||
SgbBsnesMenuItem.Checked = Global.Config.SGB_UseBsnes;
|
||||
|
@ -1762,6 +1745,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
SMSdisplayNtscToolStripMenuItem.Checked = ss.DisplayType == "NTSC";
|
||||
SMSdisplayPalToolStripMenuItem.Checked = ss.DisplayType == "PAL";
|
||||
SMSdisplayAutoToolStripMenuItem.Checked = ss.DisplayType == "Auto";
|
||||
SMSControllerStandardToolStripMenuItem.Checked = ss.ControllerType == "Standard";
|
||||
SMSControllerPaddleToolStripMenuItem.Checked = ss.ControllerType == "Paddle";
|
||||
SMSControllerLightPhaserToolStripMenuItem.Checked = ss.ControllerType == "Light Phaser";
|
||||
SMSControllerSportsPadToolStripMenuItem.Checked = ss.ControllerType == "Sports Pad";
|
||||
SMSenableBIOSToolStripMenuItem.Checked = ss.UseBIOS;
|
||||
SMSEnableFMChipMenuItem.Checked = ss.EnableFM;
|
||||
SMSOverclockMenuItem.Checked = ss.AllowOverlock;
|
||||
|
@ -1775,9 +1762,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
SMSEnableFMChipMenuItem.Visible =
|
||||
SMSFix3DGameDisplayToolStripMenuItem.Visible =
|
||||
SMSenableBIOSToolStripMenuItem.Visible =
|
||||
SMSDisplayOverscanMenuItem.Visible =
|
||||
Global.Game.System == "SMS";
|
||||
|
||||
SMSDisplayOverscanMenuItem.Visible =
|
||||
Global.Game.System == "SMS" || Global.Game.System == "SG";
|
||||
|
||||
SMSOverclockMenuItem.Visible =
|
||||
SMSForceStereoMenuItem.Visible =
|
||||
SMSdisplayToolStripMenuItem.Visible =
|
||||
|
@ -1914,6 +1903,34 @@ namespace BizHawk.Client.EmuHawk
|
|||
GlobalWin.Tools.Load<SmsVDPViewer>();
|
||||
}
|
||||
|
||||
private void SMSControllerStandardToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var s = ((SMS)Emulator).GetSyncSettings();
|
||||
s.ControllerType = "Standard";
|
||||
PutCoreSyncSettings(s);
|
||||
}
|
||||
|
||||
private void SMSControllerPaddleToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var s = ((SMS)Emulator).GetSyncSettings();
|
||||
s.ControllerType = "Paddle";
|
||||
PutCoreSyncSettings(s);
|
||||
}
|
||||
|
||||
private void SMSControllerLightPhaserToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var s = ((SMS)Emulator).GetSyncSettings();
|
||||
s.ControllerType = "Light Phaser";
|
||||
PutCoreSyncSettings(s);
|
||||
}
|
||||
|
||||
private void SMSControllerSportsPadToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var s = ((SMS)Emulator).GetSyncSettings();
|
||||
s.ControllerType = "Sports Pad";
|
||||
PutCoreSyncSettings(s);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TI83
|
||||
|
@ -2033,6 +2050,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
GlobalWin.Tools.LoadGameGenieEc();
|
||||
}
|
||||
|
||||
private void GBPrinterViewerMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
GlobalWin.Tools.Load<GBPrinterView>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GBA
|
||||
|
|
|
@ -34,6 +34,7 @@ using BizHawk.Emulation.Cores.Nintendo.SNES9X;
|
|||
using BizHawk.Emulation.Cores.Consoles.SNK;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Cores.Atari.A7800Hawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -273,7 +274,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (argParse.cmdRom != null)
|
||||
{
|
||||
// Commandline should always override auto-load
|
||||
LoadRom(argParse.cmdRom, new LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom() });
|
||||
var ioa = OpenAdvancedSerializer.ParseWithLegacy(argParse.cmdRom);
|
||||
LoadRom(argParse.cmdRom, new LoadRomArgs { OpenAdvanced = ioa });
|
||||
if (Global.Game == null)
|
||||
{
|
||||
MessageBox.Show("Failed to load " + argParse.cmdRom + " specified on commandline");
|
||||
|
@ -404,7 +406,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
PauseEmulator();
|
||||
}
|
||||
|
||||
|
||||
// start dumping, if appropriate
|
||||
if (argParse.cmdDumpType != null && argParse.cmdDumpName != null)
|
||||
{
|
||||
|
@ -1414,6 +1416,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public PresentationPanel PresentationPanel { get; }
|
||||
|
||||
//countdown for saveram autoflushing
|
||||
public int AutoFlushSaveRamIn { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
@ -1566,6 +1570,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
try // zero says: this is sort of sketchy... but this is no time for rearchitecting
|
||||
{
|
||||
if (Global.Config.AutosaveSaveRAM)
|
||||
{
|
||||
var saveram = new FileInfo(PathManager.SaveRamPath(Global.Game));
|
||||
var autosave = new FileInfo(PathManager.AutoSaveRamPath(Global.Game));
|
||||
if (autosave.Exists && autosave.LastWriteTime > saveram.LastWriteTime)
|
||||
{
|
||||
GlobalWin.OSD.AddMessage("AutoSaveRAM is newer than last saved SaveRAM");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] sram;
|
||||
|
||||
// GBA meteor core might not know how big the saveram ought to be, so just send it the whole file
|
||||
|
@ -1595,47 +1609,66 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
Emulator.AsSaveRam().StoreSaveRam(sram);
|
||||
AutoFlushSaveRamIn = Global.Config.FlushSaveRamFrames;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
GlobalWin.OSD.AddMessage("An error occurred while loading Sram");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FlushSaveRAM()
|
||||
public void FlushSaveRAM(bool autosave = false)
|
||||
{
|
||||
if (Emulator.HasSaveRam())
|
||||
{
|
||||
var path = PathManager.SaveRamPath(Global.Game);
|
||||
var f = new FileInfo(path);
|
||||
if (f.Directory != null && !f.Directory.Exists)
|
||||
string path;
|
||||
if (autosave)
|
||||
{
|
||||
f.Directory.Create();
|
||||
path = PathManager.AutoSaveRamPath(Global.Game);
|
||||
AutoFlushSaveRamIn = Global.Config.FlushSaveRamFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = PathManager.SaveRamPath(Global.Game);
|
||||
}
|
||||
var file = new FileInfo(path);
|
||||
var newPath = path + ".new";
|
||||
var newFile = new FileInfo(newPath);
|
||||
var backupPath = path + ".bak";
|
||||
var backupFile = new FileInfo(backupPath);
|
||||
if (file.Directory != null && !file.Directory.Exists)
|
||||
{
|
||||
file.Directory.Create();
|
||||
}
|
||||
|
||||
// Make backup first
|
||||
if (Global.Config.BackupSaveram && f.Exists)
|
||||
{
|
||||
var backup = path + ".bak";
|
||||
var backupFile = new FileInfo(backup);
|
||||
if (backupFile.Exists)
|
||||
{
|
||||
backupFile.Delete();
|
||||
}
|
||||
|
||||
f.CopyTo(backup);
|
||||
}
|
||||
|
||||
var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write));
|
||||
var writer = new BinaryWriter(new FileStream(newPath, FileMode.Create, FileAccess.Write));
|
||||
var saveram = Emulator.AsSaveRam().CloneSaveRam();
|
||||
|
||||
if (saveram != null)
|
||||
{
|
||||
writer.Write(saveram, 0, saveram.Length);
|
||||
}
|
||||
|
||||
writer.Close();
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
if (Global.Config.BackupSaveram)
|
||||
{
|
||||
if (backupFile.Exists)
|
||||
{
|
||||
backupFile.Delete();
|
||||
}
|
||||
|
||||
file.MoveTo(backupPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
newFile.MoveTo(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1725,8 +1758,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
case "A26":
|
||||
AtariSubMenu.Visible = true;
|
||||
break;
|
||||
case "A7800":
|
||||
A7800SubMenu.Visible = true;
|
||||
case "A78":
|
||||
if (Emulator is A7800Hawk)
|
||||
{
|
||||
A7800SubMenu.Visible = true;
|
||||
}
|
||||
break;
|
||||
case "PSX":
|
||||
PSXSubMenu.Visible = true;
|
||||
|
@ -2041,13 +2077,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (VersionInfo.DeveloperBuild)
|
||||
{
|
||||
return FormatFilter(
|
||||
"Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.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;%ARCH%",
|
||||
"Music Files", "*.psf;*.minipsf;*.sid;*.nsf",
|
||||
"Disc Images", "*.cue;*.ccd;*.m3u",
|
||||
"Disc Images", "*.cue;*.ccd;*.mds;*.m3u",
|
||||
"NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%",
|
||||
"Super NES", "*.smc;*.sfc;*.xml;%ARCH%",
|
||||
"Master System", "*.sms;*.gg;*.sg;%ARCH%",
|
||||
"PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%",
|
||||
"PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%",
|
||||
"TI-83", "*.rom;%ARCH%",
|
||||
"Archive Files", "%ARCH%",
|
||||
"Savestate", "*.state",
|
||||
|
@ -2059,7 +2095,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
"Gameboy Advance", "*.gba;%ARCH%",
|
||||
"Colecovision", "*.col;%ARCH%",
|
||||
"Intellivision", "*.int;*.bin;*.rom;%ARCH%",
|
||||
"PlayStation", "*.cue;*.ccd;*.m3u",
|
||||
"PlayStation", "*.cue;*.ccd;*.mds;*.m3u",
|
||||
"PSX Executables (experimental)", "*.exe",
|
||||
"PSF Playstation Sound File", "*.psf;*.minipsf",
|
||||
"Commodore 64", "*.prg; *.d64, *.g64; *.crt; *.tap;%ARCH%",
|
||||
|
@ -2073,17 +2109,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
return FormatFilter(
|
||||
"Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;%ARCH%",
|
||||
"Disc Images", "*.cue;*.ccd;*.m3u",
|
||||
"Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.mds;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;%ARCH%",
|
||||
"Disc Images", "*.cue;*.ccd;*.mds;*.m3u",
|
||||
"NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%",
|
||||
"Super NES", "*.smc;*.sfc;*.xml;%ARCH%",
|
||||
"PlayStation", "*.cue;*.ccd;*.m3u",
|
||||
"PlayStation", "*.cue;*.ccd;*.mds;*.m3u",
|
||||
"PSF Playstation Sound File", "*.psf;*.minipsf",
|
||||
"Nintendo 64", "*.z64;*.v64;*.n64",
|
||||
"Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%",
|
||||
"Gameboy Advance", "*.gba;%ARCH%",
|
||||
"Master System", "*.sms;*.gg;*.sg;%ARCH%",
|
||||
"PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%",
|
||||
"PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%",
|
||||
"Atari 2600", "*.a26;%ARCH%",
|
||||
"Atari 7800", "*.a78;%ARCH%",
|
||||
"Atari Lynx", "*.lnx;%ARCH%",
|
||||
|
@ -2902,6 +2938,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
Global.MovieSession.HandleMovieOnFrameLoop();
|
||||
|
||||
if (Global.Config.AutosaveSaveRAM)
|
||||
{
|
||||
if (AutoFlushSaveRamIn-- <= 0)
|
||||
{
|
||||
FlushSaveRAM(true);
|
||||
}
|
||||
}
|
||||
// why not skip audio if the user doesnt want sound
|
||||
bool renderSound = (Global.Config.SoundEnabled && !IsTurboing) || (_currAviWriter?.UsesAudio ?? false);
|
||||
if (!renderSound)
|
||||
|
@ -3540,6 +3583,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (ioa is OpenAdvanced_OpenRom)
|
||||
{
|
||||
var ioa_openrom = (OpenAdvanced_OpenRom)ioa;
|
||||
path = ioa_openrom.Path;
|
||||
}
|
||||
|
||||
CoreFileProvider.SyncCoreCommInputSignals(nextComm);
|
||||
var result = loader.LoadRom(path, nextComm);
|
||||
|
||||
|
@ -3616,9 +3665,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
JumpLists.AddRecentItem(loaderName, ioa.DisplayName);
|
||||
|
||||
// Don't load Save Ram if a movie is being loaded
|
||||
if (!Global.MovieSession.MovieIsQueued && File.Exists(PathManager.SaveRamPath(loader.Game)))
|
||||
if (!Global.MovieSession.MovieIsQueued)
|
||||
{
|
||||
LoadSaveRam();
|
||||
if (File.Exists(PathManager.SaveRamPath(loader.Game)))
|
||||
{
|
||||
LoadSaveRam();
|
||||
}
|
||||
else if (Global.Config.AutosaveSaveRAM && File.Exists(PathManager.AutoSaveRamPath(loader.Game)))
|
||||
{
|
||||
GlobalWin.OSD.AddMessage("AutoSaveRAM found, but SaveRAM was not saved");
|
||||
}
|
||||
}
|
||||
|
||||
GlobalWin.Tools.Restart();
|
||||
|
|
|
@ -489,17 +489,7 @@ 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 emu7800 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("emu7800", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
|
|
|
@ -205,9 +205,6 @@
|
|||
<data name="calculator" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\images\calculator.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="emu7800" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\images\emu7800.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ts_v_piano_16_green_blue" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\images\tastudio\ts_v_piano_16_green_blue.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
|
@ -1560,4 +1557,4 @@
|
|||
<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>
|
||||
</root>
|
||||
|
|
|
@ -48,6 +48,17 @@
|
|||
this.EnableContextMenuCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.PauseWhenMenuActivatedCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.tabPage3 = new System.Windows.Forms.TabPage();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.AutosaveSRAMtextBox = new System.Windows.Forms.NumericUpDown();
|
||||
this.AutosaveSRAMradioButton1 = new System.Windows.Forms.RadioButton();
|
||||
this.label8 = new System.Windows.Forms.Label();
|
||||
this.AutosaveSRAMradioButton2 = new System.Windows.Forms.RadioButton();
|
||||
this.AutosaveSRAMradioButton3 = new System.Windows.Forms.RadioButton();
|
||||
this.AutosaveSRAMCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.LuaInterfaceRadio = new System.Windows.Forms.RadioButton();
|
||||
this.NLuaRadio = new System.Windows.Forms.RadioButton();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.cbMoviesInAWE = new System.Windows.Forms.CheckBox();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
|
@ -56,20 +67,18 @@
|
|||
this.label12 = new System.Windows.Forms.Label();
|
||||
this.label13 = new System.Windows.Forms.Label();
|
||||
this.FrameAdvSkipLagCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.label9 = new System.Windows.Forms.Label();
|
||||
this.label10 = new System.Windows.Forms.Label();
|
||||
this.BackupSRamCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.LogWindowAsConsoleCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.NLuaRadio = new System.Windows.Forms.RadioButton();
|
||||
this.LuaInterfaceRadio = new System.Windows.Forms.RadioButton();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.label9 = new System.Windows.Forms.Label();
|
||||
this.label10 = new System.Windows.Forms.Label();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.tabPage3.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.AutosaveSRAMtextBox)).BeginInit();
|
||||
this.panel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
|
@ -123,7 +132,7 @@
|
|||
this.tabPage1.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(386, 368);
|
||||
this.tabPage1.Size = new System.Drawing.Size(386, 376);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "General";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
|
@ -270,6 +279,8 @@
|
|||
//
|
||||
// tabPage3
|
||||
//
|
||||
this.tabPage3.Controls.Add(this.groupBox2);
|
||||
this.tabPage3.Controls.Add(this.AutosaveSRAMCheckbox);
|
||||
this.tabPage3.Controls.Add(this.panel1);
|
||||
this.tabPage3.Controls.Add(this.label6);
|
||||
this.tabPage3.Controls.Add(this.cbMoviesInAWE);
|
||||
|
@ -279,8 +290,6 @@
|
|||
this.tabPage3.Controls.Add(this.label12);
|
||||
this.tabPage3.Controls.Add(this.label13);
|
||||
this.tabPage3.Controls.Add(this.FrameAdvSkipLagCheckbox);
|
||||
this.tabPage3.Controls.Add(this.label9);
|
||||
this.tabPage3.Controls.Add(this.label10);
|
||||
this.tabPage3.Controls.Add(this.BackupSRamCheckbox);
|
||||
this.tabPage3.Controls.Add(this.label4);
|
||||
this.tabPage3.Controls.Add(this.LogWindowAsConsoleCheckbox);
|
||||
|
@ -291,6 +300,128 @@
|
|||
this.tabPage3.Text = "Advanced";
|
||||
this.tabPage3.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.label10);
|
||||
this.groupBox2.Controls.Add(this.label9);
|
||||
this.groupBox2.Controls.Add(this.AutosaveSRAMtextBox);
|
||||
this.groupBox2.Controls.Add(this.AutosaveSRAMradioButton1);
|
||||
this.groupBox2.Controls.Add(this.label8);
|
||||
this.groupBox2.Controls.Add(this.AutosaveSRAMradioButton2);
|
||||
this.groupBox2.Controls.Add(this.AutosaveSRAMradioButton3);
|
||||
this.groupBox2.Location = new System.Drawing.Point(27, 59);
|
||||
this.groupBox2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(265, 60);
|
||||
this.groupBox2.TabIndex = 27;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "AutoSaveRAM";
|
||||
//
|
||||
// AutosaveSRAMtextBox
|
||||
//
|
||||
this.AutosaveSRAMtextBox.Location = new System.Drawing.Point(151, 33);
|
||||
this.AutosaveSRAMtextBox.Maximum = new decimal(new int[] {
|
||||
100000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.AutosaveSRAMtextBox.Name = "AutosaveSRAMtextBox";
|
||||
this.AutosaveSRAMtextBox.Size = new System.Drawing.Size(50, 20);
|
||||
this.AutosaveSRAMtextBox.TabIndex = 27;
|
||||
//
|
||||
// AutosaveSRAMradioButton1
|
||||
//
|
||||
this.AutosaveSRAMradioButton1.AutoSize = true;
|
||||
this.AutosaveSRAMradioButton1.Location = new System.Drawing.Point(48, 33);
|
||||
this.AutosaveSRAMradioButton1.Name = "AutosaveSRAMradioButton1";
|
||||
this.AutosaveSRAMradioButton1.Size = new System.Drawing.Size(36, 17);
|
||||
this.AutosaveSRAMradioButton1.TabIndex = 22;
|
||||
this.AutosaveSRAMradioButton1.TabStop = true;
|
||||
this.AutosaveSRAMradioButton1.Text = "5s";
|
||||
this.AutosaveSRAMradioButton1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label8
|
||||
//
|
||||
this.label8.AutoSize = true;
|
||||
this.label8.Location = new System.Drawing.Point(202, 35);
|
||||
this.label8.Name = "label8";
|
||||
this.label8.Size = new System.Drawing.Size(12, 13);
|
||||
this.label8.TabIndex = 26;
|
||||
this.label8.Text = "s";
|
||||
//
|
||||
// AutosaveSRAMradioButton2
|
||||
//
|
||||
this.AutosaveSRAMradioButton2.AutoSize = true;
|
||||
this.AutosaveSRAMradioButton2.Location = new System.Drawing.Point(90, 34);
|
||||
this.AutosaveSRAMradioButton2.Name = "AutosaveSRAMradioButton2";
|
||||
this.AutosaveSRAMradioButton2.Size = new System.Drawing.Size(39, 17);
|
||||
this.AutosaveSRAMradioButton2.TabIndex = 23;
|
||||
this.AutosaveSRAMradioButton2.TabStop = true;
|
||||
this.AutosaveSRAMradioButton2.Text = "5m";
|
||||
this.AutosaveSRAMradioButton2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// AutosaveSRAMradioButton3
|
||||
//
|
||||
this.AutosaveSRAMradioButton3.AutoSize = true;
|
||||
this.AutosaveSRAMradioButton3.Location = new System.Drawing.Point(131, 35);
|
||||
this.AutosaveSRAMradioButton3.Name = "AutosaveSRAMradioButton3";
|
||||
this.AutosaveSRAMradioButton3.Size = new System.Drawing.Size(14, 13);
|
||||
this.AutosaveSRAMradioButton3.TabIndex = 24;
|
||||
this.AutosaveSRAMradioButton3.TabStop = true;
|
||||
this.AutosaveSRAMradioButton3.UseVisualStyleBackColor = true;
|
||||
this.AutosaveSRAMradioButton3.CheckedChanged += new System.EventHandler(this.AutosaveSRAMradioButton3_CheckedChanged);
|
||||
//
|
||||
// AutosaveSRAMCheckbox
|
||||
//
|
||||
this.AutosaveSRAMCheckbox.AutoSize = true;
|
||||
this.AutosaveSRAMCheckbox.Location = new System.Drawing.Point(6, 62);
|
||||
this.AutosaveSRAMCheckbox.Name = "AutosaveSRAMCheckbox";
|
||||
this.AutosaveSRAMCheckbox.Size = new System.Drawing.Size(15, 14);
|
||||
this.AutosaveSRAMCheckbox.TabIndex = 21;
|
||||
this.AutosaveSRAMCheckbox.UseVisualStyleBackColor = true;
|
||||
this.AutosaveSRAMCheckbox.CheckedChanged += new System.EventHandler(this.AutosaveSRAMCheckbox_CheckedChanged);
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.Controls.Add(this.label7);
|
||||
this.panel1.Controls.Add(this.LuaInterfaceRadio);
|
||||
this.panel1.Controls.Add(this.NLuaRadio);
|
||||
this.panel1.Location = new System.Drawing.Point(6, 312);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(377, 61);
|
||||
this.panel1.TabIndex = 20;
|
||||
//
|
||||
// label7
|
||||
//
|
||||
this.label7.AutoSize = true;
|
||||
this.label7.Location = new System.Drawing.Point(3, 1);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(50, 13);
|
||||
this.label7.TabIndex = 2;
|
||||
this.label7.Text = "Lua Core";
|
||||
//
|
||||
// LuaInterfaceRadio
|
||||
//
|
||||
this.LuaInterfaceRadio.AutoSize = true;
|
||||
this.LuaInterfaceRadio.Location = new System.Drawing.Point(4, 36);
|
||||
this.LuaInterfaceRadio.Name = "LuaInterfaceRadio";
|
||||
this.LuaInterfaceRadio.Size = new System.Drawing.Size(338, 17);
|
||||
this.LuaInterfaceRadio.TabIndex = 1;
|
||||
this.LuaInterfaceRadio.TabStop = true;
|
||||
this.LuaInterfaceRadio.Text = "Lua+LuaInterface - Faster but memory leaks, use at your own risk!";
|
||||
this.LuaInterfaceRadio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// NLuaRadio
|
||||
//
|
||||
this.NLuaRadio.AutoSize = true;
|
||||
this.NLuaRadio.Location = new System.Drawing.Point(4, 17);
|
||||
this.NLuaRadio.Name = "NLuaRadio";
|
||||
this.NLuaRadio.Size = new System.Drawing.Size(194, 17);
|
||||
this.NLuaRadio.TabIndex = 0;
|
||||
this.NLuaRadio.TabStop = true;
|
||||
this.NLuaRadio.Text = "NLua+KopiLua - Reliable but slower";
|
||||
this.NLuaRadio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
|
@ -335,7 +466,7 @@
|
|||
// LuaDuringTurboCheckbox
|
||||
//
|
||||
this.LuaDuringTurboCheckbox.AutoSize = true;
|
||||
this.LuaDuringTurboCheckbox.Location = new System.Drawing.Point(6, 174);
|
||||
this.LuaDuringTurboCheckbox.Location = new System.Drawing.Point(6, 178);
|
||||
this.LuaDuringTurboCheckbox.Name = "LuaDuringTurboCheckbox";
|
||||
this.LuaDuringTurboCheckbox.Size = new System.Drawing.Size(166, 17);
|
||||
this.LuaDuringTurboCheckbox.TabIndex = 15;
|
||||
|
@ -345,7 +476,7 @@
|
|||
// label12
|
||||
//
|
||||
this.label12.AutoSize = true;
|
||||
this.label12.Location = new System.Drawing.Point(24, 149);
|
||||
this.label12.Location = new System.Drawing.Point(24, 162);
|
||||
this.label12.Name = "label12";
|
||||
this.label12.Size = new System.Drawing.Size(231, 13);
|
||||
this.label12.TabIndex = 14;
|
||||
|
@ -354,7 +485,7 @@
|
|||
// label13
|
||||
//
|
||||
this.label13.AutoSize = true;
|
||||
this.label13.Location = new System.Drawing.Point(24, 136);
|
||||
this.label13.Location = new System.Drawing.Point(24, 149);
|
||||
this.label13.Name = "label13";
|
||||
this.label13.Size = new System.Drawing.Size(268, 13);
|
||||
this.label13.TabIndex = 13;
|
||||
|
@ -363,45 +494,27 @@
|
|||
// FrameAdvSkipLagCheckbox
|
||||
//
|
||||
this.FrameAdvSkipLagCheckbox.AutoSize = true;
|
||||
this.FrameAdvSkipLagCheckbox.Location = new System.Drawing.Point(6, 116);
|
||||
this.FrameAdvSkipLagCheckbox.Location = new System.Drawing.Point(6, 129);
|
||||
this.FrameAdvSkipLagCheckbox.Name = "FrameAdvSkipLagCheckbox";
|
||||
this.FrameAdvSkipLagCheckbox.Size = new System.Drawing.Size(241, 17);
|
||||
this.FrameAdvSkipLagCheckbox.TabIndex = 12;
|
||||
this.FrameAdvSkipLagCheckbox.Text = "Frame advance button skips non-input frames";
|
||||
this.FrameAdvSkipLagCheckbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label9
|
||||
//
|
||||
this.label9.AutoSize = true;
|
||||
this.label9.Location = new System.Drawing.Point(24, 94);
|
||||
this.label9.Name = "label9";
|
||||
this.label9.Size = new System.Drawing.Size(99, 13);
|
||||
this.label9.TabIndex = 11;
|
||||
this.label9.Text = "before overwriting it";
|
||||
//
|
||||
// label10
|
||||
//
|
||||
this.label10.AutoSize = true;
|
||||
this.label10.Location = new System.Drawing.Point(24, 81);
|
||||
this.label10.Name = "label10";
|
||||
this.label10.Size = new System.Drawing.Size(277, 13);
|
||||
this.label10.TabIndex = 10;
|
||||
this.label10.Text = "When set, the client will make a backup copy of saveram";
|
||||
//
|
||||
// BackupSRamCheckbox
|
||||
//
|
||||
this.BackupSRamCheckbox.AutoSize = true;
|
||||
this.BackupSRamCheckbox.Location = new System.Drawing.Point(6, 61);
|
||||
this.BackupSRamCheckbox.Location = new System.Drawing.Point(6, 39);
|
||||
this.BackupSRamCheckbox.Name = "BackupSRamCheckbox";
|
||||
this.BackupSRamCheckbox.Size = new System.Drawing.Size(108, 17);
|
||||
this.BackupSRamCheckbox.Size = new System.Drawing.Size(203, 17);
|
||||
this.BackupSRamCheckbox.TabIndex = 9;
|
||||
this.BackupSRamCheckbox.Text = "Backup Saveram";
|
||||
this.BackupSRamCheckbox.Text = "Backup SaveRAM to .SaveRAM.bak";
|
||||
this.BackupSRamCheckbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(24, 37);
|
||||
this.label4.Location = new System.Drawing.Point(24, 23);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(234, 13);
|
||||
this.label4.TabIndex = 2;
|
||||
|
@ -410,53 +523,30 @@
|
|||
// LogWindowAsConsoleCheckbox
|
||||
//
|
||||
this.LogWindowAsConsoleCheckbox.AutoSize = true;
|
||||
this.LogWindowAsConsoleCheckbox.Location = new System.Drawing.Point(6, 17);
|
||||
this.LogWindowAsConsoleCheckbox.Location = new System.Drawing.Point(6, 3);
|
||||
this.LogWindowAsConsoleCheckbox.Name = "LogWindowAsConsoleCheckbox";
|
||||
this.LogWindowAsConsoleCheckbox.Size = new System.Drawing.Size(233, 17);
|
||||
this.LogWindowAsConsoleCheckbox.TabIndex = 1;
|
||||
this.LogWindowAsConsoleCheckbox.Text = "Create the log window as a console window";
|
||||
this.LogWindowAsConsoleCheckbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// panel1
|
||||
// label9
|
||||
//
|
||||
this.panel1.Controls.Add(this.label7);
|
||||
this.panel1.Controls.Add(this.LuaInterfaceRadio);
|
||||
this.panel1.Controls.Add(this.NLuaRadio);
|
||||
this.panel1.Location = new System.Drawing.Point(6, 312);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(377, 61);
|
||||
this.panel1.TabIndex = 20;
|
||||
this.label9.AutoSize = true;
|
||||
this.label9.Location = new System.Drawing.Point(6, 16);
|
||||
this.label9.Name = "label9";
|
||||
this.label9.Size = new System.Drawing.Size(225, 13);
|
||||
this.label9.TabIndex = 28;
|
||||
this.label9.Text = "Save SaveRAM to .AutoSaveRAM.SaveRAM";
|
||||
//
|
||||
// NLuaRadio
|
||||
// label10
|
||||
//
|
||||
this.NLuaRadio.AutoSize = true;
|
||||
this.NLuaRadio.Location = new System.Drawing.Point(4, 17);
|
||||
this.NLuaRadio.Name = "NLuaRadio";
|
||||
this.NLuaRadio.Size = new System.Drawing.Size(194, 17);
|
||||
this.NLuaRadio.TabIndex = 0;
|
||||
this.NLuaRadio.TabStop = true;
|
||||
this.NLuaRadio.Text = "NLua+KopiLua - Reliable but slower";
|
||||
this.NLuaRadio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// LuaInterfaceRadio
|
||||
//
|
||||
this.LuaInterfaceRadio.AutoSize = true;
|
||||
this.LuaInterfaceRadio.Location = new System.Drawing.Point(4, 36);
|
||||
this.LuaInterfaceRadio.Name = "LuaInterfaceRadio";
|
||||
this.LuaInterfaceRadio.Size = new System.Drawing.Size(338, 17);
|
||||
this.LuaInterfaceRadio.TabIndex = 1;
|
||||
this.LuaInterfaceRadio.TabStop = true;
|
||||
this.LuaInterfaceRadio.Text = "Lua+LuaInterface - Faster but memory leaks, use at your own risk!";
|
||||
this.LuaInterfaceRadio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label7
|
||||
//
|
||||
this.label7.AutoSize = true;
|
||||
this.label7.Location = new System.Drawing.Point(3, 1);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(50, 13);
|
||||
this.label7.TabIndex = 2;
|
||||
this.label7.Text = "Lua Core";
|
||||
this.label10.AutoSize = true;
|
||||
this.label10.Location = new System.Drawing.Point(9, 34);
|
||||
this.label10.Name = "label10";
|
||||
this.label10.Size = new System.Drawing.Size(33, 13);
|
||||
this.label10.TabIndex = 29;
|
||||
this.label10.Text = "every";
|
||||
//
|
||||
// EmuHawkOptions
|
||||
//
|
||||
|
@ -480,6 +570,9 @@
|
|||
this.groupBox1.PerformLayout();
|
||||
this.tabPage3.ResumeLayout(false);
|
||||
this.tabPage3.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.AutosaveSRAMtextBox)).EndInit();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
@ -508,8 +601,6 @@
|
|||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.ToolTip toolTip1;
|
||||
private System.Windows.Forms.CheckBox BackupSRamCheckbox;
|
||||
private System.Windows.Forms.Label label9;
|
||||
private System.Windows.Forms.Label label10;
|
||||
private System.Windows.Forms.CheckBox FrameAdvSkipLagCheckbox;
|
||||
private System.Windows.Forms.Label label12;
|
||||
private System.Windows.Forms.Label label13;
|
||||
|
@ -525,5 +616,14 @@
|
|||
private System.Windows.Forms.Label label7;
|
||||
private System.Windows.Forms.RadioButton LuaInterfaceRadio;
|
||||
private System.Windows.Forms.RadioButton NLuaRadio;
|
||||
private System.Windows.Forms.CheckBox AutosaveSRAMCheckbox;
|
||||
private System.Windows.Forms.Label label8;
|
||||
private System.Windows.Forms.RadioButton AutosaveSRAMradioButton3;
|
||||
private System.Windows.Forms.RadioButton AutosaveSRAMradioButton2;
|
||||
private System.Windows.Forms.RadioButton AutosaveSRAMradioButton1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.NumericUpDown AutosaveSRAMtextBox;
|
||||
private System.Windows.Forms.Label label10;
|
||||
private System.Windows.Forms.Label label9;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,34 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public partial class EmuHawkOptions : Form
|
||||
{
|
||||
public int AutosaveSaveRAMSeconds {
|
||||
get {
|
||||
if (AutosaveSRAMradioButton1.Checked)
|
||||
return 5;
|
||||
if (AutosaveSRAMradioButton2.Checked)
|
||||
return 5 * 60;
|
||||
return (int)AutosaveSRAMtextBox.Value;
|
||||
}
|
||||
set {
|
||||
switch (value)
|
||||
{
|
||||
case 5:
|
||||
AutosaveSRAMradioButton1.Checked = true;
|
||||
AutosaveSRAMtextBox.Enabled = false;
|
||||
break;
|
||||
case 5 * 60:
|
||||
AutosaveSRAMradioButton2.Checked = true;
|
||||
AutosaveSRAMtextBox.Enabled = false;
|
||||
break;
|
||||
default:
|
||||
AutosaveSRAMradioButton3.Checked = true;
|
||||
AutosaveSRAMtextBox.Enabled = true;
|
||||
break;
|
||||
}
|
||||
AutosaveSRAMtextBox.Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public EmuHawkOptions()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
@ -25,6 +53,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
SingleInstanceModeCheckbox.Checked = Global.Config.SingleInstanceMode;
|
||||
|
||||
BackupSRamCheckbox.Checked = Global.Config.BackupSaveram;
|
||||
AutosaveSRAMCheckbox.Checked = Global.Config.AutosaveSaveRAM;
|
||||
groupBox2.Enabled = AutosaveSRAMCheckbox.Checked;
|
||||
AutosaveSaveRAMSeconds = Global.Config.FlushSaveRamFrames / 60;
|
||||
FrameAdvSkipLagCheckbox.Checked = Global.Config.SkipLagFrame;
|
||||
LogWindowAsConsoleCheckbox.Checked = Global.Config.WIN32_CONSOLE;
|
||||
LuaDuringTurboCheckbox.Checked = Global.Config.RunLuaDuringTurbo;
|
||||
|
@ -56,6 +87,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
Global.Config.SingleInstanceMode = SingleInstanceModeCheckbox.Checked;
|
||||
|
||||
Global.Config.BackupSaveram = BackupSRamCheckbox.Checked;
|
||||
Global.Config.AutosaveSaveRAM = AutosaveSRAMCheckbox.Checked;
|
||||
Global.Config.FlushSaveRamFrames = AutosaveSaveRAMSeconds * 60;
|
||||
if (GlobalWin.MainForm.AutoFlushSaveRamIn > Global.Config.FlushSaveRamFrames)
|
||||
GlobalWin.MainForm.AutoFlushSaveRamIn = Global.Config.FlushSaveRamFrames;
|
||||
Global.Config.SkipLagFrame = FrameAdvSkipLagCheckbox.Checked;
|
||||
Global.Config.WIN32_CONSOLE = LogWindowAsConsoleCheckbox.Checked;
|
||||
Global.Config.RunLuaDuringTurbo = LuaDuringTurboCheckbox.Checked;
|
||||
|
@ -77,5 +112,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
DialogResult = DialogResult.Cancel;
|
||||
GlobalWin.OSD.AddMessage("Customizing aborted.");
|
||||
}
|
||||
|
||||
private void AutosaveSRAMCheckbox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
groupBox2.Enabled = AutosaveSRAMCheckbox.Checked;
|
||||
}
|
||||
|
||||
private void AutosaveSRAMradioButton3_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
AutosaveSRAMtextBox.Enabled = AutosaveSRAMradioButton3.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,220 +28,87 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.OK = new System.Windows.Forms.Button();
|
||||
this.Cancel = new System.Windows.Forms.Button();
|
||||
this.trackBar1 = new System.Windows.Forms.TrackBar();
|
||||
this.trackBar2 = new System.Windows.Forms.TrackBar();
|
||||
this.trackBar3 = new System.Windows.Forms.TrackBar();
|
||||
this.trackBar4 = new System.Windows.Forms.TrackBar();
|
||||
this.trackBar5 = new System.Windows.Forms.TrackBar();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.label8 = new System.Windows.Forms.Label();
|
||||
this.label9 = new System.Windows.Forms.Label();
|
||||
this.label10 = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar2)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar3)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar4)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar5)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// OK
|
||||
//
|
||||
this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.OK.Location = new System.Drawing.Point(41, 262);
|
||||
this.OK.Name = "OK";
|
||||
this.OK.Size = new System.Drawing.Size(75, 23);
|
||||
this.OK.TabIndex = 0;
|
||||
this.OK.Text = "&OK";
|
||||
this.OK.UseVisualStyleBackColor = true;
|
||||
this.OK.Click += new System.EventHandler(this.Ok_Click);
|
||||
//
|
||||
// Cancel
|
||||
//
|
||||
this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.Cancel.Location = new System.Drawing.Point(122, 262);
|
||||
this.Cancel.Name = "Cancel";
|
||||
this.Cancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.Cancel.TabIndex = 1;
|
||||
this.Cancel.Text = "&Cancel";
|
||||
this.Cancel.UseVisualStyleBackColor = true;
|
||||
this.Cancel.Click += new System.EventHandler(this.Cancel_Click);
|
||||
//
|
||||
// trackBar1
|
||||
//
|
||||
this.trackBar1.Location = new System.Drawing.Point(12, 12);
|
||||
this.trackBar1.Name = "trackBar1";
|
||||
this.trackBar1.Size = new System.Drawing.Size(104, 45);
|
||||
this.trackBar1.TabIndex = 2;
|
||||
this.trackBar1.ValueChanged += new System.EventHandler(this.TrackBar1_ValueChanged);
|
||||
//
|
||||
// trackBar2
|
||||
//
|
||||
this.trackBar2.Location = new System.Drawing.Point(12, 60);
|
||||
this.trackBar2.Name = "trackBar2";
|
||||
this.trackBar2.Size = new System.Drawing.Size(104, 45);
|
||||
this.trackBar2.TabIndex = 3;
|
||||
this.trackBar2.ValueChanged += new System.EventHandler(this.TrackBar2_ValueChanged);
|
||||
//
|
||||
// trackBar3
|
||||
//
|
||||
this.trackBar3.Location = new System.Drawing.Point(12, 108);
|
||||
this.trackBar3.Name = "trackBar3";
|
||||
this.trackBar3.Size = new System.Drawing.Size(104, 45);
|
||||
this.trackBar3.TabIndex = 4;
|
||||
this.trackBar3.ValueChanged += new System.EventHandler(this.TrackBar3_ValueChanged);
|
||||
//
|
||||
// trackBar4
|
||||
//
|
||||
this.trackBar4.Location = new System.Drawing.Point(12, 156);
|
||||
this.trackBar4.Name = "trackBar4";
|
||||
this.trackBar4.Size = new System.Drawing.Size(104, 45);
|
||||
this.trackBar4.TabIndex = 5;
|
||||
this.trackBar4.ValueChanged += new System.EventHandler(this.TrackBar4_ValueChanged);
|
||||
//
|
||||
// trackBar5
|
||||
//
|
||||
this.trackBar5.Location = new System.Drawing.Point(12, 204);
|
||||
this.trackBar5.Name = "trackBar5";
|
||||
this.trackBar5.Size = new System.Drawing.Size(104, 45);
|
||||
this.trackBar5.TabIndex = 6;
|
||||
this.trackBar5.ValueChanged += new System.EventHandler(this.TrackBar5_ValueChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(122, 12);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(50, 13);
|
||||
this.label1.TabIndex = 7;
|
||||
this.label1.Text = "Square 1";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(122, 60);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(50, 13);
|
||||
this.label2.TabIndex = 8;
|
||||
this.label2.Text = "Square 2";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(122, 108);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(45, 13);
|
||||
this.label3.TabIndex = 9;
|
||||
this.label3.Text = "Triangle";
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(122, 156);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(34, 13);
|
||||
this.label4.TabIndex = 10;
|
||||
this.label4.Text = "Noise";
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Location = new System.Drawing.Point(122, 204);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(31, 13);
|
||||
this.label5.TabIndex = 11;
|
||||
this.label5.Text = "DMC";
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
this.label6.Location = new System.Drawing.Point(122, 25);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(13, 13);
|
||||
this.label6.TabIndex = 12;
|
||||
this.label6.Text = "0";
|
||||
//
|
||||
// label7
|
||||
//
|
||||
this.label7.AutoSize = true;
|
||||
this.label7.Location = new System.Drawing.Point(122, 73);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(13, 13);
|
||||
this.label7.TabIndex = 13;
|
||||
this.label7.Text = "0";
|
||||
//
|
||||
// label8
|
||||
//
|
||||
this.label8.AutoSize = true;
|
||||
this.label8.Location = new System.Drawing.Point(122, 121);
|
||||
this.label8.Name = "label8";
|
||||
this.label8.Size = new System.Drawing.Size(13, 13);
|
||||
this.label8.TabIndex = 14;
|
||||
this.label8.Text = "0";
|
||||
//
|
||||
// label9
|
||||
//
|
||||
this.label9.AutoSize = true;
|
||||
this.label9.Location = new System.Drawing.Point(122, 169);
|
||||
this.label9.Name = "label9";
|
||||
this.label9.Size = new System.Drawing.Size(13, 13);
|
||||
this.label9.TabIndex = 15;
|
||||
this.label9.Text = "0";
|
||||
//
|
||||
// label10
|
||||
//
|
||||
this.label10.AutoSize = true;
|
||||
this.label10.Location = new System.Drawing.Point(122, 217);
|
||||
this.label10.Name = "label10";
|
||||
this.label10.Size = new System.Drawing.Size(13, 13);
|
||||
this.label10.TabIndex = 16;
|
||||
this.label10.Text = "0";
|
||||
//
|
||||
// NESSoundConfig
|
||||
//
|
||||
this.AcceptButton = this.OK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.Cancel;
|
||||
this.ClientSize = new System.Drawing.Size(209, 297);
|
||||
this.Controls.Add(this.label10);
|
||||
this.Controls.Add(this.label9);
|
||||
this.Controls.Add(this.label8);
|
||||
this.Controls.Add(this.label7);
|
||||
this.Controls.Add(this.label6);
|
||||
this.Controls.Add(this.label5);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.trackBar5);
|
||||
this.Controls.Add(this.trackBar4);
|
||||
this.Controls.Add(this.trackBar3);
|
||||
this.Controls.Add(this.trackBar2);
|
||||
this.Controls.Add(this.trackBar1);
|
||||
this.Controls.Add(this.Cancel);
|
||||
this.Controls.Add(this.OK);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "NESSoundConfig";
|
||||
this.ShowIcon = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "NES Sound Channels";
|
||||
this.Load += new System.EventHandler(this.NESSoundConfig_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar2)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar3)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar4)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar5)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
this.OK = new System.Windows.Forms.Button();
|
||||
this.Cancel = new System.Windows.Forms.Button();
|
||||
this.trackBar1 = new System.Windows.Forms.TrackBar();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// OK
|
||||
//
|
||||
this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.OK.Location = new System.Drawing.Point(41, 117);
|
||||
this.OK.Name = "OK";
|
||||
this.OK.Size = new System.Drawing.Size(75, 23);
|
||||
this.OK.TabIndex = 0;
|
||||
this.OK.Text = "&OK";
|
||||
this.OK.UseVisualStyleBackColor = true;
|
||||
this.OK.Click += new System.EventHandler(this.Ok_Click);
|
||||
//
|
||||
// Cancel
|
||||
//
|
||||
this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.Cancel.Location = new System.Drawing.Point(122, 117);
|
||||
this.Cancel.Name = "Cancel";
|
||||
this.Cancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.Cancel.TabIndex = 1;
|
||||
this.Cancel.Text = "&Cancel";
|
||||
this.Cancel.UseVisualStyleBackColor = true;
|
||||
this.Cancel.Click += new System.EventHandler(this.Cancel_Click);
|
||||
//
|
||||
// trackBar1
|
||||
//
|
||||
this.trackBar1.LargeChange = 1;
|
||||
this.trackBar1.Location = new System.Drawing.Point(12, 12);
|
||||
this.trackBar1.Minimum = 1;
|
||||
this.trackBar1.Name = "trackBar1";
|
||||
this.trackBar1.Size = new System.Drawing.Size(104, 45);
|
||||
this.trackBar1.TabIndex = 2;
|
||||
this.trackBar1.Value = 1;
|
||||
this.trackBar1.ValueChanged += new System.EventHandler(this.TrackBar1_ValueChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(122, 12);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(67, 13);
|
||||
this.label1.TabIndex = 7;
|
||||
this.label1.Text = "APU Volume";
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
this.label6.Location = new System.Drawing.Point(122, 25);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(13, 13);
|
||||
this.label6.TabIndex = 12;
|
||||
this.label6.Text = "0";
|
||||
//
|
||||
// NESSoundConfig
|
||||
//
|
||||
this.AcceptButton = this.OK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.Cancel;
|
||||
this.ClientSize = new System.Drawing.Size(209, 152);
|
||||
this.Controls.Add(this.label6);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.trackBar1);
|
||||
this.Controls.Add(this.Cancel);
|
||||
this.Controls.Add(this.OK);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "NESSoundConfig";
|
||||
this.ShowIcon = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "NES Sound Channels";
|
||||
this.Load += new System.EventHandler(this.NESSoundConfig_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
|
@ -250,19 +117,7 @@
|
|||
private System.Windows.Forms.Button OK;
|
||||
private System.Windows.Forms.Button Cancel;
|
||||
private System.Windows.Forms.TrackBar trackBar1;
|
||||
private System.Windows.Forms.TrackBar trackBar2;
|
||||
private System.Windows.Forms.TrackBar trackBar3;
|
||||
private System.Windows.Forms.TrackBar trackBar4;
|
||||
private System.Windows.Forms.TrackBar trackBar5;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.Label label6;
|
||||
private System.Windows.Forms.Label label7;
|
||||
private System.Windows.Forms.Label label8;
|
||||
private System.Windows.Forms.Label label9;
|
||||
private System.Windows.Forms.Label label10;
|
||||
}
|
||||
}
|
|
@ -38,11 +38,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
// get baseline maxes from a default config object
|
||||
var d = new NES.NESSettings();
|
||||
trackBar1.Maximum = d.Square1;
|
||||
trackBar2.Maximum = d.Square2;
|
||||
trackBar3.Maximum = d.Triangle;
|
||||
trackBar4.Maximum = d.Noise;
|
||||
trackBar5.Maximum = d.DMC;
|
||||
trackBar1.Minimum = d.APU_vol;
|
||||
}
|
||||
|
||||
private void NESSoundConfig_Load(object sender, EventArgs e)
|
||||
|
@ -50,11 +46,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
_oldSettings = NES.GetSettings();
|
||||
_settings = _oldSettings.Clone();
|
||||
|
||||
trackBar1.Value = _settings.Square1;
|
||||
trackBar2.Value = _settings.Square2;
|
||||
trackBar3.Value = _settings.Triangle;
|
||||
trackBar4.Value = _settings.Noise;
|
||||
trackBar5.Value = _settings.DMC;
|
||||
trackBar1.Value = _settings.APU_vol;
|
||||
}
|
||||
|
||||
private void Ok_Click(object sender, EventArgs e)
|
||||
|
@ -72,35 +64,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
private void TrackBar1_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
label6.Text = trackBar1.Value.ToString();
|
||||
_settings.Square1 = trackBar1.Value;
|
||||
NES.PutSettings(_settings);
|
||||
}
|
||||
|
||||
private void TrackBar2_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
label7.Text = trackBar2.Value.ToString();
|
||||
_settings.Square2 = trackBar2.Value;
|
||||
NES.PutSettings(_settings);
|
||||
}
|
||||
|
||||
private void TrackBar3_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
label8.Text = trackBar3.Value.ToString();
|
||||
_settings.Triangle = trackBar3.Value;
|
||||
NES.PutSettings(_settings);
|
||||
}
|
||||
|
||||
private void TrackBar4_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
label9.Text = trackBar4.Value.ToString();
|
||||
_settings.Noise = trackBar4.Value;
|
||||
NES.PutSettings(_settings);
|
||||
}
|
||||
|
||||
private void TrackBar5_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
label10.Text = trackBar5.Value.ToString();
|
||||
_settings.DMC = trackBar5.Value;
|
||||
_settings.APU_vol = trackBar1.Value;
|
||||
NES.PutSettings(_settings);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 856 B |
|
@ -0,0 +1,148 @@
|
|||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
partial class GBPrinterView
|
||||
{
|
||||
/// <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(GBPrinterView));
|
||||
this.paperView = new BmpView();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.paperScroll = new System.Windows.Forms.VScrollBar();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.saveImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileToolStripMenuItem,
|
||||
this.editToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(336, 24);
|
||||
this.menuStrip1.TabIndex = 2;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// fileToolStripMenuItem
|
||||
//
|
||||
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.saveImageToolStripMenuItem});
|
||||
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
|
||||
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
|
||||
this.fileToolStripMenuItem.Text = "&File";
|
||||
//
|
||||
// saveImageToolStripMenuItem
|
||||
//
|
||||
this.saveImageToolStripMenuItem.Name = "saveImageToolStripMenuItem";
|
||||
this.saveImageToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S)));
|
||||
this.saveImageToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
|
||||
this.saveImageToolStripMenuItem.Text = "&Save Image...";
|
||||
this.saveImageToolStripMenuItem.Click += new System.EventHandler(this.saveImageToolStripMenuItem_Click);
|
||||
//
|
||||
// editToolStripMenuItem
|
||||
//
|
||||
this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.copyToolStripMenuItem});
|
||||
this.editToolStripMenuItem.Name = "editToolStripMenuItem";
|
||||
this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20);
|
||||
this.editToolStripMenuItem.Text = "&Edit";
|
||||
//
|
||||
// copyToolStripMenuItem
|
||||
//
|
||||
this.copyToolStripMenuItem.Name = "copyToolStripMenuItem";
|
||||
this.copyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C)));
|
||||
this.copyToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
|
||||
this.copyToolStripMenuItem.Text = "&Copy";
|
||||
this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click);
|
||||
//
|
||||
// paperView
|
||||
//
|
||||
this.paperView.Name = "paperView";
|
||||
this.paperView.Location = new System.Drawing.Point(0, 48);
|
||||
this.paperView.Size = new System.Drawing.Size(320, 320);
|
||||
this.paperView.BackColor = System.Drawing.Color.Black;
|
||||
this.paperView.TabIndex = 0;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Location = new System.Drawing.Point(0, 24);
|
||||
this.label1.Size = new System.Drawing.Size(336, 24);
|
||||
this.label1.Text = "Note: the printer is only connected while this window is open.";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// paperScroll
|
||||
//
|
||||
this.paperScroll.Name = "paperScroll";
|
||||
this.paperScroll.Location = new System.Drawing.Point(320, 48);
|
||||
this.paperScroll.Size = new System.Drawing.Size(16, 320);
|
||||
this.paperScroll.Minimum = 0;
|
||||
this.paperScroll.SmallChange = 8;
|
||||
this.paperScroll.LargeChange = 160;
|
||||
this.paperScroll.ValueChanged += PaperScroll_ValueChanged;
|
||||
//
|
||||
// GBPrinterView
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.ClientSize = new System.Drawing.Size(336, 358);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.Controls.Add(this.paperView);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.paperScroll);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "GBPrinterView";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Printer Viewer";
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.FormClosed += GBPrinterView_FormClosed;
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem saveImageToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem;
|
||||
private BmpView paperView;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.VScrollBar paperScroll;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
using BizHawk.Client.EmuHawk.WinFormExtensions;
|
||||
using System.Collections.Generic;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public partial class GBPrinterView : Form, IToolFormAutoConfig
|
||||
{
|
||||
const int PaperWidth = 160;
|
||||
|
||||
// the bg color
|
||||
private static readonly uint PaperColor = (uint)Color.AntiqueWhite.ToArgb();
|
||||
|
||||
private ColorMatrix PaperAdjustment;
|
||||
|
||||
[RequiredService]
|
||||
public IGameboyCommon Gb { get; private set; }
|
||||
|
||||
// If we've connected the printer yet
|
||||
bool connected = false;
|
||||
|
||||
// the entire bitmap
|
||||
Bitmap printerHistory;
|
||||
|
||||
public GBPrinterView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// adjust the color of the printed output to be more papery
|
||||
PaperAdjustment = new ColorMatrix();
|
||||
PaperAdjustment.Matrix00 = (0xFA - 0x10) / 255F;
|
||||
PaperAdjustment.Matrix40 = 0x10 / 255F;
|
||||
PaperAdjustment.Matrix11 = (0xEB - 0x10) / 255F;
|
||||
PaperAdjustment.Matrix41 = 0x10 / 255F;
|
||||
PaperAdjustment.Matrix22 = (0xD7 - 0x18) / 255F;
|
||||
PaperAdjustment.Matrix42 = 0x18 / 255F;
|
||||
|
||||
paperView.ChangeBitmapSize(PaperWidth, PaperWidth);
|
||||
|
||||
ClearPaper();
|
||||
}
|
||||
|
||||
private void GBPrinterView_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
if (Gb != null)
|
||||
{
|
||||
Gb.SetPrinterCallback(null);
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateBefore => false;
|
||||
|
||||
public bool AskSaveChanges() => true;
|
||||
|
||||
public void FastUpdate()
|
||||
{
|
||||
}
|
||||
|
||||
public void NewUpdate(ToolFormUpdateType type)
|
||||
{
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
// Really, there's not necessarilly a reason to clear it at all,
|
||||
// since the paper would still be there,
|
||||
// but it just seems right to get a blank slate on reset.
|
||||
ClearPaper();
|
||||
|
||||
connected = false;
|
||||
}
|
||||
|
||||
public void UpdateValues()
|
||||
{
|
||||
// Automatically connect once the game is running
|
||||
if (!connected)
|
||||
{
|
||||
Gb.SetPrinterCallback(OnPrint);
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The printer callback that . See PrinterCallback for details.
|
||||
/// </summary>
|
||||
void OnPrint(IntPtr image, byte height, byte topMargin, byte bottomMargin, byte exposure)
|
||||
{
|
||||
// In this implementation:
|
||||
// the bottom margin and top margin are just white lines at the top and bottom
|
||||
// exposure is ignored
|
||||
|
||||
// The page received image
|
||||
Bitmap page = new Bitmap(PaperWidth, height);
|
||||
|
||||
var bmp = page.LockBits(new Rectangle(0, 0, PaperWidth, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < PaperWidth; x++)
|
||||
{
|
||||
uint pixel;
|
||||
unsafe
|
||||
{
|
||||
// Pixel of the image; it's just sent from the core as a big bitmap that's 160xheight
|
||||
pixel = *(uint*)(image + (x + y * PaperWidth) * sizeof(uint));
|
||||
}
|
||||
|
||||
SetPixel(bmp, x, y, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
page.UnlockBits(bmp);
|
||||
|
||||
// add it to the bottom of the history
|
||||
int oldHeight = printerHistory.Height;
|
||||
ResizeHistory(printerHistory.Height + page.Height + topMargin + bottomMargin);
|
||||
using (var g = Graphics.FromImage(printerHistory))
|
||||
{
|
||||
// Make it brown
|
||||
ImageAttributes a = new ImageAttributes();
|
||||
a.SetColorMatrix(PaperAdjustment);
|
||||
|
||||
g.DrawImage(page, new Rectangle(0, oldHeight + topMargin, page.Width, page.Height), 0F, 0F, page.Width, page.Height, GraphicsUnit.Pixel, a);
|
||||
g.Flush();
|
||||
}
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a 2x pixel
|
||||
/// </summary>
|
||||
/// <param name="bmp">The bitmap data to draw to</param>
|
||||
/// <param name="x">X position</param>
|
||||
/// <param name="y">Y position</param>
|
||||
/// <param name="c">The ARGB color to set that pixel to</param>
|
||||
unsafe void SetPixel(BitmapData bmp, int x, int y, uint c)
|
||||
{
|
||||
uint* pixel = (uint*)(bmp.Scan0 + x * 4 + y * bmp.Stride);
|
||||
*pixel = c;
|
||||
}
|
||||
|
||||
void ClearPaper()
|
||||
{
|
||||
ResizeHistory(8);
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
void ResizeHistory(int height)
|
||||
{
|
||||
// copy to a new image of height
|
||||
var newHistory = new Bitmap(PaperWidth, height);
|
||||
using (var g = Graphics.FromImage(newHistory))
|
||||
{
|
||||
g.Clear(Color.FromArgb((int)PaperColor));
|
||||
if (printerHistory != null)
|
||||
g.DrawImage(printerHistory, Point.Empty);
|
||||
g.Flush();
|
||||
}
|
||||
|
||||
if (printerHistory != null)
|
||||
printerHistory.Dispose();
|
||||
printerHistory = newHistory;
|
||||
|
||||
// Update scrollbar, viewport is a square
|
||||
paperScroll.Maximum = Math.Max(0, height);
|
||||
}
|
||||
|
||||
void RefreshView()
|
||||
{
|
||||
using (Graphics g = Graphics.FromImage(paperView.BMP))
|
||||
{
|
||||
g.Clear(Color.FromArgb((int)PaperColor));
|
||||
g.DrawImage(printerHistory, new Point(0, -paperScroll.Value));
|
||||
g.Flush();
|
||||
}
|
||||
|
||||
paperView.Refresh();
|
||||
}
|
||||
|
||||
private void saveImageToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
// slight hack to use the nice SaveFile() feature of a BmpView
|
||||
|
||||
BmpView toSave = new BmpView();
|
||||
toSave.ChangeBitmapSize(printerHistory.Size);
|
||||
using (var g = Graphics.FromImage(toSave.BMP))
|
||||
{
|
||||
g.DrawImage(printerHistory, Point.Empty);
|
||||
g.Flush();
|
||||
}
|
||||
toSave.SaveFile();
|
||||
}
|
||||
|
||||
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Clipboard.SetImage(printerHistory);
|
||||
}
|
||||
|
||||
private void PaperScroll_ValueChanged(object sender, System.EventArgs e)
|
||||
{
|
||||
RefreshView();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
<?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>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<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>
|
||||
AAABAAQAICAAAAEAIACoEAAARgAAACAgAAABAAgAqAgAAO4QAAAQEAAAAQAgAGgEAACWGQAAEBAAAAEA
|
||||
CABoBQAA/h0AACgAAAAgAAAAQAAAAAEAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAB7e3tAfHx8v3d3d/9tbW3/aWlp/2lpaf9paWn/aWlp/2lpaf9paWn/aWlp/2lpaf9paWn/aWlp/2lp
|
||||
af9paWn/aWlp/2lpaf9oaGj/ZmZm/3BwcP+EhIT/jo6Ov4+Pj0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAHt7e0B6enq/fX19/4GBgf+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4KCgv+BgYH/fn5+/3x8
|
||||
fP98fHz/fn5+/4GBgf+CgoL/goKC/3x8fP9ycnL/dXV1/4WFhf+MjIzPiIiIcISEhDB/f38QAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAd3d3QHl5eb+JiYn/qKio/7i4uP+3t7f/t7e3/7e3t/+3t7f/tra2/7Gx
|
||||
sf+oqKj/o6Oj/6SkpP+pqan/s7Oz/7a2tv+0tLT/paWl/4iIiP9+fn7/h4eH/4mJie+FhYXPgoKCj4SE
|
||||
hDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3dAeHh4v4+Pj/+7u7v/0dHR/8/Pz//Pz8//0NDQ/9HR
|
||||
0f/Q0ND/ycnJ/729vf+3t7f/uLi4/729vv/IyMr/zs7P/83Nzv+9vb3/np6e/46Ojv+NjY3/ioqK/4KC
|
||||
gv9+fn6/f39/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d0B4eHi/jo6O/7q6uv/Ozs7/ysrK/8rK
|
||||
yv/Ozs7/0NDQ/9DQ0P/Kysr/vb29/7e3t/+3t7f/urq8/8LCx//IyM3/zMzO/8TExf+ysrL/o6Oj/5iY
|
||||
mP+MjIz/fn5+/3Z2dr93d3dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3QHZ2dr+JiYn/ra2t/7e3
|
||||
t/+lpaX/p6en/7y8vP/Jycn/zs7O/8zMzP/Dw8L/urq9/7Kyu/+oqLz/nZ3C/6Cgxf+xscf/ubnD/7i4
|
||||
vP+vr7D/oKCh/5OTlP+JiYr/hYWFz4aGhnCKioowj4+PEAAAAAAAAAAAAAAAAAAAAAB3d3dAdXV1v4CA
|
||||
gP+VlZX/ioqK/2BgYP9mZmb/mpqa/7u7u//Jycn/z8/O/8zMzP/AwMj/qqrE/4iIv/9ZWbn/Vla3/39/
|
||||
uP+cnLn/rq66/7GxtP+kpKf/n5+i/6Skpf+hoaHvkpKSz4uLi4+KioowAAAAAAAAAAAAAAAAAAAAAHNz
|
||||
c0B0dHS/dHR0/3R0dP9gYGD/NjY2/zs7O/9wcHD/m5ub/7y8vP/Ozs7/0NDQ/8PDzv+mpsn/eHjD/zg4
|
||||
u/8xMbf/ZGS1/4SEtf+Rkbf/lJS1/4yMrf+UlK7/ra22/62trv+Wlpb/ioqKv4uLi0AAAAAAAAAAAAAA
|
||||
AAAAAAAAb29vQHBwcL9jY2P/S0tL/zY2Nv8mJib/KCgo/zw8PP9nZ2f/qKio/8rKyv/Pz87/wsLO/6am
|
||||
yv94eMj/ODjJ/zAwxf9hYb7/cXG4/19fsv9YWLH/WVmz/3Jyt/+jo73/sLCy/5eXmP+Kioq/i4uLQAAA
|
||||
AAAAAAAAAAAAAAAAAABvb29AcHBwv2VlZf9QUFD/PDw8/ygoKP8pKSn/Pz8//2pqav+pqan/ysrK/87O
|
||||
zv/Gxs//sLDM/42NzP9cXND/VFTN/3d3w/90dLv/S0u0/zo6tf9AQL3/YWHC/5+fwv+xsbX/l5eZ/4qK
|
||||
ir+Li4tAAAAAAAAAAAAAAAAAAAAAAHNzc0B1dXW/enp6/4WFhf9wcHD/PDw8/z8/P/94eHj/o6Oj/7+/
|
||||
v//Ozs7/0NDQ/83N0P/Gxs//uLjP/6Sk0f+ens3/paXD/42Nvv9VVb3/OzvB/0BAzP9hYc7/n5/H/7Gx
|
||||
tf+Xl5n/ioqKv4uLi0AAAAAAAAAAAAAAAAAAAAAAd3d3QHh4eL+Hh4f/pqam/5ubm/9nZ2f/ampq/6Oj
|
||||
o//ExMT/zMzM/9DQ0P/Q0ND/0dHR/9HR0f/OztH/ysrS/8bGzv/Cwsf/p6fE/3Z2xf9fX8r/YmLT/3t7
|
||||
0/+oqMj/srK1/5iYmf+Kioq/i4uLQAAAAAAAAAAAAAAAAAAAAAB3d3dAeHh4v4yMjP+0tLT/vb29/6io
|
||||
qP+pqan/v7+//8zMzP/Pz8//0NDQ/9DQ0P/R0dH/0dHR/9DQ0f/OztH/zc3Q/8zMzf/Bwcz/r6/N/6am
|
||||
z/+oqNP/r6/Q/7u7x/+0tLX/mJiZ/4qKir+Li4tAAAAAAAAAAAAAAAAAAAAAAHd3d0B4eHi/jo6O/7q6
|
||||
uv/Nzc3/yMjI/8fHx//Ly8v/zc3N/87Ozv/Ozs7/zs7O/87Ozv/Ozs7/zs7O/87Ozv/Ozs7/zs7O/8zM
|
||||
zv/Kys7/ycnP/8nJz//IyMz/xMTG/7W1tf+ZmZn/ioqKv4uLi0AAAAAAAAAAAAAAAAAAAAAAd3d3QHh4
|
||||
eL+Ojo7/uLi4/8zMzP/IyMj/xsbG/8fHx//IyMj/yMjI/8jIyP/IyMj/yMjI/8jIyP/IyMj/yMjI/8jI
|
||||
yP/IyMj/yMjI/8fHyP/Hx8n/x8fJ/8bGyP/ExMT/tbW1/5mZmf+Kioq/i4uLQAAAAAAAAAAAAAAAAAAA
|
||||
AAB3d3dAdnZ2v4aGhv+jo6P/r6+v/6qqqv+nqKj/pqio/6WpqP+lqaj/pamo/6WpqP+lqaj/pamo/6Wp
|
||||
qP+lqaj/pamo/6WpqP+mqaj/pqio/6eoqP+oqKj/rKys/7Kysv+rq6v/lZWV/4qKir+Li4tAAAAAAAAA
|
||||
AAAAAAAAAAAAAHNzc0B0dHS/dnZ2/3t7e/94eXn/b3Bw/2lsbP9nbm3/ZW9t/2Vvbf9lb23/ZW9t/2Vv
|
||||
bf9lb23/ZW9t/2Vvbf9lb23/ZW9t/2Zvbf9obmz/am1s/2xtbP94eHj/j4+P/5eXl/+Pj4//ioqKv4uL
|
||||
i0AAAAAAAAAAAAAAAAAAAAAAb29vQHFxcb9sbGz/Y2Nj/11eXv9bXV3/UWNf/0FtY/84c2b/NnNm/zZz
|
||||
Zv82c2b/NnNm/zZzZv82c2b/NnNm/zZzZv82c2b/O3Bl/0RrYv9OZV//Vl5c/2VkZf95eHn/hYWF/4mJ
|
||||
if+Kioq/i4uLQAAAAAAAAAAAAAAAAAAAAABra2tAbW1tv2dnZ/9bW1v/XV9e/2xzcf9eioD/NKWM/x2z
|
||||
kv8atJP/GLWT/xi1k/8YtZP/GLWT/xi1k/8YtZP/GLWT/xi1k/8krZD/PZ6J/1OOgf9oe3f/cXBx/25u
|
||||
bv90dHT/hISE/4qKir+Li4tAAAAAAAAAAAAAAAAAAAAAAGtra0BsbGy/ZWVl/1dXV/9cX1//dH17/2Se
|
||||
kf8swaD/DdSp/wnWqv8H16r/B9eq/wfXqv8H16r/B9eq/wfXqv8H16r/B9eq/xfNpv83uZ3/VaOS/3GK
|
||||
hf93d3f/aWlp/2xsbP+BgYH/jIyMv4uLi0AAAAAAAAAAAAAAAAAAAAAAa2trQGxsbL9lZWX/V1dX/1xf
|
||||
Xv90fXv/Y5+R/yjDof8J1qr/BNir/wLZq/8C2av/Atmr/wLZq/8C2av/Atmr/wLZq/8C2av/E8+m/zS6
|
||||
nf9To5L/cIqE/3d3d/9paWn/bGxs/4GBgf+MjIy/i4uLQAAAAAAAAAAAAAAAAAAAAABra2tAbGxsv2Vl
|
||||
Zf9XV1f/XF9e/3R9e/9in5L/JsOi/wbXqv8C2av/ANus/wDbrP8A26z/ANus/wDbrP8A26z/ANus/wDb
|
||||
rP8R0Kf/M7ud/1Kkkv9wioT/d3d3/2lpaf9sbGz/gYGB/4yMjL+Li4tAAAAAAAAAAAAAAAAAAAAAAGtr
|
||||
a0BsbGy/ZWVl/1dXV/9cX17/dH17/2Kfkv8mw6L/Bteq/wLZq/8A26z/ANus/wDbrP8A26z/ANus/wDb
|
||||
rP8A26z/ANus/xHQp/8zu53/UqSS/3CKhP93d3f/aWlp/2xsbP+BgYH/jIyMv4uLi0AAAAAAAAAAAAAA
|
||||
AAAAAAAAa2trQGxsbL9lZWX/V1dX/1xfXv90fXv/Yp+S/ybDov8G16r/Atmr/wDbrP8A26z/ANus/wDb
|
||||
rP8A26z/ANus/wDbrP8A26z/EdCn/zO7nf9SpJL/cIqE/3d3d/9paWn/bGxs/4GBgf+MjIy/i4uLQAAA
|
||||
AAAAAAAAAAAAAAAAAABra2tAbGxsv2VlZf9XV1f/XF9e/3R9e/9in5L/JsOi/wbXqv8C2av/ANus/wDb
|
||||
rP8A26z/ANus/wDbrP8A26z/ANus/wDbrP8R0Kf/M7ud/1Kkkv9wioT/d3d3/2lpaf9sbGz/gYGB/4yM
|
||||
jL+Li4tAAAAAAAAAAAAAAAAAAAAAAGtra0BsbGy/ZWVl/1dXV/9cX17/dH17/2Ofkf8ow6H/Cdaq/wTY
|
||||
q/8C2qv/Atqr/wLaq/8C2qv/Atqr/wLaq/8C2qv/Atqr/xPPpv80up3/U6OS/3CKhP93d3f/aWlp/2xs
|
||||
bP+BgYH/jIyMv4uLi0AAAAAAAAAAAAAAAAAAAAAAa2trQGxsbL9lZWX/V1dX/1xfX/90fXv/ZJ6R/yzB
|
||||
oP8N1Kn/Cdaq/wfYqv8H2Kr/B9iq/wfYqv8H2Kr/B9iq/wfYqv8H2Kr/F82m/ze5nf9Vo5L/cYqE/3d3
|
||||
d/9paWn/bGxs/4GBgf+MjIy/i4uLQAAAAAAAAAAAAAAAAAAAAABra2tAbW1tv2dnZ/9bW1v/XWBf/210
|
||||
cv9fi4H/NaaN/x60k/8btpT/GbeU/xm3lP8Zt5T/GbeU/xm3lP8Zt5T/GbeU/xm3lP8lr5H/Pp+K/1SP
|
||||
gv9pfHj/cnFx/25ubv90dHT/hISE/4qKir+Li4tAAAAAAAAAAAAAAAAAAAAAAG9vb0BxcXG/bGxs/2Rk
|
||||
ZP9fYGD/XWBg/1RmYv9EcGb/O3Zp/zl2af85d2n/OXdp/zl3af85d2n/OXdp/zl3af85d2n/OXdp/z5z
|
||||
aP9HbWX/UWdi/1lhX/9nZ2f/enp6/4WFhf+JiYn/ioqKv4uLi0AAAAAAAAAAAAAAAAAAAAAAc3NzQHV1
|
||||
db9xcXH/aGho/2BgYP9XWFj/UVRU/09WVf9NV1X/TVdV/01XVf9NV1X/TVdV/01XVf9NV1X/TVdV/01X
|
||||
Vf9NV1X/TldV/1BWVP9SVVT/VFVU/2FhYf95eXn/hoaG74iIiM+Li4uPioqKMAAAAAAAAAAAAAAAAAAA
|
||||
AAB3d3dAeXl5v3R0dP9oaGj/YGBg/1paWv9XWFj/VlhY/1VZWP9VWVj/VVlY/1VZWP9VWVj/VVlY/1VZ
|
||||
WP9VWVj/VVlY/1VZWP9WWVj/VlhY/1dYWP9YWFj/X19f/2xsbP91dXXPfX19cIqKijCPj48QAAAAAAAA
|
||||
AAAAAAAAAAAAAHt7e0B8fHy/dXV1/2hoaP9gYGD/XFxc/1paWv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1pa
|
||||
Wv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1paWv9eXl7/ZmZm/2lpab9ra2tAAAAAAAAA
|
||||
AAAAAAAA8AAAP/AAAD/wAAAP8AAAD/AAAA/wAAAP8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA
|
||||
AAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA
|
||||
AAPwAAAD8AAAD/AAAA8oAAAAIAAAAEAAAAABAAgAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA/zMz
|
||||
M/82Njb/ODg4/z57bv87fW//OH9v/zd/cP9DQ0P/SEhI/01NTf9MX1v/T15b/1FRUf9XV1f/VFlY/1dY
|
||||
WP9TXFr/UF5b/1RcWv9YWln/Wlpa/1ldXP9aXFz/XFxc/11eXv9KYVz/TGBc/11lY/9UbWf/XWhm/1Jt
|
||||
aP9HdWv/RnZs/1dzbf9Zcm3/THpw/0t8cf9gYGD/YGJi/2JiYv9hZGP/YWVk/2FmZP9kZGT/ZmZm/2Nq
|
||||
af9ibmv/aGho/2pqav9pbGv/bGxs/25ubv9jcm//ZHNv/29xcf9tcnH/bnNy/2R6dv9ofHf/aHx4/2h/
|
||||
ev9sf3v/b357/3BwcP9ycnL/cXd2/3R0dP92dnb/cnl3/3N8ev90fHr/eHh4/3p6ev95fHv/en18/3x8
|
||||
fP9+fn7/NoBw/zuFdf88hHT/Q4Bz/0CCdP9Whnz/Uol9/2qAfP9sgHz/Skq5/0tLvP9PT77/UVG//1pa
|
||||
uP9jY7T/Z2e1/2pqtv9mZrn/YWG+/2Rkv/9vb7n/bW28/3FxvP99fbj/SkrD/05Owv9RUcf/UlLI/25u
|
||||
wf9pacr/dXXD/3l5xP9wcMr/cXHO/3p6yf87m4b/PpiE/zych/8crY7/HqyN/x2vj/8ero//K6SK/yym
|
||||
i/8mqIv/IKuN/yepjP8hrY7/OLKX/zS2mf84spj/M7ud/zW6nf8wvp//Lr+g/1Sdjf9Ymov/WJqM/1if
|
||||
kP9piIL/aoiB/2qMhf9To5H/V6CQ/1Kkkv8ewp//D8yj/wvOpP8OzaT/DM6k/w7OpP8Yx6H/EM2j/xbN
|
||||
pv8Wzqb/Gcyl/wbXqv8P0qj/CNaq/wPZq/8E2Kv/Btiq/wDarP8R0aj/gICA/4KCgv+DhIT/hISE/4aG
|
||||
hv+IiIj/ioqK/4yMjP+Ojo7/j4+Q/5CQkP+SkpL/lJSU/5aWl/+YmJj/mpqa/5ubnf+cnJ3/np6i/5yc
|
||||
pP+Tk6//n5+p/4qKsf+Kirf/gYG5/5WVv/+amrr/nqKh/6Ghof+jpKT/pKSk/6ampv+lpan/pqau/6mp
|
||||
qf+rq67/ra2t/6KisP+lpbL/qamz/66usv+mprn/pKS+/7CwsP+1tbX/srK4/7e3uv+xsb7/t7e+/7i4
|
||||
uP+9vb7/hobA/4ODxv+KisD/h4fP/5aWw/+amsH/nJzD/5iYxv+QkM3/mprM/6Kixf+oqMT/o6PJ/6Wl
|
||||
y/+goM7/qqrN/7KywP+zs8X/u7vA/76+wf+6usX/vb3H/7e3yf+wsM3/u7vL/7+/yv++vs3/oKDQ/7Gx
|
||||
0P+/wMD/wMHB/8TExf/Bwcr/wMDN/8bGzf/Jycn/y8vN/83Nzf/BwdD/ycnQ/83N0P/Q0ND/AAAA/wBM
|
||||
TExJSURDQ0NDQ0FBQUFBOUFCQ0A0RKOoqaelo6QAAExMTE2ipqmpqaqqqaimpKWnqKmno0lJo6enpqOl
|
||||
pQAASUlJoqq+xs3Nzc3NxMC+vb/FxsazqqWnqKalo6KiAABISEmirs30+Pj4+PTz087O0PL0886+r6qo
|
||||
paJNTaOoAEhISKOvzfP09Pj6/vjy09DS6e716M2+r6qmoqKlp6kASEhITaq/xL7BzvT6+PTn0cza2+DR
|
||||
z8W/r6qpqKipqABERERJpKmlQ0SvzfT5+Org12Nj1bzLyLW1tLOvq6ipAENDQ0NBNBkJCjOvzvj97+Ft
|
||||
Wlhfurm5uLbHwbCsqagAQEBBNDAQCAEDDUnB9Pn24nBpZmBkXlxdZbzIsqyoqQBBQUE0MBgJAgMNS8T0
|
||||
+fvs3W9rbGNbV1pq2ce0rKmoAEREQ0RJSDANDUOx0/j+/fvx8N7c1WBnaW7ZybOsqakARERITaiwq0lM
|
||||
s9P4+v7+/fz77+vf1m5v2N/Js6yoqABISEmircTNwcHT+Pr+/v7+/vr59+7k4/Dk5sqzrKmpAEhISKKu
|
||||
zfPz8/T5+P36+vr6/vr59/f1+/bozb6tqKgASEhJoq7G1PPy8vP08/Pz8/Pz8/Py8+ry6NTNs6ypqQBI
|
||||
SERMp7G/v769vb29vb29vb29vb29vr7BxMCwqqioAENDRERMTaJKRz9VVVVVVVVVPVU+Pz9GSqSsrqyq
|
||||
qakAQEBAQDMxLS4jJVJQUE9PT09PT1BRJCMvN0mlqKioqAA0NDQzLSYqNVNzfHV2dHZ0dnR2fXhyVDo4
|
||||
QUmjqKmpADMzMzEsGSo7h3+VlJSbk5uTm5OUj4CFiUJAQU2nqakAMzMzMSwZKz6Ig6GfnZ2dnZ2dnZyZ
|
||||
go6LRTRBTaepqQAzMzMwKBcrPY2Em5+goKCgoKCgn5iBjotFNEBNp6mpADMzMzEsGSs9jYSbnaCgoKCg
|
||||
oKCemIGOi0U0QU2nqakAMzMzMCgYKz2NhJudnaCgoKCgoJ+YgY6LRTRATaepqQAzMzMxLBkrPYiDm52g
|
||||
oKCgoKCgnpiBjotFNEFNp6mpADMzMzAoGCtViIShn52dnZ2dnZ2cmYKMi0U0QE2nqakAMzMzMSwZKzyH
|
||||
f5WUk5GRkZGRkZaPgIWJRTRDoqepqQA0NDQzLScqNlNzfHV3dnZ2dnZ2fXlyVDs5QUijp6ipAEFBQUAz
|
||||
LCccHSEFB05OTk5OTk4GBCAfHjJEoqaoqakAQ0NDQTQwJhcTDBsaGhoaGhoaGhoLDBMWLEOipqioqABJ
|
||||
SUlIQTEoFRQQDw8PDw8PDw8PDw8QEBUoNEiipqmpAElJSUhBMCYYFBQUFBQUFBQUFBQUFBQUFSYtM0FM
|
||||
p6jwAAA/8AAAP/AAAA/wAAAP8AAAD/AAAA/wAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA
|
||||
AAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA
|
||||
AAPwAAAP8AAADygAAAAQAAAAIAAAAAEAIAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx8
|
||||
fP9paWn/aWlp/2lpaf9paWn/aWlp/2lpaf9paWn/aWlp/2ZmZv+Pj4//AAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAB5eXn/09PT/9LS0v/S0tL/z8/P/7e3t/+5ubn/0tLS/83Nzf+BgYH/i4uL/4ODg/8AAAAAAAAAAAAA
|
||||
AAAAAAAAeHh4/9DQ0P/Gxsb/0NDQ/9HR0f+4uLj/tra2/8PDzP/Ozs//t7e3/5aWlv90dHT/AAAAAAAA
|
||||
AAAAAAAAAAAAAHZ2dv+QkJD/IyMj/6ysrP/Q0ND/0tLR/5iYx/8YGK//gICy/7i4vf+goKX/uLi4/4uL
|
||||
i/8AAAAAAAAAAAAAAABubm7/JCQk/xwcHP8lJSX/xsbG/9HR0f+YmMn/GBjS/3h4vv83N6z/Q0O6/76+
|
||||
w/+Li4v/AAAAAAAAAAAAAAAAeHh4/62trf8lJSX/u7u7/9DQ0P/R0dH/0dHR/8bG0/+6ur//OjrC/0JC
|
||||
2v++vsT/i4uL/wAAAAAAAAAAAAAAAHh4eP/R0dH/xsbG/9DQ0P/R0dH/0dHR/9HR0f/R0dH/0dHR/8rK
|
||||
0v/Ly9P/w8PD/4uLi/8AAAAAAAAAAAAAAAB5eXn/zc3N/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bG
|
||||
xv/Gxsb/x8fH/8PDw/+Li4v/AAAAAAAAAAAAAAAAc3Nz/2NjY/9NTk7/RlNQ/0VTUP9FU1D/RVNQ/0VT
|
||||
UP9FU1D/SlFP/09PT/+Ojo7/i4uL/wAAAAAAAAAAAAAAAGxsbP9RUVH/gY2K/xLSqP8K1qr/Ctaq/wrW
|
||||
qv8K1qr/Ctaq/0mvmf9/fn//YmJi/4yMjP8AAAAAAAAAAAAAAABsbGz/UFBQ/4CNiv8J1qr/ANus/wDb
|
||||
rP8A26z/ANus/wDbrP9EsZn/f35+/2JiYv+MjIz/AAAAAAAAAAAAAAAAbGxs/1BQUP+AjYr/Cdaq/wDb
|
||||
rP8A26z/ANus/wDbrP8A26z/RLGZ/39+fv9iYmL/jIyM/wAAAAAAAAAAAAAAAGxsbP9QUFD/gI2K/wnW
|
||||
qv8A26z/ANus/wDbrP8A26z/ANus/0Sxmf9/fn7/YmJi/4yMjP8AAAAAAAAAAAAAAABsbGz/UVFR/4GN
|
||||
iv8S0qj/Cteq/wrXqv8K16r/Cteq/wrXqv9Jr5n/f35+/2JiYv+MjIz/AAAAAAAAAAAAAAAAc3Nz/2Vl
|
||||
Zf9RUlL/SldU/0lXVP9JV1T/SVdU/0lXVP9JV1T/TlRT/1NTU/+Pj4//i4uL/wAAAAAAAAAAAAAAAHx8
|
||||
fP9iYmL/Wlpa/1paWv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1paWv9bW1v/ampq/wAAAAAAAAAAwAcAAMAD
|
||||
AADAAwAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAMAACgA
|
||||
AAAQAAAAIAAAAAEACAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAcHBz/IyMj/yQkJP8lJSX/TU5O/09P
|
||||
T/9KUU//RVNQ/0ZTUP9OVFP/SVdU/0pXVP9QUFD/UVFR/1FSUv9TU1P/Wlpa/1tbW/9iYmL/Y2Nj/2Vl
|
||||
Zf9mZmb/aWlp/2pqav9sbGz/bm5u/3Nzc/90dHT/dnZ2/3h4eP95eXn/fHx8/39+fv8YGK//Nzes/0ND
|
||||
uv94eL7/GBjS/zo6wv9CQtr/Sa+Z/0Sxmf8J1qr/Ctaq/wDbrP8S0qj/gYGB/4ODg/+AjYr/gY2K/4uL
|
||||
i/+MjIz/jo6O/4+Pj/+QkJD/lpaW/4CAsv+goKX/rKys/62trf+2trb/t7e3/7i4uP+5ubn/u7u7/7i4
|
||||
vf+6ur//mJjH/5iYyf++vsP/vr7E/8PDw//Gxsb/x8fH/8PDzP/Nzc3/zs7P/8/Pz//GxtP/ysrS/8vL
|
||||
0//Q0ND/0dHR/9LS0f/T09P//////wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
|
||||
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/VVUfFhYWFhYWFxYVNVVVVVVV
|
||||
HlRTU009P1NLLjIvVVVVVR1RSFFSPjxKTD03G1VVVVUcNgE6UVNDIThBOT4yVVVVGQIAA0hSRCUkIiNF
|
||||
MlVVVR07A0BRUlJOQiYnRjJVVVUdUkhRUlJSUlJPUEcyVVVVHktISEhISEhISElHMlVVVRoTBAgHBwcH
|
||||
BwYFNDJVVVUYDTEtKysrKysoIBIzVVVVGAwwKiwsLCwsKSASM1VVVRgMMCosLCwsLCkgEjNVVVUYDDAq
|
||||
LCwsLCwpIBIzVVVVGA0xLSsrKysrKCASM1VVVRoUDgsKCgoKCgkPNTJVVVUfEhAQEBAQEBAQERdVVcAH
|
||||
AADAAwAAwAMAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMAD
|
||||
AAA=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
|
@ -526,7 +526,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (_addr + j + DataSize <= _domain.Size)
|
||||
{
|
||||
rowStr.AppendFormat(_digitFormatString, MakeValue(_addr + j));
|
||||
int t_val = 0;
|
||||
int t_next = 0;
|
||||
|
||||
for (int k = 0; k < DataSize; k++)
|
||||
{
|
||||
t_next = MakeValue(1, _addr + j + k);
|
||||
t_val += (t_next << ((DataSize - k - 1) * 8));
|
||||
}
|
||||
|
||||
rowStr.AppendFormat(_digitFormatString, t_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -569,7 +578,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (Global.CheatList.IsActive(_domain, address))
|
||||
{
|
||||
return Global.CheatList.GetCheatValue(_domain, address, (WatchSize)DataSize ).Value;
|
||||
return Global.CheatList.GetCheatValue(_domain, address, (WatchSize)dataSize ).Value;
|
||||
}
|
||||
|
||||
switch (dataSize)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
@ -289,5 +290,74 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TastudioBranchInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public int Frame { get; set; }
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
[LuaMethod("getbranches", "Returns a list of the current tastudio branches. Each entry will have the Id, Frame, and Text properties of the branch")]
|
||||
public LuaTable GetBranches()
|
||||
{
|
||||
var table = Lua.NewTable();
|
||||
|
||||
if (Engaged())
|
||||
{
|
||||
var branches = Tastudio.CurrentTasMovie.Branches.Select(b => new
|
||||
{
|
||||
Id = b.UniqueIdentifier.ToString(),
|
||||
Frame = b.Frame,
|
||||
Text = b.UserText
|
||||
})
|
||||
.ToList();
|
||||
|
||||
for (int i = 0; i < branches.Count; i++)
|
||||
{
|
||||
table[i] = branches[i];
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
[LuaMethod("getbranchinput", "Gets the controller state of the given frame with the given branch identifier")]
|
||||
public LuaTable GetBranchInput(string branchId, int frame)
|
||||
{
|
||||
var table = Lua.NewTable();
|
||||
|
||||
if (Engaged())
|
||||
{
|
||||
if (Tastudio.CurrentTasMovie.Branches.Any(b => b.UniqueIdentifier.ToString() == branchId))
|
||||
{
|
||||
var branch = Tastudio.CurrentTasMovie.Branches.First(b => b.UniqueIdentifier.ToString() == branchId);
|
||||
if (frame < branch.InputLog.Count)
|
||||
{
|
||||
var input = branch.InputLog[frame];
|
||||
|
||||
var adapter = new Bk2ControllerAdapter
|
||||
{
|
||||
Definition = Global.MovieSession.MovieControllerAdapter.Definition
|
||||
};
|
||||
|
||||
adapter.SetControllersAsMnemonic(input);
|
||||
|
||||
foreach (var button in adapter.Definition.BoolButtons)
|
||||
{
|
||||
table[button] = adapter.IsPressed(button);
|
||||
}
|
||||
|
||||
foreach (var button in adapter.Definition.FloatControls)
|
||||
{
|
||||
table[button] = adapter.GetFloat(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
private bool _triggerAutoRestore; // If true, autorestore will be called on mouse up
|
||||
private bool? _autoRestorePaused = null;
|
||||
private int? _seekStartFrame = null;
|
||||
private bool _shouldUnpauseFromRewind = false;
|
||||
private bool _unpauseAfterSeeking = false;
|
||||
|
||||
private ControllerDefinition ControllerType => Global.MovieSession.MovieControllerAdapter.Definition;
|
||||
|
||||
|
@ -111,10 +111,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
Mainform.PauseOnFrame = null;
|
||||
if (_shouldUnpauseFromRewind)
|
||||
if (_unpauseAfterSeeking)
|
||||
{
|
||||
Mainform.UnpauseEmulator();
|
||||
_shouldUnpauseFromRewind = false;
|
||||
_unpauseAfterSeeking = false;
|
||||
}
|
||||
|
||||
if (CurrentTasMovie != null)
|
||||
|
@ -762,7 +762,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void TasView_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && !_supressContextMenu && TasView.SelectedRows.Any())
|
||||
if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader &&
|
||||
!_supressContextMenu && TasView.SelectedRows.Any() && !_leftButtonHeld)
|
||||
{
|
||||
if (Global.MovieSession.Movie.FrameCount < TasView.SelectedRows.Max())
|
||||
{
|
||||
|
|
|
@ -72,11 +72,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else if (ofd.FileName.EndsWith(".bkm") || ofd.FileName.EndsWith(".bk2")) // todo: proper extention iteration
|
||||
{
|
||||
Mainform.StartNewMovie(MovieService.Get(ofd.FileName), false);
|
||||
|
||||
var result1 = MessageBox.Show("This is a regular movie, a new project must be created from it, in order to use in TAStudio\nProceed?", "Convert movie", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
|
||||
if (result1 == DialogResult.OK)
|
||||
{
|
||||
Mainform.StartNewMovie(MovieService.Get(ofd.FileName), false);
|
||||
ConvertCurrentMovieToTasproj();
|
||||
StartNewMovieWrapper(false);
|
||||
SetUpColumns();
|
||||
|
|
|
@ -829,7 +829,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (frame == Emulator.Frame)
|
||||
return;
|
||||
|
||||
_shouldUnpauseFromRewind = fromRewinding && !Mainform.EmulatorPaused;
|
||||
_unpauseAfterSeeking = (fromRewinding || WasRecording) && !Mainform.EmulatorPaused;
|
||||
TastudioPlayMode();
|
||||
KeyValuePair<int, byte[]> closestState = CurrentTasMovie.TasStateManager.GetStateClosestToFrame(frame);
|
||||
if (closestState.Value != null && (frame < Emulator.Frame || closestState.Key > Emulator.Frame))
|
||||
|
@ -871,7 +871,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
// frame == Emulator.Frame when frame == 0
|
||||
if (frame > Emulator.Frame)
|
||||
{
|
||||
if (Mainform.EmulatorPaused || Mainform.IsSeeking || fromRewinding) // make seek frame keep up with emulation on fast scrolls
|
||||
// make seek frame keep up with emulation on fast scrolls
|
||||
if (Mainform.EmulatorPaused || Mainform.IsSeeking || fromRewinding || WasRecording)
|
||||
{
|
||||
StartSeeking(frame);
|
||||
}
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Atari.A7800Hawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
[Schema("A7800")]
|
||||
public class A7800HawkSchema : IVirtualPadSchema
|
||||
{
|
||||
private string UnpluggedControllerName => typeof(UnpluggedController).DisplayName();
|
||||
private string StandardControllerName => typeof(StandardController).DisplayName();
|
||||
private string ProLineControllerName => typeof(ProLineController).DisplayName();
|
||||
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
|
||||
{
|
||||
var A78SyncSettings = ((A7800Hawk)core).GetSyncSettings().Clone();
|
||||
var port1 = A78SyncSettings.Port1;
|
||||
var port2 = A78SyncSettings.Port2;
|
||||
|
||||
if (port1 == StandardControllerName)
|
||||
{
|
||||
yield return JoystickController(1);
|
||||
}
|
||||
|
||||
if (port2 == StandardControllerName)
|
||||
{
|
||||
yield return JoystickController(2);
|
||||
}
|
||||
|
||||
if (port1 == ProLineControllerName)
|
||||
{
|
||||
yield return ProLineController(1);
|
||||
}
|
||||
|
||||
if (port2 == ProLineControllerName)
|
||||
{
|
||||
yield return ProLineController(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static PadSchema ProLineController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Player " + 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 + " Trigger",
|
||||
DisplayName = "1",
|
||||
Location = new Point(120, 24),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Trigger 2",
|
||||
DisplayName = "2",
|
||||
Location = new Point(145, 24),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema JoystickController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Player " + 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 + " Trigger",
|
||||
DisplayName = "1",
|
||||
Location = new Point(120, 24),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema PaddleController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Player " + controller,
|
||||
IsConsole = false,
|
||||
DefaultSize = new Size(250, 74),
|
||||
Buttons = new[]
|
||||
{
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Paddle",
|
||||
DisplayName = "Paddle",
|
||||
Location = new Point(23, 15),
|
||||
Type = PadSchema.PadInputType.FloatSingle
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Trigger",
|
||||
DisplayName = "1",
|
||||
Location = new Point(12, 90),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema LightGunController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Light Gun",
|
||||
IsConsole = false,
|
||||
DefaultSize = new Size(356, 290),
|
||||
MaxSize = new Size(356, 290),
|
||||
Buttons = new[]
|
||||
{
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " VPos",
|
||||
Location = new Point(14, 17),
|
||||
Type = PadSchema.PadInputType.TargetedPair,
|
||||
TargetSize = new Size(256, 240),
|
||||
SecondaryNames = new[]
|
||||
{
|
||||
"P" + controller + " HPos",
|
||||
}
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "P" + controller + " Trigger",
|
||||
DisplayName = "Trigger",
|
||||
Location = new Point(284, 17),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema ConsoleButtons()
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Console",
|
||||
IsConsole = true,
|
||||
DefaultSize = new Size(215, 50),
|
||||
Buttons = new[]
|
||||
{
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Select",
|
||||
DisplayName = "Select",
|
||||
Location = new Point(10, 15),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Reset",
|
||||
DisplayName = "Reset",
|
||||
Location = new Point(60, 15),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Power",
|
||||
DisplayName = "Power",
|
||||
Location = new Point(108, 15),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "Pause",
|
||||
DisplayName = "Pause",
|
||||
Location = new Point(158, 15),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
},
|
||||
new PadSchema.ButtonSchema
|
||||
{
|
||||
Name = "BW",
|
||||
DisplayName = "BW",
|
||||
Location = new Point(158, 15),
|
||||
Type = PadSchema.PadInputType.Boolean
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
using System.Drawing;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Atari.Atari7800;
|
||||
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Cores.Atari.A7800Hawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -11,33 +13,42 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
|
||||
{
|
||||
switch (((Atari7800)core).ControlAdapter.ControlType.Name)
|
||||
return Atari7800HawkSchema.GetPadSchemas((A7800Hawk)core);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Atari7800HawkSchema
|
||||
{
|
||||
private static string UnpluggedControllerName => typeof(UnpluggedController).DisplayName();
|
||||
private static string StandardControllerName => typeof(StandardController).DisplayName();
|
||||
private static string ProLineControllerName => typeof(ProLineController).DisplayName();
|
||||
|
||||
public static IEnumerable<PadSchema> GetPadSchemas(A7800Hawk core)
|
||||
{
|
||||
var A78SyncSettings = core.GetSyncSettings().Clone();
|
||||
var port1 = A78SyncSettings.Port1;
|
||||
var port2 = A78SyncSettings.Port2;
|
||||
|
||||
if (port1 == StandardControllerName)
|
||||
{
|
||||
case "Atari 7800 Joystick Controller":
|
||||
yield return JoystickController(1);
|
||||
yield return JoystickController(2);
|
||||
break;
|
||||
case "Atari 7800 Paddle Controller":
|
||||
yield return PaddleController(1);
|
||||
yield return PaddleController(2);
|
||||
break;
|
||||
case "Atari 7800 Keypad Controller":
|
||||
break;
|
||||
case "Atari 7800 Driving Controller":
|
||||
break;
|
||||
case "Atari 7800 Booster Grip Controller":
|
||||
break;
|
||||
case "Atari 7800 ProLine Joystick Controller":
|
||||
yield return ProLineController(1);
|
||||
yield return ProLineController(2);
|
||||
break;
|
||||
case "Atari 7800 Light Gun Controller":
|
||||
yield return LightGunController(1);
|
||||
yield return LightGunController(2);
|
||||
break;
|
||||
yield return JoystickController(1);
|
||||
}
|
||||
|
||||
if (port2 == StandardControllerName)
|
||||
{
|
||||
yield return JoystickController(2);
|
||||
}
|
||||
|
||||
if (port1 == ProLineControllerName)
|
||||
{
|
||||
yield return ProLineController(1);
|
||||
}
|
||||
|
||||
if (port2 == ProLineControllerName)
|
||||
{
|
||||
yield return ProLineController(2);
|
||||
}
|
||||
|
||||
yield return ConsoleButtons();
|
||||
}
|
||||
|
||||
private static PadSchema ProLineController(int controller)
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
<Compile Include="Interfaces\IEmulatorServiceProvider.cs" />
|
||||
<Compile Include="Interfaces\Services\IBoardInfo.cs" />
|
||||
<Compile Include="Interfaces\Services\ICreateGameDBEntries.cs" />
|
||||
<Compile Include="Interfaces\Services\ICycleTiming.cs" />
|
||||
<Compile Include="Interfaces\Services\ISoundProvider.cs" />
|
||||
<Compile Include="Interfaces\Services\ICodeDataLogger.cs" />
|
||||
<Compile Include="Interfaces\Services\IDebuggable.cs" />
|
||||
|
|
|
@ -20,6 +20,20 @@ namespace BizHawk.Emulation.Common
|
|||
}
|
||||
}
|
||||
|
||||
public class NoAvailableCoreException : Exception
|
||||
{
|
||||
public NoAvailableCoreException()
|
||||
: base("System is currently NOT emulated")
|
||||
{
|
||||
}
|
||||
|
||||
public NoAvailableCoreException(string message)
|
||||
: base ("System is currently NOT emulated: " + message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class CGBNotSupportedException : Exception
|
||||
{
|
||||
public CGBNotSupportedException()
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Common
|
||||
{
|
||||
public interface ICycleTiming
|
||||
{
|
||||
/// <summary>
|
||||
/// Total elapsed emulation time relative to <see cref="ClockRate"/>
|
||||
/// </summary>
|
||||
long CycleCount { get; }
|
||||
/// <summary>
|
||||
/// Clock Rate in hz for <see cref="CycleCount"/>
|
||||
/// </summary>
|
||||
double ClockRate { get; }
|
||||
}
|
||||
}
|
|
@ -63,9 +63,6 @@
|
|||
<Reference Include="ELFSharp">
|
||||
<HintPath>..\References\ELFSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EMU7800">
|
||||
<HintPath>..\References\EMU7800.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\References\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -368,30 +365,10 @@
|
|||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\M6532.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\Maria.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\Pokey.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\Tia.Audio.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\TIA.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\Tia.ISoundProvider.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\Tia.SyncState.cs" />
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.cs" />
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.IDebuggable.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.IEmulator.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.IInputPollable.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.IMemoryDomains.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.IStatable.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800Control.cs" />
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.ISaveRam.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\lynx\LibLynx.cs" />
|
||||
<Compile Include="Consoles\Atari\lynx\Lynx.cs" />
|
||||
<Compile Include="Consoles\Atari\lynx\Lynx.IInputPollable.cs">
|
||||
|
@ -486,6 +463,9 @@
|
|||
<Compile Include="Consoles\Nintendo\Gameboy\Gambatte.IEmulator.cs">
|
||||
<DependentUpon>Gambatte.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\Gambatte.ILinkable.cs">
|
||||
<DependentUpon>Gambatte.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\Gambatte.IMemoryDomains.cs">
|
||||
<DependentUpon>Gambatte.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -535,6 +515,7 @@
|
|||
<Compile Include="Consoles\Nintendo\Gameboy\GambatteLink.IVideoProvider.cs">
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GambattePrinter.cs" />
|
||||
<Compile Include="Consoles\Nintendo\Gameboy\GamebatteLink.ISoundProvider.cs">
|
||||
<DependentUpon>GambatteLink.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -771,6 +752,7 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper049.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper052.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper074.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper114.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper115.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper121.cs" />
|
||||
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper123.cs" />
|
||||
|
@ -899,6 +881,9 @@
|
|||
<Compile Include="Consoles\Nintendo\NES\NES.IDriveLight.cs">
|
||||
<DependentUpon>NES.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\NES.ICodeDataLogger.cs">
|
||||
<DependentUpon>NES.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\NES\NES.IInputPollable.cs">
|
||||
<DependentUpon>NES.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -1090,6 +1075,8 @@
|
|||
<Compile Include="Consoles\Sega\Saturn\LibSaturnus.cs" />
|
||||
<Compile Include="Consoles\Sega\Saturn\Saturnus.cs" />
|
||||
<Compile Include="Consoles\Sega\Saturn\SaturnusControllerDeck.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\EEPROM.93c46.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\MemoryMap.EEPROM.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\SMS.cs" />
|
||||
<Compile Include="Consoles\Sega\SMS\SMS.ICodeDataLogger.cs">
|
||||
<DependentUpon>SMS.cs</DependentUpon>
|
||||
|
@ -1205,12 +1192,14 @@
|
|||
<Compile Include="CPUs\Z80-GB\Registers.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Tables.cs" />
|
||||
<Compile Include="CPUs\Z80-GB\Z80.cs" />
|
||||
<Compile Include="CPUs\Z80\Disassembler.cs" />
|
||||
<Compile Include="CPUs\Z80\Execute.cs" />
|
||||
<Compile Include="CPUs\Z80\Interrupts.cs" />
|
||||
<Compile Include="CPUs\Z80\Registers.cs" />
|
||||
<Compile Include="CPUs\Z80\Tables.cs" />
|
||||
<Compile Include="CPUs\Z80\Z80A.cs" />
|
||||
<Compile Include="CPUs\Z80A\NewDisassembler.cs" />
|
||||
<Compile Include="CPUs\Z80A\Execute.cs" />
|
||||
<Compile Include="CPUs\Z80A\Interrupts.cs" />
|
||||
<Compile Include="CPUs\Z80A\Registers.cs" />
|
||||
<Compile Include="CPUs\Z80A\Operations.cs" />
|
||||
<Compile Include="CPUs\Z80A\Tables_Direct.cs" />
|
||||
<Compile Include="CPUs\Z80A\Tables_Indirect.cs" />
|
||||
<Compile Include="CPUs\Z80A\Z80A.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
private bool iff1;
|
||||
public bool IFF1 { get { return iff1; } set { iff1 = value; } }
|
||||
|
||||
private bool iff2;
|
||||
public bool IFF2 { get { return iff2; } set { iff2 = value; } }
|
||||
|
||||
private bool interrupt;
|
||||
public bool Interrupt { get { return interrupt; } set { interrupt = value; } }
|
||||
|
||||
private bool nonMaskableInterrupt;
|
||||
public bool NonMaskableInterrupt
|
||||
{
|
||||
get { return nonMaskableInterrupt; }
|
||||
set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; }
|
||||
}
|
||||
|
||||
private bool nonMaskableInterruptPending;
|
||||
public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } }
|
||||
|
||||
private int interruptMode;
|
||||
public int InterruptMode
|
||||
{
|
||||
get { return interruptMode; }
|
||||
set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; }
|
||||
}
|
||||
|
||||
private bool halted;
|
||||
public bool Halted { get { return halted; } set { halted = value; } }
|
||||
|
||||
public Action IRQCallback = delegate() { };
|
||||
public Action NMICallback = delegate() { };
|
||||
|
||||
private void ResetInterrupts()
|
||||
{
|
||||
IFF1 = false;
|
||||
IFF2 = false;
|
||||
Interrupt = false;
|
||||
NonMaskableInterrupt = false;
|
||||
NonMaskableInterruptPending = false;
|
||||
InterruptMode = 1;
|
||||
Halted = false;
|
||||
}
|
||||
|
||||
private void Halt()
|
||||
{
|
||||
Halted = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
[Serializable()]
|
||||
public struct RegisterPair
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public ushort Word;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public byte Low;
|
||||
|
||||
[FieldOffset(1)]
|
||||
public byte High;
|
||||
|
||||
public RegisterPair(ushort value)
|
||||
{
|
||||
Word = value;
|
||||
Low = (byte)(Word);
|
||||
High = (byte)(Word >> 8);
|
||||
}
|
||||
|
||||
public static implicit operator ushort(RegisterPair rp)
|
||||
{
|
||||
return rp.Word;
|
||||
}
|
||||
|
||||
public static implicit operator RegisterPair(ushort value)
|
||||
{
|
||||
return new RegisterPair(value);
|
||||
}
|
||||
}
|
||||
|
||||
private bool RegFlagC
|
||||
{
|
||||
get { return (RegAF.Low & 0x01) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x01) | (value ? 0x01 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlagN
|
||||
{
|
||||
get { return (RegAF.Low & 0x02) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x02) | (value ? 0x02 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlagP
|
||||
{
|
||||
get { return (RegAF.Low & 0x04) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x04) | (value ? 0x04 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlag3
|
||||
{
|
||||
get { return (RegAF.Low & 0x08) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x08) | (value ? 0x08 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlagH
|
||||
{
|
||||
get { return (RegAF.Low & 0x10) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x10) | (value ? 0x10 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlag5
|
||||
{
|
||||
get { return (RegAF.Low & 0x20) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x20) | (value ? 0x20 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlagZ
|
||||
{
|
||||
get { return (RegAF.Low & 0x40) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x40) | (value ? 0x40 : 0x00)); }
|
||||
}
|
||||
|
||||
private bool RegFlagS
|
||||
{
|
||||
get { return (RegAF.Low & 0x80) != 0; }
|
||||
set { RegAF.Low = (byte)((RegAF.Low & ~0x80) | (value ? 0x80 : 0x00)); }
|
||||
}
|
||||
|
||||
private RegisterPair RegAF;
|
||||
private RegisterPair RegBC;
|
||||
private RegisterPair RegDE;
|
||||
private RegisterPair RegHL;
|
||||
private RegisterPair RegWZ;
|
||||
|
||||
private RegisterPair RegAltAF; // Shadow for A and F
|
||||
private RegisterPair RegAltBC; // Shadow for B and C
|
||||
private RegisterPair RegAltDE; // Shadow for D and E
|
||||
private RegisterPair RegAltHL; // Shadow for H and L
|
||||
// NOTE: There is no AltWZ register (despite it being shown on various block diagrams)
|
||||
|
||||
private byte RegI; // I (interrupt vector)
|
||||
private byte RegR; // R (memory refresh)
|
||||
|
||||
private RegisterPair RegIX; // IX (index register x)
|
||||
private RegisterPair RegIY; // IY (index register y)
|
||||
|
||||
private RegisterPair RegSP; // SP (stack pointer)
|
||||
private RegisterPair RegPC; // PC (program counter)
|
||||
|
||||
private void ResetRegisters()
|
||||
{
|
||||
// Clear main registers
|
||||
RegAF = 0; RegBC = 0; RegDE = 0; RegHL = 0; RegWZ = 0;
|
||||
// Clear alternate registers
|
||||
RegAltAF = 0; RegAltBC = 0; RegAltDE = 0; RegAltHL = 0;
|
||||
// Clear special purpose registers
|
||||
RegI = 0; RegR = 0;
|
||||
RegIX.Word = 0; RegIY.Word = 0;
|
||||
RegSP.Word = 0; RegPC.Word = 0;
|
||||
}
|
||||
|
||||
public byte RegisterA
|
||||
{
|
||||
get { return RegAF.High; }
|
||||
set { RegAF.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterF
|
||||
{
|
||||
get { return RegAF.Low; }
|
||||
set { RegAF.Low = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterAF
|
||||
{
|
||||
get { return RegAF.Word; }
|
||||
set { RegAF.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterB
|
||||
{
|
||||
get { return RegBC.High; }
|
||||
set { RegBC.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterC
|
||||
{
|
||||
get { return RegBC.Low; }
|
||||
set { RegBC.Low = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterBC
|
||||
{
|
||||
get { return RegBC.Word; }
|
||||
set { RegBC.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterD
|
||||
{
|
||||
get { return RegDE.High; }
|
||||
set { RegDE.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterE
|
||||
{
|
||||
get { return RegDE.Low; }
|
||||
set { RegDE.Low = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterDE
|
||||
{
|
||||
get { return RegDE.Word; }
|
||||
set { RegDE.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterH
|
||||
{
|
||||
get { return RegHL.High; }
|
||||
set { RegHL.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterL
|
||||
{
|
||||
get { return RegHL.Low; }
|
||||
set { RegHL.Low = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterHL
|
||||
{
|
||||
get { return RegHL.Word; }
|
||||
set { RegHL.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterW
|
||||
{
|
||||
get { return RegWZ.High; }
|
||||
set { RegWZ.High = value; }
|
||||
}
|
||||
|
||||
public byte RegisterZ
|
||||
{
|
||||
get { return RegWZ.Low; }
|
||||
set { RegWZ.Low = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterWZ
|
||||
{
|
||||
get { return RegWZ.Word; }
|
||||
set { RegWZ.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterPC
|
||||
{
|
||||
get { return RegPC.Word; }
|
||||
set { RegPC.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterSP
|
||||
{
|
||||
get { return RegSP.Word; }
|
||||
set { RegSP.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterIX
|
||||
{
|
||||
get { return RegIX.Word; }
|
||||
set { RegIX.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterIY
|
||||
{
|
||||
get { return RegIY.Word; }
|
||||
set { RegIY.Word = value; }
|
||||
}
|
||||
|
||||
public byte RegisterI
|
||||
{
|
||||
get { return RegI; }
|
||||
set { RegI = value; }
|
||||
}
|
||||
|
||||
public byte RegisterR
|
||||
{
|
||||
get { return RegR; }
|
||||
set { RegR = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterShadowAF
|
||||
{
|
||||
get { return RegAltAF.Word; }
|
||||
set { RegAltAF.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterShadowBC
|
||||
{
|
||||
get { return RegAltBC.Word; }
|
||||
set { RegAltBC.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterShadowDE
|
||||
{
|
||||
get { return RegAltDE.Word; }
|
||||
set { RegAltDE.Word = value; }
|
||||
}
|
||||
|
||||
public ushort RegisterShadowHL
|
||||
{
|
||||
get { return RegAltHL.Word; }
|
||||
set { RegAltHL.Word = value; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,331 +0,0 @@
|
|||
namespace BizHawk.Emulation.Cores.Components.Z80
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
private void InitialiseTables()
|
||||
{
|
||||
InitTableInc();
|
||||
InitTableDec();
|
||||
InitTableParity();
|
||||
InitTableALU();
|
||||
InitTableRotShift();
|
||||
InitTableHalfBorrow();
|
||||
InitTableHalfCarry();
|
||||
InitTableNeg();
|
||||
InitTableDaa();
|
||||
}
|
||||
|
||||
private byte[] TableInc;
|
||||
private void InitTableInc()
|
||||
{
|
||||
TableInc = new byte[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
TableInc[i] = FlagByte(false, false, i == 0x80, UndocumentedX(i), (i & 0xF) == 0x0, UndocumentedY(i), i == 0, i > 127);
|
||||
}
|
||||
|
||||
private byte[] TableDec;
|
||||
private void InitTableDec()
|
||||
{
|
||||
TableDec = new byte[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
TableDec[i] = FlagByte(false, true, i == 0x7F, UndocumentedX(i), (i & 0xF) == 0xF, UndocumentedY(i), i == 0, i > 127);
|
||||
}
|
||||
|
||||
private bool[] TableParity;
|
||||
private void InitTableParity()
|
||||
{
|
||||
TableParity = new bool[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int Bits = 0;
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
Bits += (i >> j) & 1;
|
||||
}
|
||||
TableParity[i] = (Bits & 1) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
private ushort[, , ,] TableALU;
|
||||
private void InitTableALU()
|
||||
{
|
||||
TableALU = new ushort[8, 256, 256, 2]; // Class, OP1, OP2, Carry
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
for (int op1 = 0; op1 < 256; ++op1)
|
||||
{
|
||||
for (int op2 = 0; op2 < 256; ++op2)
|
||||
{
|
||||
for (int c = 0; c < 2; ++c)
|
||||
{
|
||||
|
||||
int ac = (i == 1 || i == 3) ? c : 0;
|
||||
|
||||
bool S = false;
|
||||
bool Z = false;
|
||||
bool C = false;
|
||||
bool H = false;
|
||||
bool N = false;
|
||||
bool P = false;
|
||||
|
||||
byte result_b = 0;
|
||||
int result_si = 0;
|
||||
int result_ui = 0;
|
||||
|
||||
// Fetch result
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
result_si = (sbyte)op1 + (sbyte)op2 + ac;
|
||||
result_ui = op1 + op2 + ac;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 7:
|
||||
result_si = (sbyte)op1 - (sbyte)op2 - ac;
|
||||
result_ui = op1 - op2 - ac;
|
||||
break;
|
||||
case 4:
|
||||
result_si = op1 & op2;
|
||||
break;
|
||||
case 5:
|
||||
result_si = op1 ^ op2;
|
||||
break;
|
||||
case 6:
|
||||
result_si = op1 | op2;
|
||||
break;
|
||||
}
|
||||
|
||||
result_b = (byte)result_si;
|
||||
|
||||
// Parity/Carry
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 7:
|
||||
P = result_si < -128 || result_si > 127;
|
||||
C = result_ui < 0 || result_ui > 255;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
P = TableParity[result_b];
|
||||
C = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Subtraction
|
||||
N = i == 2 || i == 3 || i == 7;
|
||||
|
||||
// Half carry
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
H = ((op1 & 0xF) + (op2 & 0xF) + (ac & 0xF)) > 0xF;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 7:
|
||||
H = ((op1 & 0xF) - (op2 & 0xF) - (ac & 0xF)) < 0x0;
|
||||
break;
|
||||
case 4:
|
||||
H = true;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
H = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Undocumented
|
||||
byte UndocumentedFlags = (byte)(result_b & 0x28);
|
||||
if (i == 7) UndocumentedFlags = (byte)(op2 & 0x28);
|
||||
|
||||
S = result_b > 127;
|
||||
Z = result_b == 0;
|
||||
|
||||
if (i == 7) result_b = (byte)op1;
|
||||
|
||||
TableALU[i, op1, op2, c] = (ushort)(
|
||||
result_b * 256 +
|
||||
((C ? 0x01 : 0) + (N ? 0x02 : 0) + (P ? 0x04 : 0) + (H ? 0x10 : 0) + (Z ? 0x40 : 0) + (S ? 0x80 : 0)) +
|
||||
(UndocumentedFlags));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool[,] TableHalfBorrow;
|
||||
private void InitTableHalfBorrow()
|
||||
{
|
||||
TableHalfBorrow = new bool[256, 256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
TableHalfBorrow[i, j] = ((i & 0xF) - (j & 0xF)) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool[,] TableHalfCarry;
|
||||
private void InitTableHalfCarry()
|
||||
{
|
||||
TableHalfCarry = new bool[256, 256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
for (int j = 0; j < 256; j++)
|
||||
{
|
||||
TableHalfCarry[i, j] = ((i & 0xF) + (j & 0xF)) > 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ushort[, ,] TableRotShift;
|
||||
private void InitTableRotShift()
|
||||
{
|
||||
TableRotShift = new ushort[2, 8, 65536]; // All, operation, AF
|
||||
for (int all = 0; all < 2; all++)
|
||||
{
|
||||
for (int y = 0; y < 8; ++y)
|
||||
{
|
||||
for (int af = 0; af < 65536; af++)
|
||||
{
|
||||
byte Old = (byte)(af >> 8);
|
||||
bool OldCarry = (af & 0x01) != 0;
|
||||
|
||||
ushort newAf = (ushort)(af & ~(0x13)); // Clear HALF-CARRY, SUBTRACT and CARRY flags
|
||||
|
||||
byte New = Old;
|
||||
if ((y & 1) == 0)
|
||||
{
|
||||
if ((Old & 0x80) != 0) ++newAf;
|
||||
|
||||
New <<= 1;
|
||||
|
||||
if ((y & 0x04) == 0)
|
||||
{
|
||||
if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((y & 0x02) != 0) New |= 0x01;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if ((Old & 0x01) != 0) ++newAf;
|
||||
|
||||
New >>= 1;
|
||||
|
||||
if ((y & 0x04) == 0)
|
||||
{
|
||||
if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((y & 0x02) == 0) New |= (byte)(Old & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
newAf &= 0xFF;
|
||||
newAf |= (ushort)(New * 256);
|
||||
|
||||
if (all == 1)
|
||||
{
|
||||
newAf &= unchecked((ushort)~0xC4); // Clear S, Z, P
|
||||
if (New > 127) newAf |= 0x80;
|
||||
if (New == 0) newAf |= 0x40;
|
||||
if (TableParity[New]) newAf |= 0x04;
|
||||
}
|
||||
|
||||
TableRotShift[all, y, af] = (ushort)((newAf & ~0x28) | ((newAf >> 8) & 0x28));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ushort[] TableNeg;
|
||||
private void InitTableNeg()
|
||||
{
|
||||
TableNeg = new ushort[65536];
|
||||
for (int af = 0; af < 65536; af++)
|
||||
{
|
||||
ushort raf = 0;
|
||||
byte b = (byte)(af >> 8);
|
||||
byte a = (byte)-b;
|
||||
raf |= (ushort)(a * 256);
|
||||
raf |= FlagByte(b != 0x00, true, b == 0x80, UndocumentedX(a), TableHalfCarry[a, b], UndocumentedY(a), a == 0, a > 127);
|
||||
TableNeg[af] = raf;
|
||||
}
|
||||
}
|
||||
|
||||
private ushort[] TableDaa;
|
||||
private void InitTableDaa()
|
||||
{
|
||||
TableDaa = new ushort[65536];
|
||||
for (int af = 0; af < 65536; ++af)
|
||||
{
|
||||
byte a = (byte)(af >> 8);
|
||||
byte tmp = a;
|
||||
|
||||
if (IsN(af))
|
||||
{
|
||||
if (IsH(af) || ((a & 0x0F) > 0x09)) tmp -= 0x06;
|
||||
if (IsC(af) || a > 0x99) tmp -= 0x60;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsH(af) || ((a & 0x0F) > 0x09)) tmp += 0x06;
|
||||
if (IsC(af) || a > 0x99) tmp += 0x60;
|
||||
}
|
||||
|
||||
TableDaa[af] = (ushort)((tmp * 256) + FlagByte(IsC(af) || a > 0x99, IsN(af), TableParity[tmp], UndocumentedX(tmp), ((a ^ tmp) & 0x10) != 0, UndocumentedY(tmp), tmp == 0, tmp > 127));
|
||||
}
|
||||
}
|
||||
|
||||
private byte FlagByte(bool C, bool N, bool P, bool X, bool H, bool Y, bool Z, bool S)
|
||||
{
|
||||
return (byte)(
|
||||
(C ? 0x01 : 0) +
|
||||
(N ? 0x02 : 0) +
|
||||
(P ? 0x04 : 0) +
|
||||
(X ? 0x08 : 0) +
|
||||
(H ? 0x10 : 0) +
|
||||
(Y ? 0x20 : 0) +
|
||||
(Z ? 0x40 : 0) +
|
||||
(S ? 0x80 : 0)
|
||||
);
|
||||
}
|
||||
|
||||
private bool UndocumentedX(int value)
|
||||
{
|
||||
return (value & 0x08) != 0;
|
||||
}
|
||||
|
||||
private bool UndocumentedY(int value)
|
||||
{
|
||||
return (value & 0x20) != 0;
|
||||
}
|
||||
|
||||
private bool IsC(int value) { return (value & 0x01) != 0; }
|
||||
private bool IsN(int value) { return (value & 0x02) != 0; }
|
||||
private bool IsP(int value) { return (value & 0x04) != 0; }
|
||||
private bool IsX(int value) { return (value & 0x08) != 0; }
|
||||
private bool IsH(int value) { return (value & 0x10) != 0; }
|
||||
private bool IsY(int value) { return (value & 0x20) != 0; }
|
||||
private bool IsZ(int value) { return (value & 0x40) != 0; }
|
||||
private bool IsS(int value) { return (value & 0x80) != 0; }
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
// This Z80 emulator is a modified version of Ben Ryves 'Brazil' emulator.
|
||||
// It is MIT licensed.
|
||||
|
||||
// for WZ register details, see: http://www.grimware.org/lib/exe/fetch.php/documentations/devices/z80/z80.memptr.eng.txt
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80
|
||||
{
|
||||
public sealed partial class Z80A
|
||||
{
|
||||
public Z80A()
|
||||
{
|
||||
InitialiseTables();
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
PendingCycles = 0;
|
||||
ExpectedExecutedCycles = 0;
|
||||
TotalExecutedCycles = 0;
|
||||
}
|
||||
|
||||
public void SoftReset()
|
||||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
}
|
||||
|
||||
// Memory Access
|
||||
|
||||
public Func<ushort, bool, byte> FetchMemory;
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
public Action<ushort, byte> WriteMemory;
|
||||
|
||||
public byte ReadMemoryWrapper(ushort addr)
|
||||
{
|
||||
if (MemoryCallbacks != null)
|
||||
{
|
||||
MemoryCallbacks.CallReads(addr, "System Bus");
|
||||
}
|
||||
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public byte FetchFirstMemoryWrapper(ushort addr)
|
||||
{
|
||||
if (MemoryCallbacks != null)
|
||||
{
|
||||
MemoryCallbacks.CallReads(addr, "System Bus");
|
||||
}
|
||||
|
||||
if (FetchMemory != null)
|
||||
{
|
||||
return FetchMemory(addr, true);
|
||||
}
|
||||
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public byte FetchMemoryWrapper(ushort addr)
|
||||
{
|
||||
if (MemoryCallbacks != null)
|
||||
{
|
||||
MemoryCallbacks.CallReads(addr, "System Bus");
|
||||
}
|
||||
|
||||
if (FetchMemory != null)
|
||||
{
|
||||
return FetchMemory(addr, false);
|
||||
}
|
||||
|
||||
return ReadMemory(addr);
|
||||
}
|
||||
|
||||
public void WriteMemoryWrapper(ushort addr, byte value)
|
||||
{
|
||||
if (MemoryCallbacks != null)
|
||||
{
|
||||
MemoryCallbacks.CallWrites(addr, "System Bus");
|
||||
}
|
||||
|
||||
WriteMemory(addr, value);
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; set; }
|
||||
|
||||
// Utility function, not used by core
|
||||
public ushort ReadWord(ushort addr)
|
||||
{
|
||||
ushort value = ReadMemory(addr++);
|
||||
value |= (ushort)(ReadMemory(addr) << 8);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Hardware I/O Port Access
|
||||
|
||||
public Func<ushort, byte> ReadHardware;
|
||||
public Action<ushort, byte> WriteHardware;
|
||||
|
||||
// State Save/Load
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Z80");
|
||||
ser.Sync("AF", ref RegAF.Word);
|
||||
ser.Sync("BC", ref RegBC.Word);
|
||||
ser.Sync("DE", ref RegDE.Word);
|
||||
ser.Sync("HL", ref RegHL.Word);
|
||||
ser.Sync("WZ", ref RegWZ.Word);
|
||||
ser.Sync("ShadowAF", ref RegAltAF.Word);
|
||||
ser.Sync("ShadowBC", ref RegAltBC.Word);
|
||||
ser.Sync("ShadowDE", ref RegAltDE.Word);
|
||||
ser.Sync("ShadowHL", ref RegAltHL.Word);
|
||||
ser.Sync("I", ref RegI);
|
||||
ser.Sync("R", ref RegR);
|
||||
ser.Sync("IX", ref RegIX.Word);
|
||||
ser.Sync("IY", ref RegIY.Word);
|
||||
ser.Sync("SP", ref RegSP.Word);
|
||||
ser.Sync("PC", ref RegPC.Word);
|
||||
ser.Sync("IRQ", ref interrupt);
|
||||
ser.Sync("NMI", ref nonMaskableInterrupt);
|
||||
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
|
||||
ser.Sync("IM", ref interruptMode);
|
||||
ser.Sync("IFF1", ref iff1);
|
||||
ser.Sync("IFF2", ref iff2);
|
||||
ser.Sync("Halted", ref halted);
|
||||
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
|
||||
ser.Sync("PendingCycles", ref pendingCycles);
|
||||
ser.Sync("EI_pending", ref EI_pending);
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80A
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
private bool iff1;
|
||||
public bool IFF1 { get { return iff1; } set { iff1 = value; } }
|
||||
|
||||
private bool iff2;
|
||||
public bool IFF2 { get { return iff2; } set { iff2 = value; } }
|
||||
|
||||
private bool nonMaskableInterrupt;
|
||||
public bool NonMaskableInterrupt
|
||||
{
|
||||
get { return nonMaskableInterrupt; }
|
||||
set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; }
|
||||
}
|
||||
|
||||
private bool nonMaskableInterruptPending;
|
||||
public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } }
|
||||
|
||||
private int interruptMode;
|
||||
public int InterruptMode
|
||||
{
|
||||
get { return interruptMode; }
|
||||
set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; }
|
||||
}
|
||||
|
||||
public Action IRQCallback = delegate () { };
|
||||
public Action NMICallback = delegate () { };
|
||||
|
||||
private void NMI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
ASGN, PCl, 0x66,
|
||||
ASGN, PCh, 0,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// Mode 0 interrupts only take effect if a CALL or RST is on the data bus
|
||||
// Otherwise operation just continues as normal
|
||||
// For now assume a NOP is on the data bus, in which case no stack operations occur
|
||||
|
||||
//NOTE: TODO: When a CALL is present on the data bus, adjust WZ accordingly
|
||||
private void INTERRUPT_0(ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// Just jump to $0038
|
||||
private void INTERRUPT_1()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
ASGN, PCl, 0x38,
|
||||
IDLE,
|
||||
ASGN, PCh, 0,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCh,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
ASGN, PCl, 0,
|
||||
TR, PCh, I,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60};
|
||||
|
||||
private void ResetInterrupts()
|
||||
{
|
||||
IFF1 = false;
|
||||
IFF2 = false;
|
||||
NonMaskableInterrupt = false;
|
||||
NonMaskableInterruptPending = false;
|
||||
FlagI = false;
|
||||
InterruptMode = 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,114 +1,27 @@
|
|||
//http://www.zophar.net/fileuploads/2/10819kouzv/z80undoc.html
|
||||
|
||||
//TODO: ex. (IX+00h) could be turned into (IX)
|
||||
|
||||
//usage:
|
||||
//VgMuseum.Z80.Disassembler disasm = new Disassembler();
|
||||
//ushort pc = RegPC.Word;
|
||||
//string str = disasm.Disassemble(() => ReadMemory(pc++));
|
||||
//Console.WriteLine(str);
|
||||
|
||||
//please note that however much youre tempted to, timings can't be put in a table here because they depend on how the instruction executes at runtime
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80A
|
||||
{
|
||||
public class Disassembler : IDisassemblable
|
||||
public sealed partial class Z80A : IDisassemblable
|
||||
{
|
||||
readonly static sbyte[,] opcodeSizes = new sbyte[7, 256];
|
||||
|
||||
public static void GenerateOpcodeSizes()
|
||||
{
|
||||
Disassembler disasm = new Disassembler();
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[0, i] = (sbyte)pc;
|
||||
}
|
||||
|
||||
opcodeSizes[0, 0xCB] = -1;
|
||||
opcodeSizes[0, 0xED] = -2;
|
||||
opcodeSizes[0, 0xDD] = -3;
|
||||
opcodeSizes[0, 0xFD] = -4;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { 0xCB, (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[1, i] = (sbyte)pc;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { 0xED, (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[2, i] = (sbyte)pc;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { 0xDD, (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[3, i] = (sbyte)pc;
|
||||
}
|
||||
|
||||
opcodeSizes[3, 0xCB] = -5;
|
||||
opcodeSizes[3, 0xED] = -2;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { 0xFD, (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[4, i] = (sbyte)pc;
|
||||
}
|
||||
|
||||
opcodeSizes[3, 0xCB] = -6;
|
||||
opcodeSizes[3, 0xED] = -2;
|
||||
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { 0xDD, 0xCB, (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[5, i] = (sbyte)pc;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int pc = 0;
|
||||
byte[] opcode = { 0xFD, 0xCB, (byte)i, 0, 0, 0 };
|
||||
disasm.Disassemble(() => opcode[pc++]);
|
||||
opcodeSizes[6, i] = (sbyte)pc;
|
||||
}
|
||||
}
|
||||
|
||||
static string Result(string format, Func<byte> read)
|
||||
static string Result(string format, Func<ushort, byte> read, ref ushort addr)
|
||||
{
|
||||
//d immediately succeeds the opcode
|
||||
//n immediate succeeds the opcode and the displacement (if present)
|
||||
//nn immediately succeeds the opcode and the displacement (if present)
|
||||
if (format.IndexOf("nn") != -1)
|
||||
{
|
||||
byte B = read();
|
||||
byte C = read();
|
||||
byte B = read(addr++);
|
||||
byte C = read(addr++);
|
||||
format = format.Replace("nn", string.Format("{0:X4}h", B + C * 256));
|
||||
}
|
||||
|
||||
if (format.IndexOf("n") != -1)
|
||||
{
|
||||
byte B = read();
|
||||
byte B = read(addr++);
|
||||
format = format.Replace("n", string.Format("{0:X2}h", B));
|
||||
}
|
||||
|
||||
|
@ -116,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80
|
|||
|
||||
if (format.IndexOf("d") != -1)
|
||||
{
|
||||
byte B = read();
|
||||
byte B = read(addr++);
|
||||
bool neg = ((B & 0x80) != 0);
|
||||
char sign = neg ? '-' : '+';
|
||||
int val = neg ? 256 - B : B;
|
||||
|
@ -480,46 +393,49 @@ namespace BizHawk.Emulation.Cores.Components.Z80
|
|||
"NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100
|
||||
};
|
||||
|
||||
string DisassembleInternal(Func<byte> read)
|
||||
public string Disassemble(ushort addr, Func<ushort, byte> read, out ushort size)
|
||||
{
|
||||
byte A = read();
|
||||
ushort start_addr = addr;
|
||||
ushort extra_inc = 0;
|
||||
byte A = read(addr++);
|
||||
string format;
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB:
|
||||
A = read();
|
||||
A = read(addr++);
|
||||
format = mnemonicsCB[A];
|
||||
break;
|
||||
case 0xDD:
|
||||
A = read();
|
||||
A = read(addr++);
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB: format = mnemonicsDDCB[A]; break;
|
||||
case 0xCB: format = mnemonicsDDCB[read((ushort)(addr + 1))]; extra_inc = 1; break;
|
||||
case 0xED: format = mnemonicsED[A]; break;
|
||||
default: format = mnemonicsDD[A]; break;
|
||||
}
|
||||
break;
|
||||
case 0xED:
|
||||
A = read();
|
||||
A = read(addr++);
|
||||
format = mnemonicsED[A];
|
||||
break;
|
||||
case 0xFD:
|
||||
A = read();
|
||||
A = read(addr++);
|
||||
switch (A)
|
||||
{
|
||||
case 0xCB: format = mnemonicsFDCB[A]; break;
|
||||
case 0xCB: format = mnemonicsFDCB[read((ushort)(addr + 1))]; extra_inc = 1; break;
|
||||
case 0xED: format = mnemonicsED[A]; break;
|
||||
default: format = mnemonicsFD[A]; break;
|
||||
}
|
||||
break;
|
||||
default: format = mnemonics[A]; break;
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
string temp = Result(format, read, ref addr);
|
||||
|
||||
public string Disassemble(Func<byte> read)
|
||||
{
|
||||
return Result(DisassembleInternal(read), read);
|
||||
addr += extra_inc;
|
||||
|
||||
size = (ushort)(addr - start_addr);
|
||||
return temp;
|
||||
}
|
||||
|
||||
#region IDisassemblable
|
||||
|
@ -543,7 +459,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80
|
|||
public string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
int loc = (int)addr;
|
||||
string ret = Disassemble(() => m.PeekByte(loc++));
|
||||
ushort unused = 0;
|
||||
string ret = Disassemble((ushort) addr, a => m.PeekByte(a), out unused);
|
||||
length = loc - (int)addr;
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,742 @@
|
|||
using BizHawk.Common.NumberExtensions;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80A
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
public void Read_Func(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public void Write_Func(ushort dest_l, ushort dest_h, ushort 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)
|
||||
{
|
||||
WriteMemory((ushort)((Regs[dest_l] | (Regs[dest_h] << 8)) + inc), (byte)Regs[src]);
|
||||
}
|
||||
|
||||
public void OUT_Func(ushort dest, ushort src)
|
||||
{
|
||||
WriteHardware(Regs[dest], (byte)(Regs[src]));
|
||||
}
|
||||
|
||||
public void IN_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = ReadHardware(Regs[src]);
|
||||
}
|
||||
|
||||
public void TR_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = Regs[src];
|
||||
}
|
||||
|
||||
public void TR16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
Regs[dest_l] = Regs[src_l];
|
||||
Regs[dest_h] = Regs[src_h];
|
||||
}
|
||||
|
||||
public void ADD16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
|
||||
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
|
||||
int temp = Reg16_d + Reg16_s;
|
||||
|
||||
FlagC = temp.Bit(16);
|
||||
FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF)) > 0xFFF;
|
||||
FlagN = false;
|
||||
Flag3 = (temp & 0x0800) != 0;
|
||||
Flag5 = (temp & 0x2000) != 0;
|
||||
|
||||
Regs[dest_l] = (ushort)(temp & 0xFF);
|
||||
Regs[dest_h] = (ushort)((temp & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
public void ADD8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d += Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d += (Regs[src] & 0xF);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = false;
|
||||
Flag3 = (ans & 0x08) != 0;
|
||||
Flag5 = (ans & 0x20) != 0;
|
||||
FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
|
||||
FlagS = ans > 127;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void SUB8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
Flag3 = (ans & 0x08) != 0;
|
||||
Flag5 = (ans & 0x20) != 0;
|
||||
FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
|
||||
FlagS = ans > 127;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void BIT_Func(ushort bit, ushort src)
|
||||
{
|
||||
FlagZ = !Regs[src].Bit(bit);
|
||||
FlagP = FlagZ; // special case
|
||||
FlagH = true;
|
||||
FlagN = false;
|
||||
FlagS = ((bit == 7) && Regs[src].Bit(bit));
|
||||
Flag5 = Regs[src].Bit(5);
|
||||
Flag3 = Regs[src].Bit(3);
|
||||
}
|
||||
|
||||
// When doing I* + n bit tests, flags 3 and 5 come from I* + n
|
||||
// This cooresponds to the high byte of WZ
|
||||
// This is the same for the (HL) bit tests, except that WZ were not assigned to before the test occurs
|
||||
public void I_BIT_Func(ushort bit, ushort src)
|
||||
{
|
||||
FlagZ = !Regs[src].Bit(bit);
|
||||
FlagP = FlagZ; // special case
|
||||
FlagH = true;
|
||||
FlagN = false;
|
||||
FlagS = ((bit == 7) && Regs[src].Bit(bit));
|
||||
Flag5 = Regs[W].Bit(5);
|
||||
Flag3 = Regs[W].Bit(3);
|
||||
}
|
||||
|
||||
public void SET_Func(ushort bit, ushort src)
|
||||
{
|
||||
Regs[src] |= (ushort)(1 << bit);
|
||||
}
|
||||
|
||||
public void RES_Func(ushort bit, ushort src)
|
||||
{
|
||||
Regs[src] &= (ushort)(0xFF - (1 << bit));
|
||||
}
|
||||
|
||||
public void ASGN_Func(ushort src, ushort val)
|
||||
{
|
||||
Regs[src] = val;
|
||||
}
|
||||
|
||||
public void SLL_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | 0x1);
|
||||
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SLA_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)((Regs[src] << 1) & 0xFF);
|
||||
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SRA_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation
|
||||
|
||||
Regs[src] = (ushort)((Regs[src] >> 1) | temp);
|
||||
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void SRL_Func(ushort src)
|
||||
{
|
||||
FlagC = Regs[src].Bit(0) ? true : false;
|
||||
|
||||
Regs[src] = (ushort)(Regs[src] >> 1);
|
||||
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void CPL_Func(ushort src)
|
||||
{
|
||||
Regs[src] = (ushort)((~Regs[src]) & 0xFF);
|
||||
|
||||
FlagH = true;
|
||||
FlagN = true;
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void CCF_Func(ushort src)
|
||||
{
|
||||
FlagH = FlagC;
|
||||
FlagC = !FlagC;
|
||||
FlagN = false;
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void SCF_Func(ushort src)
|
||||
{
|
||||
FlagC = true;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void AND8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] & Regs[src]);
|
||||
|
||||
FlagZ = Regs[dest] == 0;
|
||||
FlagC = false;
|
||||
FlagH = true;
|
||||
FlagN = false;
|
||||
Flag3 = (Regs[dest] & 0x08) != 0;
|
||||
Flag5 = (Regs[dest] & 0x20) != 0;
|
||||
FlagS = Regs[dest] > 127;
|
||||
FlagP = TableParity[Regs[dest]];
|
||||
}
|
||||
|
||||
public void OR8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)(Regs[dest] | Regs[src]);
|
||||
|
||||
FlagZ = Regs[dest] == 0;
|
||||
FlagC = false;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
Flag3 = (Regs[dest] & 0x08) != 0;
|
||||
Flag5 = (Regs[dest] & 0x20) != 0;
|
||||
FlagS = Regs[dest] > 127;
|
||||
FlagP = TableParity[Regs[dest]];
|
||||
}
|
||||
|
||||
public void XOR8_Func(ushort dest, ushort src)
|
||||
{
|
||||
Regs[dest] = (ushort)((Regs[dest] ^ Regs[src]));
|
||||
|
||||
FlagZ = Regs[dest] == 0;
|
||||
FlagC = false;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
Flag3 = (Regs[dest] & 0x08) != 0;
|
||||
Flag5 = (Regs[dest] & 0x20) != 0;
|
||||
FlagS = Regs[dest] > 127;
|
||||
FlagP = TableParity[Regs[dest]];
|
||||
}
|
||||
|
||||
public void CP8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
|
||||
FlagS = ans > 127;
|
||||
}
|
||||
|
||||
public void RRC_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)((FlagC ? 0x80 : 0) | (Regs[src] >> 1));
|
||||
|
||||
if (!imm)
|
||||
{
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
}
|
||||
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void RR_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
ushort c = (ushort)(FlagC ? 0x80 : 0);
|
||||
|
||||
FlagC = Regs[src].Bit(0);
|
||||
|
||||
Regs[src] = (ushort)(c | (Regs[src] >> 1));
|
||||
|
||||
if (!imm)
|
||||
{
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
}
|
||||
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void RLC_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
ushort c = (ushort)(Regs[src].Bit(7) ? 1 : 0);
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
|
||||
|
||||
if (!imm)
|
||||
{
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
}
|
||||
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void RL_Func(ushort src)
|
||||
{
|
||||
bool imm = src == Aim;
|
||||
if (imm) { src = A; }
|
||||
|
||||
ushort c = (ushort)(FlagC ? 1 : 0);
|
||||
FlagC = Regs[src].Bit(7);
|
||||
|
||||
Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c);
|
||||
|
||||
if (!imm)
|
||||
{
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagZ = Regs[src] == 0;
|
||||
FlagP = TableParity[Regs[src]];
|
||||
}
|
||||
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
}
|
||||
|
||||
public void INC8_Func(ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[src];
|
||||
Reg16_d += 1;
|
||||
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[src] & 0xF;
|
||||
Reg16_d += 1;
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = false;
|
||||
|
||||
Regs[src] = ans;
|
||||
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagP = Regs[src] == 0x80;
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void DEC8_Func(ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[src];
|
||||
Reg16_d -= 1;
|
||||
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[src] & 0xF;
|
||||
Reg16_d -= 1;
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
|
||||
Regs[src] = ans;
|
||||
|
||||
FlagS = Regs[src].Bit(7);
|
||||
FlagP = Regs[src] == 0x7F;
|
||||
Flag3 = (Regs[src] & 0x08) != 0;
|
||||
Flag5 = (Regs[src] & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void INC16_Func(ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
|
||||
|
||||
Reg16_d += 1;
|
||||
|
||||
Regs[src_l] = (ushort)(Reg16_d & 0xFF);
|
||||
Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
public void DEC16_Func(ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[src_l] | (Regs[src_h] << 8);
|
||||
|
||||
Reg16_d -= 1;
|
||||
|
||||
Regs[src_l] = (ushort)(Reg16_d & 0xFF);
|
||||
Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
public void ADC8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
int c = FlagC ? 1 : 0;
|
||||
|
||||
Reg16_d += (Regs[src] + c);
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d += ((Regs[src] & 0xF) + c);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = false;
|
||||
Flag3 = (ans & 0x08) != 0;
|
||||
Flag5 = (ans & 0x20) != 0;
|
||||
FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
|
||||
FlagS = ans > 127;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void SBC8_Func(ushort dest, ushort src)
|
||||
{
|
||||
int Reg16_d = Regs[dest];
|
||||
int c = FlagC ? 1 : 0;
|
||||
|
||||
Reg16_d -= (Regs[src] + c);
|
||||
|
||||
FlagC = Reg16_d.Bit(8);
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d = Regs[dest] & 0xF;
|
||||
Reg16_d -= ((Regs[src] & 0xF) + c);
|
||||
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
FlagN = true;
|
||||
Flag3 = (ans & 0x08) != 0;
|
||||
Flag5 = (ans & 0x20) != 0;
|
||||
FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
|
||||
FlagS = ans > 127;
|
||||
|
||||
Regs[dest] = ans;
|
||||
}
|
||||
|
||||
public void DA_Func(ushort src)
|
||||
{
|
||||
byte a = (byte)Regs[src];
|
||||
byte temp = a;
|
||||
|
||||
if (FlagN)
|
||||
{
|
||||
if (FlagH || ((a & 0x0F) > 0x09)) { temp -= 0x06; }
|
||||
if (FlagC || a > 0x99) { temp -= 0x60; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FlagH || ((a & 0x0F) > 0x09)) { temp += 0x06; }
|
||||
if (FlagC || a > 0x99) { temp += 0x60; }
|
||||
}
|
||||
|
||||
temp &= 0xFF;
|
||||
|
||||
FlagC = FlagC || a > 0x99;
|
||||
FlagZ = temp == 0;
|
||||
FlagH = ((a ^ temp) & 0x10) != 0;
|
||||
FlagP = TableParity[temp];
|
||||
FlagS = temp > 127;
|
||||
Flag3 = (temp & 0x08) != 0;
|
||||
Flag5 = (temp & 0x20) != 0;
|
||||
|
||||
Regs[src] = temp;
|
||||
}
|
||||
|
||||
// used for signed operations
|
||||
public void ADDS_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[dest_l];
|
||||
int Reg16_s = Regs[src_l];
|
||||
|
||||
Reg16_d += Reg16_s;
|
||||
|
||||
ushort temp = 0;
|
||||
|
||||
// since this is signed addition, calculate the high byte carry appropriately
|
||||
// note that flags are unaffected by this operation
|
||||
if (Reg16_s.Bit(7))
|
||||
{
|
||||
if (((Reg16_d & 0xFF) >= Regs[dest_l]))
|
||||
{
|
||||
temp = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = (ushort)(Reg16_d.Bit(8) ? 1 : 0);
|
||||
}
|
||||
|
||||
ushort ans_l = (ushort)(Reg16_d & 0xFF);
|
||||
|
||||
Regs[dest_l] = ans_l;
|
||||
Regs[dest_h] += temp;
|
||||
Regs[dest_h] &= 0xFF;
|
||||
|
||||
}
|
||||
|
||||
public void EXCH_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
ushort temp = Regs[dest_l];
|
||||
Regs[dest_l] = Regs[src_l];
|
||||
Regs[src_l] = temp;
|
||||
|
||||
temp = Regs[dest_h];
|
||||
Regs[dest_h] = Regs[src_h];
|
||||
Regs[src_h] = temp;
|
||||
}
|
||||
|
||||
public void SBC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
|
||||
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
|
||||
int c = FlagC ? 1 : 0;
|
||||
|
||||
int ans = Reg16_d - Reg16_s - c;
|
||||
|
||||
FlagN = true;
|
||||
FlagC = ans.Bit(16);
|
||||
FlagP = (Reg16_d.Bit(15) != Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15));
|
||||
FlagS = (ushort)(ans & 0xFFFF) > 32767;
|
||||
FlagZ = (ans & 0xFFFF) == 0;
|
||||
Flag3 = (ans & 0x0800) != 0;
|
||||
Flag5 = (ans & 0x2000) != 0;
|
||||
|
||||
// redo for half carry flag
|
||||
Reg16_d &= 0xFFF;
|
||||
Reg16_d -= ((Reg16_s & 0xFFF) + c);
|
||||
|
||||
FlagH = Reg16_d.Bit(12);
|
||||
|
||||
Regs[dest_l] = (ushort)(ans & 0xFF);
|
||||
Regs[dest_h] = (ushort)((ans >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
public void ADC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8);
|
||||
int Reg16_s = Regs[src_l] | (Regs[src_h] << 8);
|
||||
|
||||
int ans = Reg16_d + Reg16_s + (FlagC ? 1 : 0);
|
||||
|
||||
FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF) + (FlagC ? 1 : 0)) > 0xFFF;
|
||||
FlagN = false;
|
||||
FlagC = ans.Bit(16);
|
||||
FlagP = (Reg16_d.Bit(15) == Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15));
|
||||
FlagS = (ans & 0xFFFF) > 32767;
|
||||
FlagZ = (ans & 0xFFFF) == 0;
|
||||
Flag3 = (ans & 0x0800) != 0;
|
||||
Flag5 = (ans & 0x2000) != 0;
|
||||
|
||||
Regs[dest_l] = (ushort)(ans & 0xFF);
|
||||
Regs[dest_h] = (ushort)((ans >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
public void NEG_8_Func(ushort src)
|
||||
{
|
||||
int Reg16_d = 0;
|
||||
Reg16_d -= Regs[src];
|
||||
|
||||
FlagC = Regs[src] != 0x0;
|
||||
FlagZ = (Reg16_d & 0xFF) == 0;
|
||||
FlagP = Regs[src] == 0x80;
|
||||
FlagS = (Reg16_d & 0xFF) > 127;
|
||||
|
||||
ushort ans = (ushort)(Reg16_d & 0xFF);
|
||||
// redo for half carry flag
|
||||
Reg16_d = 0;
|
||||
Reg16_d -= (Regs[src] & 0xF);
|
||||
FlagH = Reg16_d.Bit(4);
|
||||
Regs[src] = ans;
|
||||
FlagN = true;
|
||||
Flag3 = (ans & 0x08) != 0;
|
||||
Flag5 = (ans & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void RRD_Func(ushort dest, ushort src)
|
||||
{
|
||||
ushort temp1 = Regs[src];
|
||||
ushort temp2 = Regs[dest];
|
||||
Regs[dest] = (ushort)(((temp1 & 0x0F) << 4) + ((temp2 & 0xF0) >> 4));
|
||||
Regs[src] = (ushort)((temp1 & 0xF0) + (temp2 & 0x0F));
|
||||
|
||||
temp1 = Regs[src];
|
||||
FlagS = temp1 > 127;
|
||||
FlagZ = temp1 == 0;
|
||||
FlagH = false;
|
||||
FlagP = TableParity[temp1];
|
||||
FlagN = false;
|
||||
Flag3 = (temp1 & 0x08) != 0;
|
||||
Flag5 = (temp1 & 0x20) != 0;
|
||||
}
|
||||
|
||||
public void RLD_Func(ushort dest, ushort src)
|
||||
{
|
||||
ushort temp1 = Regs[src];
|
||||
ushort temp2 = Regs[dest];
|
||||
Regs[dest] = (ushort)((temp1 & 0x0F) + ((temp2 & 0x0F) << 4));
|
||||
Regs[src] = (ushort)((temp1 & 0xF0) + ((temp2 & 0xF0) >> 4));
|
||||
|
||||
temp1 = Regs[src];
|
||||
FlagS = temp1 > 127;
|
||||
FlagZ = temp1 == 0;
|
||||
FlagH = false;
|
||||
FlagP = TableParity[temp1];
|
||||
FlagN = false;
|
||||
Flag3 = (temp1 & 0x08) != 0;
|
||||
Flag5 = (temp1 & 0x20) != 0;
|
||||
}
|
||||
|
||||
// sets flags for LD/R
|
||||
public void SET_FL_LD_Func()
|
||||
{
|
||||
FlagP = (Regs[C] | (Regs[B] << 8)) != 0;
|
||||
FlagH = false;
|
||||
FlagN = false;
|
||||
Flag5 = ((Regs[ALU] + Regs[A]) & 0x02) != 0;
|
||||
Flag3 = ((Regs[ALU] + Regs[A]) & 0x08) != 0;
|
||||
}
|
||||
|
||||
// set flags for CP/R
|
||||
public void SET_FL_CP_Func()
|
||||
{
|
||||
int Reg8_d = Regs[A];
|
||||
int Reg8_s = Regs[ALU];
|
||||
|
||||
// get half carry flag
|
||||
byte temp = (byte)((Reg8_d & 0xF) - (Reg8_s & 0xF));
|
||||
FlagH = temp.Bit(4);
|
||||
|
||||
temp = (byte)(Reg8_d - Reg8_s);
|
||||
FlagN = true;
|
||||
FlagZ = temp == 0;
|
||||
FlagS = temp > 127;
|
||||
FlagP = (Regs[C] | (Regs[B] << 8)) != 0;
|
||||
|
||||
temp = (byte)(Reg8_d - Reg8_s - (FlagH ? 1 : 0));
|
||||
Flag5 = (temp & 0x02) != 0;
|
||||
Flag3 = (temp & 0x08) != 0;
|
||||
}
|
||||
|
||||
// set flags for LD A, I/R
|
||||
public void SET_FL_IR_Func(ushort dest)
|
||||
{
|
||||
if (dest == A)
|
||||
{
|
||||
FlagN = false;
|
||||
FlagH = false;
|
||||
FlagZ = Regs[A] == 0;
|
||||
FlagS = Regs[A] > 127;
|
||||
FlagP = iff2;
|
||||
Flag5 = (Regs[A] & 0x02) != 0;
|
||||
Flag3 = (Regs[A] & 0x08) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
TODO:
|
||||
|
||||
Mode 0 and 2 interrupts
|
||||
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
|
|
@ -0,0 +1,132 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
|
||||
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;
|
||||
public ushort SPh = 3;
|
||||
public ushort A = 4;
|
||||
public ushort F = 5;
|
||||
public ushort B = 6;
|
||||
public ushort C = 7;
|
||||
public ushort D = 8;
|
||||
public ushort E = 9;
|
||||
public ushort H = 10;
|
||||
public ushort L = 11;
|
||||
public ushort W = 12;
|
||||
public ushort Z = 13;
|
||||
public ushort Aim = 14; // use this indicator for RLCA etc., since the Z flag is reset on those
|
||||
public ushort Ixl = 15;
|
||||
public ushort Ixh = 16;
|
||||
public ushort Iyl = 17;
|
||||
public ushort Iyh = 18;
|
||||
public ushort Int = 19;
|
||||
public ushort R = 20;
|
||||
public ushort I = 21;
|
||||
public ushort ZERO = 22; // it is convenient to have a register that is always zero, to reuse instructions
|
||||
public ushort ALU = 23; // This will be temporary arthimatic storage
|
||||
// shadow registers
|
||||
public ushort A_s = 24;
|
||||
public ushort F_s = 25;
|
||||
public ushort B_s = 26;
|
||||
public ushort C_s = 27;
|
||||
public ushort D_s = 28;
|
||||
public ushort E_s = 29;
|
||||
public ushort H_s = 30;
|
||||
public ushort L_s = 31;
|
||||
|
||||
public ushort[] Regs = new ushort[36];
|
||||
|
||||
public bool FlagI;
|
||||
|
||||
public bool FlagC
|
||||
{
|
||||
get { return (Regs[5] & 0x01) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x01) | (value ? 0x01 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagN
|
||||
{
|
||||
get { return (Regs[5] & 0x02) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x02) | (value ? 0x02 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagP
|
||||
{
|
||||
get { return (Regs[5] & 0x04) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x04) | (value ? 0x04 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool Flag3
|
||||
{
|
||||
get { return (Regs[5] & 0x08) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x08) | (value ? 0x08 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagH
|
||||
{
|
||||
get { return (Regs[5] & 0x10) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool Flag5
|
||||
{
|
||||
get { return (Regs[5] & 0x20) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagZ
|
||||
{
|
||||
get { return (Regs[5] & 0x40) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); }
|
||||
}
|
||||
|
||||
public bool FlagS
|
||||
{
|
||||
get { return (Regs[5] & 0x80) != 0; }
|
||||
set { Regs[5] = (ushort)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); }
|
||||
}
|
||||
|
||||
public ushort RegPC
|
||||
{
|
||||
get { return (ushort)(Regs[0] | (Regs[1] << 8)); }
|
||||
set
|
||||
{
|
||||
Regs[0] = (ushort)(value & 0xFF);
|
||||
Regs[1] = (ushort)((value >> 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetRegisters()
|
||||
{
|
||||
for (int i=0; i < 36; i++)
|
||||
{
|
||||
Regs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private bool[] TableParity;
|
||||
private void InitTableParity()
|
||||
{
|
||||
TableParity = new bool[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int Bits = 0;
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
Bits += (i >> j) & 1;
|
||||
}
|
||||
TableParity[i] = (Bits & 1) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,572 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80A
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
// this contains the vectors of instrcution operations
|
||||
// NOTE: This list is NOT confirmed accurate for each individual cycle
|
||||
|
||||
private void NOP_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers
|
||||
// but it's simpler to emulate just by exchanging the register with it's shadow
|
||||
private void EXCH_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{EXCH,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void EXX_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{EXX,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// this exchanges 2 16 bit registers
|
||||
private void EXCH_16_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{EXCH_16, dest_l, dest_h, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void INC_16(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
||||
private void DEC_16(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
DEC16, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// this is done in two steps technically, but the flags don't work out using existing funcitons
|
||||
// so let's use a different function since it's an internal operation anyway
|
||||
private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR16, Z, W, dest_l, dest_h,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
ADD16, dest_l, dest_h, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void REG_OP(ushort operation, ushort dest, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, dest, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// Operations using the I and R registers take one T-cycle longer
|
||||
private void REG_OP_IR(ushort operation, ushort dest, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, dest, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
SET_FL_IR, dest,
|
||||
OP };
|
||||
}
|
||||
|
||||
// note: do not use DEC here since no flags are affected by this operation
|
||||
private void DJNZ_()
|
||||
{
|
||||
if ((Regs[B] - 1) != 0)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
ASGN, B, (ushort)((Regs[B] - 1) & 0xFF),
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
ASGN, W, 0,
|
||||
IDLE,
|
||||
ADDS, PCl, PCh, Z, W,
|
||||
TR16, Z, W, PCl, PCh,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
ASGN, B, (ushort)((Regs[B] - 1) & 0xFF),
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void HALT_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
}
|
||||
|
||||
private void JR_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
ASGN, W, 0,
|
||||
IDLE,
|
||||
ADDS, PCl, PCh, Z, W,
|
||||
TR16, Z, W, PCl, PCh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void JP_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void RET_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void RETI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void RETN_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, W, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
EI_RETN,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
||||
private void RET_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, W, SPl, SPh,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void CALL_COND(bool cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, PCh,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
TR, PCl, Z,
|
||||
TR, PCh, W,
|
||||
OP };
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
|
||||
private void INT_OP(ushort operation, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void BIT_OP(ushort operation, ushort bit, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{operation, bit, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void PUSH_(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, src_h,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
IDLE,
|
||||
WR, SPl, SPh, src_l,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
|
||||
private void POP_(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, src_l, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
RD, src_h, SPl, SPh,
|
||||
IDLE,
|
||||
INC16, SPl, SPh,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void RST_(ushort n)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCh,
|
||||
DEC16, SPl, SPh,
|
||||
WR, SPl, SPh, PCl,
|
||||
IDLE,
|
||||
ASGN, Z, n,
|
||||
ASGN, W, 0,
|
||||
TR16, PCl, PCh, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void PREFIX_(ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
PREFIX, src};
|
||||
}
|
||||
|
||||
private void PREFETCH_(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{TR16, Z, W, src_l, src_h,
|
||||
ADDS, Z, W, ALU, ZERO,
|
||||
IDLE,
|
||||
PREFIX, IXYprefetch };
|
||||
}
|
||||
|
||||
private void DI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{DI,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void EI_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{EI,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void JP_16(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{TR, PCl, src_l,
|
||||
IDLE,
|
||||
TR, PCh, src_h,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_SP_16(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
TR, SPl, src_l,
|
||||
TR, SPh, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void OUT_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
TR, W, A,
|
||||
OUT, ALU, A,
|
||||
TR, Z, ALU,
|
||||
INC16, Z, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP};
|
||||
}
|
||||
|
||||
private void OUT_REG_(ushort dest, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
OUT, dest, src,
|
||||
IDLE,
|
||||
TR16, Z, W, C, B,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
OP};
|
||||
}
|
||||
|
||||
private void IN_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
TR, W, A,
|
||||
IN, A, ALU,
|
||||
TR, Z, ALU,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP};
|
||||
}
|
||||
|
||||
private void IN_REG_(ushort dest, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IN, dest, src,
|
||||
IDLE,
|
||||
TR16, Z, W, C, B,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
OP};
|
||||
}
|
||||
|
||||
private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR16, Z, W, dest_l, dest_h,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
op, dest_l, dest_h, src_l, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP};
|
||||
}
|
||||
|
||||
private void INT_MODE_(ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
INT_MODE, src,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void RRD_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
TR16, Z, W, L, H,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
RRD, ALU, A,
|
||||
IDLE,
|
||||
WR, Z, W, ALU,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void RLD_()
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
TR16, Z, W, L, H,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
RLD, ALU, A,
|
||||
IDLE,
|
||||
WR, Z, W, ALU,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,478 @@
|
|||
namespace BizHawk.Emulation.Cores.Components.Z80A
|
||||
{
|
||||
public partial class Z80A
|
||||
{
|
||||
private void INT_OP_IND(ushort operation, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
operation, ALU,
|
||||
IDLE,
|
||||
WR, src_l, src_h, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
operation, bit, ALU,
|
||||
IDLE,
|
||||
WR, src_l, src_h, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// Note that this operation uses I_BIT, same as indexed BIT.
|
||||
// This is where the strange behaviour in Flag bits 3 and 5 come from.
|
||||
// normally WZ contain I* + n when doing I_BIT ops, but here we use that code path
|
||||
// even though WZ is not assigned to, letting it's value from other operations show through
|
||||
private void BIT_TE_IND(ushort operation, ushort bit, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
I_BIT, bit, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
operation, dest, ALU,
|
||||
INC16, src_l, src_h,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
TR16, Z, W, src_l, src_h,
|
||||
RD, ALU, Z, W,
|
||||
INC16, Z, W,
|
||||
operation, dest, ALU,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_16_IND_nn(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
WR, Z, W, src_l,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
WR, Z, W, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_16_nn(ushort dest_l, ushort dest_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, dest_l, Z, W,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
IDLE,
|
||||
RD, dest_h, Z, W,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND_nn(ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
WR, Z, W, src,
|
||||
INC16, Z, W,
|
||||
TR, W, A,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_8_nn(ushort dest)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, Z, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, W, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
RD, dest, Z, W,
|
||||
IDLE,
|
||||
INC16, Z, W,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
TR16, Z, W, dest_l, dest_h,
|
||||
WR, Z, W, src,
|
||||
INC16, Z, W,
|
||||
TR, W, A,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
IDLE,
|
||||
WR, dest_l, dest_h, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, dest, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, dest, src_l, src_h,
|
||||
IDLE,
|
||||
DEC16, src_l, src_h,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, dest_l, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
RD, dest_h, src_l, src_h,
|
||||
IDLE,
|
||||
INC16, src_l, src_h,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void INC_8_IND(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
INC8, ALU,
|
||||
IDLE,
|
||||
WR, src_l, src_h, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void DEC_8_IND(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, src_l, src_h,
|
||||
IDLE,
|
||||
DEC8, ALU,
|
||||
IDLE,
|
||||
WR, src_l, src_h, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
// NOTE: WZ implied for the wollowing 3 functions
|
||||
private void I_INT_OP(ushort operation, ushort dest)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
operation, ALU,
|
||||
IDLE,
|
||||
WR, Z, W, ALU,
|
||||
IDLE,
|
||||
TR, dest, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void I_BIT_OP(ushort operation, ushort bit, ushort dest)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
operation, bit, ALU,
|
||||
IDLE,
|
||||
WR, Z, W, ALU,
|
||||
IDLE,
|
||||
TR, dest, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void I_BIT_TE(ushort bit)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
I_BIT, bit, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void I_OP_n(ushort operation, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
TR16, Z, W, src_l, src_h,
|
||||
IDLE,
|
||||
ADDS, Z, W, ALU, ZERO,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
operation, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, Z, W, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void I_OP_n_n(ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
TR16, Z, W, src_l, src_h,
|
||||
IDLE,
|
||||
ADDS, Z, W, ALU, ZERO,
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
WR, Z, W, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
TR16, Z, W, src_l, src_h,
|
||||
IDLE,
|
||||
ADDS, Z, W, ALU, ZERO,
|
||||
IDLE,
|
||||
RD, ALU, Z, W,
|
||||
IDLE,
|
||||
operation, dest, ALU,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
RD, ALU, PCl, PCh,
|
||||
IDLE,
|
||||
INC16, PCl, PCh,
|
||||
IDLE,
|
||||
TR16, Z, W, dest_l, dest_h,
|
||||
IDLE,
|
||||
ADDS, Z, W, ALU, ZERO,
|
||||
IDLE,
|
||||
WR, Z, W, src,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
|
||||
private void LD_OP_R(ushort operation, ushort repeat_instr)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{RD, ALU, L, H,
|
||||
IDLE,
|
||||
WR, E, D, ALU,
|
||||
IDLE,
|
||||
operation, L, H,
|
||||
IDLE,
|
||||
operation, E, D,
|
||||
IDLE,
|
||||
DEC16, C, B,
|
||||
SET_FL_LD,
|
||||
IDLE,
|
||||
OP_R, 0, operation, repeat_instr };
|
||||
}
|
||||
|
||||
private void CP_OP_R(ushort operation, ushort repeat_instr)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, ALU, L, H,
|
||||
operation, L, H,
|
||||
IDLE,
|
||||
IDLE,
|
||||
DEC16, C, B,
|
||||
SET_FL_CP,
|
||||
IDLE,
|
||||
operation, Z, W,
|
||||
IDLE,
|
||||
OP_R, 1, operation, repeat_instr };
|
||||
}
|
||||
|
||||
private void IN_OP_R(ushort operation, ushort repeat_instr)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IN, ALU, C,
|
||||
IDLE,
|
||||
WR, L, H, ALU,
|
||||
IDLE,
|
||||
operation, L, H,
|
||||
IDLE,
|
||||
TR16, Z, W, C, B,
|
||||
operation, Z, W,
|
||||
IDLE,
|
||||
DEC8, B,
|
||||
IDLE,
|
||||
OP_R, 2, operation, repeat_instr };
|
||||
}
|
||||
|
||||
private void OUT_OP_R(ushort operation, ushort repeat_instr)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{RD, ALU, L, H,
|
||||
IDLE,
|
||||
OUT, C, ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
operation, L, H,
|
||||
DEC8, B,
|
||||
IDLE,
|
||||
TR16, Z, W, C, B,
|
||||
operation, Z, W,
|
||||
IDLE,
|
||||
OP_R, 3, operation, repeat_instr };
|
||||
}
|
||||
|
||||
// this is an indirect change of a a 16 bit register with memory
|
||||
private void EXCH_16_IND_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
RD, Z, dest_l, dest_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
I_RD, W, dest_l, dest_h, 1,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR, dest_l, dest_h, src_l,
|
||||
IDLE,
|
||||
IDLE,
|
||||
I_WR, dest_l, dest_h, 1, src_h,
|
||||
IDLE,
|
||||
IDLE,
|
||||
TR16, src_l, src_h, Z, W,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,687 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
// Z80A CPU
|
||||
namespace BizHawk.Emulation.Cores.Components.Z80A
|
||||
{
|
||||
public sealed partial class Z80A
|
||||
{
|
||||
// operations that can take place in an instruction
|
||||
public const ushort IDLE = 0;
|
||||
public const ushort OP = 1;
|
||||
public const ushort OP_R = 2; // used for repeating operations
|
||||
public const ushort HALT = 3;
|
||||
public const ushort RD = 4;
|
||||
public const ushort WR = 5;
|
||||
public const ushort I_RD = 6;
|
||||
public const ushort I_WR = 7;
|
||||
public const ushort TR = 8;
|
||||
public const ushort TR16 = 9;
|
||||
public const ushort ADD16 = 10;
|
||||
public const ushort ADD8 = 11;
|
||||
public const ushort SUB8 = 12;
|
||||
public const ushort ADC8 = 13;
|
||||
public const ushort SBC8 = 14;
|
||||
public const ushort SBC16 = 15;
|
||||
public const ushort ADC16 = 16;
|
||||
public const ushort INC16 = 17;
|
||||
public const ushort INC8 = 18;
|
||||
public const ushort DEC16 = 19;
|
||||
public const ushort DEC8 = 20;
|
||||
public const ushort RLC = 21;
|
||||
public const ushort RL = 22;
|
||||
public const ushort RRC = 23;
|
||||
public const ushort RR = 24;
|
||||
public const ushort CPL = 25;
|
||||
public const ushort DA = 26;
|
||||
public const ushort SCF = 27;
|
||||
public const ushort CCF = 28;
|
||||
public const ushort AND8 = 29;
|
||||
public const ushort XOR8 = 30;
|
||||
public const ushort OR8 = 31;
|
||||
public const ushort CP8 = 32;
|
||||
public const ushort SLA = 33;
|
||||
public const ushort SRA = 34;
|
||||
public const ushort SRL = 35;
|
||||
public const ushort SLL = 36;
|
||||
public const ushort BIT = 37;
|
||||
public const ushort RES = 38;
|
||||
public const ushort SET = 39;
|
||||
public const ushort EI = 40;
|
||||
public const ushort DI = 41;
|
||||
public const ushort EXCH = 42;
|
||||
public const ushort EXX = 43;
|
||||
public const ushort EXCH_16 = 44;
|
||||
public const ushort PREFIX = 45;
|
||||
public const ushort PREFETCH = 46;
|
||||
public const ushort ASGN = 47;
|
||||
public const ushort ADDS = 48; // signed 16 bit operation used in 2 instructions
|
||||
public const ushort INT_MODE = 49;
|
||||
public const ushort EI_RETN = 50;
|
||||
public const ushort EI_RETI = 51; // reti has no delay in interrupt enable
|
||||
public const ushort OUT = 52;
|
||||
public const ushort IN = 53;
|
||||
public const ushort NEG = 54;
|
||||
public const ushort RRD = 55;
|
||||
public const ushort RLD = 56;
|
||||
public const ushort SET_FL_LD = 57;
|
||||
public const ushort SET_FL_CP = 58;
|
||||
public const ushort SET_FL_IR = 59;
|
||||
public const ushort I_BIT = 60;
|
||||
public const ushort HL_BIT = 61;
|
||||
|
||||
public byte temp_R;
|
||||
|
||||
public Z80A()
|
||||
{
|
||||
Reset();
|
||||
InitTableParity();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
TotalExecutedCycles = 0;
|
||||
cur_instr = new ushort[] { OP };
|
||||
NO_prefix = true;
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; set; }
|
||||
|
||||
// Memory Access
|
||||
public Func<ushort, byte> FetchMemory;
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
public Action<ushort, byte> WriteMemory;
|
||||
public Func<ushort, byte> PeekMemory;
|
||||
public Func<ushort, byte> DummyReadMemory;
|
||||
|
||||
// Hardware I/O Port Access
|
||||
public Func<ushort, byte> ReadHardware;
|
||||
public Action<ushort, byte> WriteHardware;
|
||||
|
||||
//this only calls when the first byte of an instruction is fetched.
|
||||
public Action<ushort> OnExecFetch;
|
||||
|
||||
public void UnregisterMemoryMapper()
|
||||
{
|
||||
ReadMemory = null;
|
||||
WriteMemory = null;
|
||||
PeekMemory = null;
|
||||
DummyReadMemory = null;
|
||||
ReadHardware = null;
|
||||
WriteHardware = null;
|
||||
}
|
||||
|
||||
public void SetCallbacks
|
||||
(
|
||||
Func<ushort, byte> ReadMemory,
|
||||
Func<ushort, byte> DummyReadMemory,
|
||||
Func<ushort, byte> PeekMemory,
|
||||
Action<ushort, byte> WriteMemory,
|
||||
Func<ushort, byte> ReadHardware,
|
||||
Action<ushort, byte> WriteHardware
|
||||
)
|
||||
{
|
||||
this.ReadMemory = ReadMemory;
|
||||
this.DummyReadMemory = DummyReadMemory;
|
||||
this.PeekMemory = PeekMemory;
|
||||
this.WriteMemory = WriteMemory;
|
||||
this.ReadHardware = ReadHardware;
|
||||
this.WriteHardware = WriteHardware;
|
||||
}
|
||||
|
||||
// Execute instructions
|
||||
public void ExecuteOne()
|
||||
{
|
||||
if (Regs[A] > 255) { Console.WriteLine(RegPC); }
|
||||
switch (cur_instr[instr_pntr++])
|
||||
{
|
||||
case IDLE:
|
||||
// do nothing
|
||||
break;
|
||||
case OP:
|
||||
// Read the opcode of the next instruction
|
||||
if (EI_pending > 0)
|
||||
{
|
||||
EI_pending--;
|
||||
if (EI_pending == 0) { IFF1 = IFF2 = true; }
|
||||
}
|
||||
|
||||
// Process interrupt requests.
|
||||
if (nonMaskableInterruptPending)
|
||||
{
|
||||
nonMaskableInterruptPending = false;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""});
|
||||
}
|
||||
|
||||
iff2 = iff1;
|
||||
iff1 = false;
|
||||
NMI_();
|
||||
NMICallback();
|
||||
}
|
||||
else if (iff1 && FlagI)
|
||||
{
|
||||
iff1 = iff2 = false;
|
||||
EI_pending = 0;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""});
|
||||
}
|
||||
|
||||
switch (interruptMode)
|
||||
{
|
||||
case 0:
|
||||
// Requires something to be pushed onto the data bus
|
||||
// we'll assume it's a zero for now
|
||||
INTERRUPT_0(0);
|
||||
break;
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
IRQCallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null) TraceCallback(State());
|
||||
FetchInstruction(FetchMemory(RegPC++));
|
||||
}
|
||||
instr_pntr = 0;
|
||||
|
||||
temp_R = (byte)(Regs[R] & 0x7F);
|
||||
temp_R++;
|
||||
temp_R &= 0x7F;
|
||||
Regs[R] = (byte)((Regs[R] & 0x80) | temp_R);
|
||||
break;
|
||||
case OP_R:
|
||||
// determine if we repeat based on what operation we are doing
|
||||
// single execution versions also come here, but never repeat
|
||||
ushort temp1 = cur_instr[instr_pntr++];
|
||||
ushort temp2 = cur_instr[instr_pntr++];
|
||||
ushort temp3 = cur_instr[instr_pntr++];
|
||||
|
||||
bool repeat = false;
|
||||
int Reg16_d = Regs[C] | (Regs[B] << 8);
|
||||
switch (temp1)
|
||||
{
|
||||
case 0:
|
||||
repeat = Reg16_d != 0;
|
||||
break;
|
||||
case 1:
|
||||
repeat = (Reg16_d != 0) && !FlagZ;
|
||||
break;
|
||||
case 2:
|
||||
repeat = Regs[B] != 0;
|
||||
break;
|
||||
case 3:
|
||||
repeat = Regs[B] != 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// if we repeat, we do a 5 cycle refresh which decrements PC by 2
|
||||
// if we don't repeat, continue on as a normal opcode fetch
|
||||
if (repeat && temp3 > 0)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
DEC16, PCl, PCh,
|
||||
IDLE,
|
||||
DEC16, PCl, PCh,
|
||||
OP };
|
||||
|
||||
// adjust WZ register accordingly
|
||||
switch (temp1)
|
||||
{
|
||||
case 0:
|
||||
// TEST: PC before or after the instruction?
|
||||
Regs[Z] = Regs[PCl];
|
||||
Regs[W] = Regs[PCh];
|
||||
INC16_Func(Z, W);
|
||||
break;
|
||||
case 1:
|
||||
// TEST: PC before or after the instruction?
|
||||
Regs[Z] = Regs[PCl];
|
||||
Regs[W] = Regs[PCh];
|
||||
INC16_Func(Z, W);
|
||||
break;
|
||||
case 2:
|
||||
// Nothing
|
||||
break;
|
||||
case 3:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Interrupts can occur at this point, so process them accordingly
|
||||
// Read the opcode of the next instruction
|
||||
if (EI_pending > 0)
|
||||
{
|
||||
EI_pending--;
|
||||
if (EI_pending == 0) { IFF1 = IFF2 = true; }
|
||||
}
|
||||
|
||||
// Process interrupt requests.
|
||||
if (nonMaskableInterruptPending)
|
||||
{
|
||||
nonMaskableInterruptPending = false;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""});
|
||||
}
|
||||
|
||||
iff2 = iff1;
|
||||
iff1 = false;
|
||||
NMI_();
|
||||
NMICallback();
|
||||
}
|
||||
else if (iff1 && FlagI)
|
||||
{
|
||||
iff1 = iff2 = false;
|
||||
EI_pending = 0;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""});
|
||||
}
|
||||
|
||||
switch (interruptMode)
|
||||
{
|
||||
case 0:
|
||||
// Requires something to be pushed onto the data bus
|
||||
// we'll assume it's a zero for now
|
||||
INTERRUPT_0(0);
|
||||
break;
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
IRQCallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnExecFetch != null) OnExecFetch(RegPC);
|
||||
if (TraceCallback != null) TraceCallback(State());
|
||||
FetchInstruction(FetchMemory(RegPC++));
|
||||
}
|
||||
|
||||
temp_R = (byte)(Regs[R] & 0x7F);
|
||||
temp_R++;
|
||||
temp_R &= 0x7F;
|
||||
Regs[R] = (byte)((Regs[R] & 0x80) | temp_R);
|
||||
}
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
|
||||
case HALT:
|
||||
halted = true;
|
||||
if (EI_pending > 0)
|
||||
{
|
||||
EI_pending--;
|
||||
if (EI_pending == 0) { IFF1 = IFF2 = true; }
|
||||
}
|
||||
|
||||
// Process interrupt requests.
|
||||
if (nonMaskableInterruptPending)
|
||||
{
|
||||
nonMaskableInterruptPending = false;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""});
|
||||
}
|
||||
|
||||
iff2 = iff1;
|
||||
iff1 = false;
|
||||
NMI_();
|
||||
NMICallback();
|
||||
halted = false;
|
||||
}
|
||||
else if (iff1 && FlagI)
|
||||
{
|
||||
iff1 = iff2 = false;
|
||||
EI_pending = 0;
|
||||
|
||||
if (TraceCallback != null)
|
||||
{
|
||||
TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""});
|
||||
}
|
||||
|
||||
switch (interruptMode)
|
||||
{
|
||||
case 0:
|
||||
// Requires something to be pushed onto the data bus
|
||||
// we'll assume it's a zero for now
|
||||
INTERRUPT_0(0);
|
||||
break;
|
||||
case 1:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
IRQCallback();
|
||||
halted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
}
|
||||
temp_R = (byte)(Regs[R] & 0x7F);
|
||||
temp_R++;
|
||||
temp_R &= 0x7F;
|
||||
Regs[R] = (byte)((Regs[R] & 0x80) | temp_R);
|
||||
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case RD:
|
||||
Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case WR:
|
||||
Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case I_RD:
|
||||
I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case I_WR:
|
||||
I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case TR:
|
||||
TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case TR16:
|
||||
TR16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADD16:
|
||||
ADD16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADD8:
|
||||
ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SUB8:
|
||||
SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADC8:
|
||||
ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADC16:
|
||||
ADC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SBC8:
|
||||
SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SBC16:
|
||||
SBC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INC16:
|
||||
INC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INC8:
|
||||
INC8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DEC16:
|
||||
DEC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DEC8:
|
||||
DEC8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RLC:
|
||||
RLC_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RL:
|
||||
RL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RRC:
|
||||
RRC_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RR:
|
||||
RR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CPL:
|
||||
CPL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case DA:
|
||||
DA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SCF:
|
||||
SCF_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CCF:
|
||||
CCF_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case AND8:
|
||||
AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case XOR8:
|
||||
XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case OR8:
|
||||
OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case CP8:
|
||||
CP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SLA:
|
||||
SLA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SRA:
|
||||
SRA_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SRL:
|
||||
SRL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SLL:
|
||||
SLL_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case BIT:
|
||||
BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case I_BIT:
|
||||
I_BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RES:
|
||||
RES_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SET:
|
||||
SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case EI:
|
||||
EI_pending = 2;
|
||||
break;
|
||||
case DI:
|
||||
IFF1 = IFF2 = false;
|
||||
break;
|
||||
case EXCH:
|
||||
EXCH_16_Func(F_s, A_s, F, A);
|
||||
break;
|
||||
case EXX:
|
||||
EXCH_16_Func(C_s, B_s, C, B);
|
||||
EXCH_16_Func(E_s, D_s, E, D);
|
||||
EXCH_16_Func(L_s, H_s, L, H);
|
||||
break;
|
||||
case EXCH_16:
|
||||
EXCH_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case PREFIX:
|
||||
ushort prefix_src = cur_instr[instr_pntr++];
|
||||
NO_prefix = false;
|
||||
if (prefix_src == CBpre) { CB_prefix = true; }
|
||||
if (prefix_src == EXTDpre) { EXTD_prefix = true; }
|
||||
if (prefix_src == IXpre) { IX_prefix = true; }
|
||||
if (prefix_src == IYpre) { IY_prefix = true; }
|
||||
if (prefix_src == IXCBpre) { IXCB_prefix = true; IXCB_prefetch = true; }
|
||||
if (prefix_src == IYCBpre) { IYCB_prefix = true; IYCB_prefetch = true; }
|
||||
|
||||
FetchInstruction(FetchMemory(RegPC++));
|
||||
instr_pntr = 0;
|
||||
// only the first prefix in a double prefix increases R, although I don't know how / why
|
||||
if (prefix_src < 4)
|
||||
{
|
||||
temp_R = (byte)(Regs[R] & 0x7F);
|
||||
temp_R++;
|
||||
temp_R &= 0x7F;
|
||||
Regs[R] = (byte)((Regs[R] & 0x80) | temp_R);
|
||||
}
|
||||
break;
|
||||
case ASGN:
|
||||
ASGN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case ADDS:
|
||||
ADDS_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case EI_RETI:
|
||||
// NOTE: This is needed for systems using multiple interrupt sources, it triggers the next interrupt
|
||||
// Not currently implemented here
|
||||
iff1 = iff2;
|
||||
break;
|
||||
case EI_RETN:
|
||||
iff1 = iff2;
|
||||
break;
|
||||
case OUT:
|
||||
OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case IN:
|
||||
IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case NEG:
|
||||
NEG_8_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case INT_MODE:
|
||||
interruptMode = cur_instr[instr_pntr++];
|
||||
break;
|
||||
case RRD:
|
||||
RRD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case RLD:
|
||||
RLD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
|
||||
break;
|
||||
case SET_FL_LD:
|
||||
SET_FL_LD_Func();
|
||||
break;
|
||||
case SET_FL_CP:
|
||||
SET_FL_CP_Func();
|
||||
break;
|
||||
case SET_FL_IR:
|
||||
SET_FL_IR_Func(cur_instr[instr_pntr++]);
|
||||
break;
|
||||
}
|
||||
totalExecutedCycles++;
|
||||
}
|
||||
|
||||
// tracer stuff
|
||||
public Action<TraceInfo> TraceCallback;
|
||||
|
||||
public string TraceHeader
|
||||
{
|
||||
get { return "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; }
|
||||
}
|
||||
|
||||
public TraceInfo State(bool disassemble = true)
|
||||
{
|
||||
ushort bytes_read = 0;
|
||||
|
||||
string disasm = disassemble ? Disassemble(RegPC, ReadMemory, out bytes_read) : "---";
|
||||
string byte_code = null;
|
||||
|
||||
for (ushort i = 0; i < bytes_read; i++)
|
||||
{
|
||||
byte_code += ReadMemory((ushort)(RegPC + i)).ToHexString(2);
|
||||
if (i < (bytes_read - 1))
|
||||
{
|
||||
byte_code += " ";
|
||||
}
|
||||
}
|
||||
|
||||
return new TraceInfo
|
||||
{
|
||||
Disassembly = string.Format(
|
||||
"{0:X4}: {1} {2}",
|
||||
RegPC,
|
||||
byte_code.PadRight(12),
|
||||
disasm.PadRight(26)),
|
||||
RegisterInfo = string.Format(
|
||||
"AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4} Cy:{7} {8}{9}{10}{11}{12}{13}{14}{15}{16}",
|
||||
(Regs[A] << 8) + Regs[F],
|
||||
(Regs[B] << 8) + Regs[C],
|
||||
(Regs[D] << 8) + Regs[E],
|
||||
(Regs[H] << 8) + Regs[L],
|
||||
(Regs[Ixh] << 8) + Regs[Ixl],
|
||||
(Regs[Iyh] << 8) + Regs[Iyl],
|
||||
Regs[SPl] | (Regs[SPh] << 8),
|
||||
TotalExecutedCycles,
|
||||
FlagC ? "C" : "c",
|
||||
FlagN ? "N" : "n",
|
||||
FlagP ? "P" : "p",
|
||||
Flag3 ? "3" : "-",
|
||||
FlagH ? "H" : "h",
|
||||
Flag5 ? "5" : "-",
|
||||
FlagZ ? "Z" : "z",
|
||||
FlagS ? "S" : "s",
|
||||
FlagI ? "E" : "e")
|
||||
};
|
||||
}
|
||||
// State Save/Load
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Z80A");
|
||||
ser.Sync("Regs", ref Regs, false);
|
||||
ser.Sync("NMI", ref nonMaskableInterrupt);
|
||||
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
|
||||
ser.Sync("IM", ref interruptMode);
|
||||
ser.Sync("IFF1", ref iff1);
|
||||
ser.Sync("IFF2", ref iff2);
|
||||
ser.Sync("Halted", ref halted);
|
||||
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
|
||||
ser.Sync("EI_pending", ref EI_pending);
|
||||
|
||||
ser.Sync("instruction_pointer", ref instr_pntr);
|
||||
ser.Sync("current instruction", ref cur_instr, false);
|
||||
ser.Sync("opcode", ref opcode);
|
||||
ser.Sync("FlagI", ref FlagI);
|
||||
|
||||
ser.Sync("NO Preifx", ref NO_prefix);
|
||||
ser.Sync("CB Preifx", ref CB_prefix);
|
||||
ser.Sync("IX_prefix", ref IX_prefix);
|
||||
ser.Sync("IY_prefix", ref IY_prefix);
|
||||
ser.Sync("IXCB_prefix", ref IXCB_prefix);
|
||||
ser.Sync("IYCB_prefix", ref IYCB_prefix);
|
||||
ser.Sync("EXTD_prefix", ref EXTD_prefix);
|
||||
ser.Sync("IXCB_prefetch", ref IXCB_prefetch);
|
||||
ser.Sync("IYCB_prefetch", ref IYCB_prefetch);
|
||||
ser.Sync("PF", ref PF);
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = _cpu.RegisterA,
|
||||
["AF"] = _cpu.RegisterAF,
|
||||
["B"] = _cpu.RegisterB,
|
||||
["BC"] = _cpu.RegisterBC,
|
||||
["C"] = _cpu.RegisterC,
|
||||
["D"] = _cpu.RegisterD,
|
||||
["DE"] = _cpu.RegisterDE,
|
||||
["E"] = _cpu.RegisterE,
|
||||
["F"] = _cpu.RegisterF,
|
||||
["H"] = _cpu.RegisterH,
|
||||
["HL"] = _cpu.RegisterHL,
|
||||
["I"] = _cpu.RegisterI,
|
||||
["IX"] = _cpu.RegisterIX,
|
||||
["IY"] = _cpu.RegisterIY,
|
||||
["L"] = _cpu.RegisterL,
|
||||
["PC"] = _cpu.RegisterPC,
|
||||
["R"] = _cpu.RegisterR,
|
||||
["Shadow AF"] = _cpu.RegisterShadowAF,
|
||||
["Shadow BC"] = _cpu.RegisterShadowBC,
|
||||
["Shadow DE"] = _cpu.RegisterShadowDE,
|
||||
["Shadow HL"] = _cpu.RegisterShadowHL,
|
||||
["SP"] = _cpu.RegisterSP,
|
||||
["Flag C"] = _cpu.RegisterF.Bit(0),
|
||||
["Flag N"] = _cpu.RegisterF.Bit(1),
|
||||
["Flag P/V"] = _cpu.RegisterF.Bit(2),
|
||||
["Flag 3rd"] = _cpu.RegisterF.Bit(3),
|
||||
["Flag H"] = _cpu.RegisterF.Bit(4),
|
||||
["Flag 5th"] = _cpu.RegisterF.Bit(5),
|
||||
["Flag Z"] = _cpu.RegisterF.Bit(6),
|
||||
["Flag S"] = _cpu.RegisterF.Bit(7)
|
||||
["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,73 +49,85 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.RegisterA = (byte)value;
|
||||
break;
|
||||
case "AF":
|
||||
_cpu.RegisterAF = (byte)value;
|
||||
break;
|
||||
case "B":
|
||||
_cpu.RegisterB = (byte)value;
|
||||
break;
|
||||
case "BC":
|
||||
_cpu.RegisterBC = (byte)value;
|
||||
break;
|
||||
case "C":
|
||||
_cpu.RegisterC = (byte)value;
|
||||
break;
|
||||
case "D":
|
||||
_cpu.RegisterD = (byte)value;
|
||||
break;
|
||||
case "DE":
|
||||
_cpu.RegisterDE = (byte)value;
|
||||
break;
|
||||
case "E":
|
||||
_cpu.RegisterE = (byte)value;
|
||||
break;
|
||||
case "F":
|
||||
_cpu.RegisterF = (byte)value;
|
||||
break;
|
||||
case "H":
|
||||
_cpu.RegisterH = (byte)value;
|
||||
break;
|
||||
case "HL":
|
||||
_cpu.RegisterHL = (byte)value;
|
||||
break;
|
||||
case "I":
|
||||
_cpu.RegisterI = (byte)value;
|
||||
break;
|
||||
case "IX":
|
||||
_cpu.RegisterIX = (byte)value;
|
||||
break;
|
||||
case "IY":
|
||||
_cpu.RegisterIY = (byte)value;
|
||||
break;
|
||||
case "L":
|
||||
_cpu.RegisterL = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.RegisterPC = (ushort)value;
|
||||
break;
|
||||
case "R":
|
||||
_cpu.RegisterR = (byte)value;
|
||||
break;
|
||||
case "Shadow AF":
|
||||
_cpu.RegisterShadowAF = (byte)value;
|
||||
break;
|
||||
case "Shadow BC":
|
||||
_cpu.RegisterShadowBC = (byte)value;
|
||||
break;
|
||||
case "Shadow DE":
|
||||
_cpu.RegisterShadowDE = (byte)value;
|
||||
break;
|
||||
case "Shadow HL":
|
||||
_cpu.RegisterShadowHL = (byte)value;
|
||||
break;
|
||||
case "SP":
|
||||
_cpu.RegisterSP = (byte)value;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,21 +13,42 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
_controller = controller;
|
||||
_lagged = true;
|
||||
|
||||
_cpu.Debug = _tracer.Enabled;
|
||||
|
||||
if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
_cpu.Logger = s => _tracer.Put(s);
|
||||
_cpu.TraceCallback = s => _tracer.Put(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpu.TraceCallback = null;
|
||||
}
|
||||
|
||||
// I eyeballed this speed
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
_onPressed = controller.IsPressed("ON");
|
||||
_onPressed = controller.IsPressed("ON");
|
||||
|
||||
// and this was derived from other emus
|
||||
_cpu.ExecuteCycles(10000);
|
||||
_cpu.Interrupt = true;
|
||||
if (_onPressed && ON_key_int_EN && !ON_key_int)
|
||||
{
|
||||
ON_key_int = true;
|
||||
_cpu.FlagI = true;
|
||||
}
|
||||
|
||||
// see: http://wikiti.brandonw.net/index.php?title=83:Ports:04
|
||||
// for timer interrupt frequency
|
||||
|
||||
// CPU frequency is 6MHz
|
||||
for (int i = 0; i < 100000; i++)
|
||||
{
|
||||
_cpu.ExecuteOne();
|
||||
|
||||
TIM_count++;
|
||||
if (TIM_count >= TIM_hit)
|
||||
{
|
||||
TIM_count = 0;
|
||||
|
||||
if (TIM_1_int_EN)
|
||||
{
|
||||
TIM_1_int = true;
|
||||
_cpu.FlagI = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Frame++;
|
||||
|
|
|
@ -7,55 +7,52 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
{
|
||||
public partial class TI83 : IStatable
|
||||
{
|
||||
private byte[] _stateBuffer;
|
||||
public bool BinarySaveStatesPreferred
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public bool BinarySaveStatesPreferred => false;
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
SyncState(new Serializer(writer));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
SyncState(new Serializer(reader));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
SyncState(Serializer.CreateBinaryWriter(bw));
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(Serializer.CreateBinaryReader(br));
|
||||
}
|
||||
|
||||
public void SaveStateText(TextWriter tw)
|
||||
{
|
||||
SyncState(Serializer.CreateTextWriter(tw));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader tr)
|
||||
{
|
||||
SyncState(Serializer.CreateTextReader(tr));
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
if (_stateBuffer == null)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new BinaryWriter(stream);
|
||||
SaveStateBinary(writer);
|
||||
_stateBuffer = stream.ToArray();
|
||||
writer.Close();
|
||||
return _stateBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var stream = new MemoryStream(_stateBuffer);
|
||||
var writer = new BinaryWriter(stream);
|
||||
SaveStateBinary(writer);
|
||||
writer.Close();
|
||||
return _stateBuffer;
|
||||
}
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("TI83");
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
_cpu.SyncState(ser);
|
||||
|
||||
ser.BeginSection("TI83");
|
||||
ser.Sync("RAM", ref _ram, false);
|
||||
ser.Sync("romPageLow3Bits", ref _romPageLow3Bits);
|
||||
ser.Sync("romPageHighBit", ref _romPageHighBit);
|
||||
|
@ -72,6 +69,15 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("LagCount", ref _lagCount);
|
||||
ser.Sync("IsLag", ref _isLag);
|
||||
ser.Sync("ON_key_int", ref ON_key_int);
|
||||
ser.Sync("ON_key_int_EN", ref ON_key_int_EN);
|
||||
ser.Sync("TIM_1_int", ref TIM_1_int);
|
||||
ser.Sync("TIM_1_int_EN", ref TIM_1_int_EN);
|
||||
ser.Sync("TIM_frq", ref TIM_frq);
|
||||
ser.Sync("TIM_mult", ref TIM_mult);
|
||||
ser.Sync("TIM_count", ref TIM_count);
|
||||
ser.Sync("TIM_hit", ref TIM_hit);
|
||||
|
||||
ser.EndSection();
|
||||
|
||||
if (ser.IsReader)
|
||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.Globalization;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.Z80;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
|
||||
// http://www.ticalc.org/pub/text/calcinfo/
|
||||
namespace BizHawk.Emulation.Cores.Calculators
|
||||
|
@ -23,6 +23,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
PutSettings((TI83Settings)settings ?? new TI83Settings());
|
||||
|
||||
CoreComm = comm;
|
||||
_cpu.FetchMemory = ReadMemory;
|
||||
_cpu.ReadMemory = ReadMemory;
|
||||
_cpu.WriteMemory = WriteMemory;
|
||||
_cpu.ReadHardware = ReadHardware;
|
||||
|
@ -34,21 +35,13 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
_rom = rom;
|
||||
LinkPort = new TI83LinkPort(this);
|
||||
|
||||
// different calculators (different revisions?) have different initPC. we track this in the game database by rom hash
|
||||
// if( *(unsigned long *)(m_pRom + 0x6ce) == 0x04D3163E ) m_Regs.PC.W = 0x6ce; //KNOWN
|
||||
// else if( *(unsigned long *)(m_pRom + 0x6f6) == 0x04D3163E ) m_Regs.PC.W = 0x6f6; //UNKNOWN
|
||||
if (game["initPC"])
|
||||
{
|
||||
_startPC = ushort.Parse(game.OptionValue("initPC"), NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
HardReset();
|
||||
SetupMemoryDomains();
|
||||
|
||||
_tracer = new TraceBuffer { Header = _cpu.TraceHeader };
|
||||
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
ser.Register<IDisassemblable>(new Disassembler());
|
||||
ser.Register<IDisassemblable>(_cpu);
|
||||
}
|
||||
|
||||
private readonly TraceBuffer _tracer;
|
||||
|
@ -57,8 +50,6 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
private readonly byte[] _rom;
|
||||
|
||||
// configuration
|
||||
private readonly ushort _startPC;
|
||||
|
||||
private IController _controller;
|
||||
|
||||
private byte[] _ram;
|
||||
|
@ -75,6 +66,10 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
private bool _cursorMoved;
|
||||
private int _frame;
|
||||
|
||||
public bool ON_key_int, ON_key_int_EN;
|
||||
public bool TIM_1_int, TIM_1_int_EN;
|
||||
public int TIM_frq, TIM_mult, TIM_count, TIM_hit;
|
||||
|
||||
// Link Cable
|
||||
public TI83LinkPort LinkPort { get; }
|
||||
|
||||
|
@ -151,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
if (LinkActive)
|
||||
{
|
||||
// Prevent rom calls from disturbing link port activity
|
||||
if (LinkActive && _cpu.RegisterPC < 0x4000)
|
||||
if (LinkActive && _cpu.RegPC < 0x4000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -169,7 +164,60 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
_romPageLow3Bits = value & 0x7;
|
||||
break;
|
||||
case 3: // PORT_STATUS
|
||||
_maskOn = (byte)(value & 1);
|
||||
// controls ON key interrupts
|
||||
if ((value & 0x1) == 0)
|
||||
{
|
||||
ON_key_int = false;
|
||||
ON_key_int_EN = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ON_key_int_EN = true;
|
||||
}
|
||||
|
||||
// controls first timer interrupts
|
||||
if ((value & 0x2) == 0)
|
||||
{
|
||||
TIM_1_int = false;
|
||||
TIM_1_int_EN = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
TIM_1_int_EN = true;
|
||||
}
|
||||
|
||||
// controls second timer, not yet implemented and unclear how to differentiate
|
||||
if ((value & 0x4) == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
// controls low power mode, not yet implemeneted
|
||||
if ((value & 0x8) == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
break;
|
||||
case 4: // PORT_INTCTRL
|
||||
// controls ON key interrupts
|
||||
TIM_frq = value & 6;
|
||||
|
||||
TIM_mult = ((value & 0x10) == 0x10) ? 1800 : 1620;
|
||||
|
||||
TIM_hit = (int)Math.Floor((double)TIM_mult / (3 + TIM_frq * 2));
|
||||
|
||||
TIM_hit = (int)Math.Floor((double)6000000 / TIM_hit);
|
||||
|
||||
// Bit 0 is some form of memory mapping
|
||||
|
||||
// Bit 5 controls reset
|
||||
|
||||
// Bit 6-7 controls battery power compare (not implemented, will always return full power)
|
||||
|
||||
break;
|
||||
case 16: // PORT_DISPCTRL
|
||||
////Console.WriteLine("write PORT_DISPCTRL {0}",value);
|
||||
|
@ -198,22 +246,23 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
{
|
||||
// Console.WriteLine("read PORT_STATUS");
|
||||
// Bits:
|
||||
// 0 - Set if ON key is down and ON key is trapped
|
||||
// 0 - Set if ON key Interrupt generated
|
||||
// 1 - Update things (keyboard etc)
|
||||
// 2 - Unknown, but used
|
||||
// 3 - Set if ON key is up
|
||||
// 4-7 - Unknown
|
||||
////if (onPressed && maskOn) ret |= 1;
|
||||
////if (!onPressed) ret |= 0x8;
|
||||
return (byte)((_controller.IsPressed("ON") ? _maskOn : 8) | (LinkActive ? 0 : 2));
|
||||
|
||||
return (byte)((_controller.IsPressed("ON") ? 0 : 8) |
|
||||
(TIM_1_int ? 2 : 0) |
|
||||
(ON_key_int ? 1 : 0));
|
||||
}
|
||||
|
||||
case 4: // PORT_INTCTRL
|
||||
////Console.WriteLine("read PORT_INTCTRL");
|
||||
return 0xFF;
|
||||
// returns mirror of link port
|
||||
return (byte)((_romPageHighBit << 4) | (LinkState << 2) | LinkOutput);
|
||||
|
||||
case 16: // PORT_DISPCTRL
|
||||
////Console.WriteLine("read DISPCTRL");
|
||||
// Console.WriteLine("read DISPCTRL");
|
||||
break;
|
||||
|
||||
case 17: // PORT_DISPDATA
|
||||
|
@ -428,13 +477,13 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
|
||||
private void IRQCallback()
|
||||
{
|
||||
// Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", cpu.RegisterI, cpu.InterruptMode);
|
||||
_cpu.Interrupt = false;
|
||||
//Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", _cpu.Regs[_cpu.I], _cpu.InterruptMode);
|
||||
_cpu.FlagI = false;
|
||||
}
|
||||
|
||||
private void NMICallback()
|
||||
{
|
||||
Console.WriteLine("NMI");
|
||||
//Console.WriteLine("NMI");
|
||||
_cpu.NonMaskableInterrupt = false;
|
||||
}
|
||||
|
||||
|
@ -447,7 +496,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
_ram[i] = 0xFF;
|
||||
}
|
||||
|
||||
_cpu.RegisterPC = _startPC;
|
||||
_cpu.RegPC = 0;
|
||||
|
||||
_cpu.IFF1 = false;
|
||||
_cpu.IFF2 = false;
|
||||
|
@ -463,4 +512,4 @@ namespace BizHawk.Emulation.Cores.Calculators
|
|||
_displayX = _displayY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
private IController _controller;
|
||||
private int _frame;
|
||||
private int _lastAddress;
|
||||
private bool _frameStartPending = true;
|
||||
|
||||
private bool _leftDifficultySwitchPressed;
|
||||
private bool _rightDifficultySwitchPressed;
|
||||
|
@ -34,6 +33,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
internal byte[] Rom { get; }
|
||||
internal int DistinctAccessCount { get; private set; }
|
||||
|
||||
// keeps track of tia cycles, 3 cycles per CPU cycle
|
||||
private int cyc_counter;
|
||||
|
||||
private static MapperBase SetMultiCartMapper(int romLength, int gameTotal)
|
||||
{
|
||||
switch (romLength / gameTotal)
|
||||
|
@ -319,17 +321,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
|
||||
_m6532 = new M6532(this);
|
||||
|
||||
// Set up the system state here. for instance..
|
||||
// Read from the reset vector for where to start
|
||||
Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC
|
||||
HardReset();
|
||||
|
||||
// Show mapper class on romstatusdetails
|
||||
CoreComm.RomStatusDetails = $"{this._game.Name}\r\nSHA1:{Rom.HashSHA1()}\r\nMD5:{Rom.HashMD5()}\r\nMapper Impl \"{_mapper.GetType()}\"";
|
||||
|
||||
// as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves.
|
||||
// some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532
|
||||
// executing a reset sequence at power on, but it's needed so let's hard code it for now
|
||||
Cpu.S = 0xFD;
|
||||
}
|
||||
|
||||
private bool _pal;
|
||||
|
@ -349,96 +344,28 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
};
|
||||
|
||||
_tia.Reset();
|
||||
|
||||
_m6532 = new M6532(this);
|
||||
Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC
|
||||
|
||||
// as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves.
|
||||
// some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532
|
||||
// executing a reset sequence at power on, but it's needed so let's hard code it for now
|
||||
Cpu.S = 0xFD;
|
||||
|
||||
SetupMemoryDomains();
|
||||
}
|
||||
|
||||
private void VFrameAdvance() // advance up to 500 lines looking for end of video frame
|
||||
// after vsync falling edge, continues to end of next line
|
||||
{
|
||||
bool frameend = false;
|
||||
_tia.FrameEndCallBack = (n) => frameend = true;
|
||||
for (int i = 0; i < 500 && !frameend; i++)
|
||||
{
|
||||
ScanlineAdvance();
|
||||
}
|
||||
|
||||
_tia.FrameEndCallBack = null;
|
||||
}
|
||||
|
||||
private void StartFrameCond()
|
||||
{
|
||||
if (_frameStartPending)
|
||||
{
|
||||
_frame++;
|
||||
_islag = true;
|
||||
|
||||
if (_controller.IsPressed("Power"))
|
||||
{
|
||||
HardReset();
|
||||
}
|
||||
|
||||
if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld)
|
||||
{
|
||||
_leftDifficultySwitchPressed ^= true;
|
||||
_leftDifficultySwitchHeld = true;
|
||||
}
|
||||
else if (!_controller.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
_leftDifficultySwitchHeld = false;
|
||||
}
|
||||
|
||||
if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld)
|
||||
{
|
||||
_rightDifficultySwitchPressed ^= true;
|
||||
_rightDifficultySwitchHeld = true;
|
||||
}
|
||||
else if (!_controller.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
_rightDifficultySwitchHeld = false;
|
||||
}
|
||||
|
||||
_tia.BeginAudioFrame();
|
||||
_frameStartPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void FinishFrameCond()
|
||||
{
|
||||
if (_tia.LineCount >= _tia.NominalNumScanlines)
|
||||
{
|
||||
_tia.CompleteAudioFrame();
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
|
||||
_tia.LineCount = 0;
|
||||
_frameStartPending = true;
|
||||
}
|
||||
cyc_counter = 0;
|
||||
}
|
||||
|
||||
private void Cycle()
|
||||
{
|
||||
_tia.Execute(1);
|
||||
_tia.Execute(1);
|
||||
_tia.Execute(1);
|
||||
_m6532.Timer.Tick();
|
||||
if (Tracer.Enabled)
|
||||
_tia.Execute();
|
||||
cyc_counter++;
|
||||
if (cyc_counter == 3)
|
||||
{
|
||||
Tracer.Put(Cpu.TraceState());
|
||||
}
|
||||
_m6532.Timer.Tick();
|
||||
if (Tracer.Enabled)
|
||||
{
|
||||
Tracer.Put(Cpu.TraceState());
|
||||
}
|
||||
|
||||
Cpu.ExecuteOne();
|
||||
_mapper.ClockCpu();
|
||||
Cpu.ExecuteOne();
|
||||
_mapper.ClockCpu();
|
||||
|
||||
cyc_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte ReadControls1(bool peek)
|
||||
|
|
|
@ -60,97 +60,18 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
case StepType.Out:
|
||||
case StepType.Over:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case StepType.Into:
|
||||
StepInto();
|
||||
break;
|
||||
case StepType.Out:
|
||||
StepOut();
|
||||
break;
|
||||
case StepType.Over:
|
||||
StepOver();
|
||||
break;
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public int TotalExecutedCycles => Cpu.TotalExecutedCycles;
|
||||
|
||||
private void StepInto()
|
||||
{
|
||||
do
|
||||
{
|
||||
CycleAdvance();
|
||||
} while (!Cpu.AtStart);
|
||||
}
|
||||
|
||||
private void StepOver()
|
||||
{
|
||||
var instruction = Cpu.PeekMemory(Cpu.PC);
|
||||
|
||||
if (instruction == JSR)
|
||||
{
|
||||
var destination = Cpu.PC + opsize[JSR];
|
||||
while (Cpu.PC != destination)
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StepInto();
|
||||
}
|
||||
}
|
||||
|
||||
private void StepOut()
|
||||
{
|
||||
var instruction = Cpu.PeekMemory(Cpu.PC);
|
||||
|
||||
JSRCount = instruction == JSR ? 1 : 0;
|
||||
|
||||
var bailOutFrame = Frame + 1;
|
||||
while (true)
|
||||
{
|
||||
StepInto();
|
||||
var instr = Cpu.PeekMemory(Cpu.PC);
|
||||
if (instr == JSR)
|
||||
{
|
||||
JSRCount++;
|
||||
}
|
||||
else if (instr == RTS && JSRCount <= 0)
|
||||
{
|
||||
StepInto();
|
||||
JSRCount = 0;
|
||||
break;
|
||||
}
|
||||
else if (instr == RTS)
|
||||
{
|
||||
JSRCount--;
|
||||
}
|
||||
else // Emergency bail out logic
|
||||
{
|
||||
if (Frame == bailOutFrame)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int JSRCount = 0;
|
||||
|
||||
private const byte JSR = 0x20;
|
||||
|
@ -212,22 +133,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
|
||||
#region Currently Unused Debug hooks
|
||||
|
||||
private void ScanlineAdvance()
|
||||
{
|
||||
StartFrameCond();
|
||||
int currentLine = _tia.LineCount;
|
||||
while (_tia.LineCount == currentLine)
|
||||
Cycle();
|
||||
FinishFrameCond();
|
||||
}
|
||||
|
||||
private void CycleAdvance()
|
||||
{
|
||||
StartFrameCond();
|
||||
Cycle();
|
||||
FinishFrameCond();
|
||||
}
|
||||
|
||||
private int CurrentScanLine
|
||||
{
|
||||
get { return _tia.LineCount; }
|
||||
|
|
|
@ -12,18 +12,53 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
{
|
||||
_controller = controller;
|
||||
|
||||
StartFrameCond();
|
||||
while (_tia.LineCount < _tia.NominalNumScanlines)
|
||||
_frame++;
|
||||
_islag = true;
|
||||
|
||||
// Handle all the console controls here
|
||||
if (_controller.IsPressed("Power"))
|
||||
{
|
||||
HardReset();
|
||||
}
|
||||
|
||||
if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld)
|
||||
{
|
||||
_leftDifficultySwitchPressed ^= true;
|
||||
_leftDifficultySwitchHeld = true;
|
||||
}
|
||||
else if (!_controller.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
_leftDifficultySwitchHeld = false;
|
||||
}
|
||||
|
||||
if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld)
|
||||
{
|
||||
_rightDifficultySwitchPressed ^= true;
|
||||
_rightDifficultySwitchHeld = true;
|
||||
}
|
||||
else if (!_controller.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
_rightDifficultySwitchHeld = false;
|
||||
}
|
||||
|
||||
while (!_tia.New_Frame)
|
||||
{
|
||||
Cycle();
|
||||
}
|
||||
|
||||
_tia.New_Frame = false;
|
||||
|
||||
if (rendersound == false)
|
||||
{
|
||||
_tia.AudioClocks = 0; // we need this here since the async sound provider won't check in this case
|
||||
}
|
||||
|
||||
FinishFrameCond();
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
|
||||
_tia.LineCount = 0;
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
ser.Sync("Lag", ref _lagcount);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("IsLag", ref _islag);
|
||||
ser.Sync("frameStartPending", ref _frameStartPending);
|
||||
ser.Sync("cyc_counter", ref cyc_counter);
|
||||
ser.Sync("leftDifficultySwitchPressed", ref _leftDifficultySwitchPressed);
|
||||
ser.Sync("rightDifficultySwitchPressed", ref _rightDifficultySwitchPressed);
|
||||
ser.Sync("leftDifficultySwitchHeld", ref _leftDifficultySwitchHeld);
|
||||
|
|
|
@ -102,18 +102,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
// give the emu a minimal of input\output connections so it doesn't crash
|
||||
var comm = new CoreComm(null, null);
|
||||
|
||||
|
||||
// here we advance past start up irregularities to see how long a frame is based on calls to Vsync
|
||||
// we run 72 frames, then run 270 scanlines worth of cycles.
|
||||
// if we don't hit a new frame, we can be pretty confident we are in PAL
|
||||
using (Atari2600 emu = new Atari2600(new CoreComm(null, null), newgame, rom, null, null))
|
||||
{
|
||||
List<int> framecounts = new List<int>();
|
||||
emu._tia.FrameEndCallBack = (i) => framecounts.Add(i);
|
||||
for (int i = 0; i < 71; i++) // run for 71 * 262 lines, since we're in NTSC mode
|
||||
for (int i = 0; i < 72; i++)
|
||||
{
|
||||
emu.FrameAdvance(NullController.Instance, false, false);
|
||||
}
|
||||
|
||||
int numpal = framecounts.Count((i) => i > 287);
|
||||
bool pal = numpal >= 25;
|
||||
Console.WriteLine("PAL Detection: {0} lines, {1}", numpal, pal);
|
||||
for (int i = 0; i < 61560; i++)
|
||||
{
|
||||
emu.Cycle();
|
||||
}
|
||||
|
||||
bool pal = !emu._tia.New_Frame;
|
||||
|
||||
Console.WriteLine("PAL Detection: {0}", pal);
|
||||
return pal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
_spf = _vsyncNum / (double)_vsyncDen > 55.0 ? 735 : 882;
|
||||
}
|
||||
|
||||
// indicates to the core where a new frame is starting
|
||||
public bool New_Frame = false;
|
||||
|
||||
private const int BackColor = unchecked((int)0xff000000);
|
||||
private const int ScreenWidth = 160;
|
||||
private const int MaxScreenHeight = 312;
|
||||
|
@ -161,11 +164,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
/// </summary>
|
||||
public int LineCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a callback that is called at the end of a video frame. used internally
|
||||
/// </summary>
|
||||
public Action<int> FrameEndCallBack { private get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_hsyncCnt = 0;
|
||||
|
@ -229,11 +227,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
|
||||
// Execute TIA cycles
|
||||
public void Execute(int cycles)
|
||||
public void Execute()
|
||||
{
|
||||
// Still ignoring cycles...
|
||||
|
||||
// delay vblank latch
|
||||
// Handle all of the Latch delays that occur in the TIA
|
||||
if (_vblankDelay > 0)
|
||||
{
|
||||
_vblankDelay++;
|
||||
|
@ -244,7 +240,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
}
|
||||
|
||||
// delay latch to new playfield register
|
||||
if (_pf0Updater)
|
||||
{
|
||||
_pf0DelayClock++;
|
||||
|
@ -275,7 +270,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
}
|
||||
|
||||
// delay latch to missile enable
|
||||
if (_enam0Delay > 0)
|
||||
{
|
||||
_enam0Delay++;
|
||||
|
@ -296,7 +290,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
}
|
||||
|
||||
// delay latch to ball enable
|
||||
if (_enambDelay > 0)
|
||||
{
|
||||
_enambDelay++;
|
||||
|
@ -307,7 +300,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
}
|
||||
|
||||
// delay latch to player graphics registers
|
||||
if (_prg0Delay > 0)
|
||||
{
|
||||
_prg0Delay++;
|
||||
|
@ -333,7 +325,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
}
|
||||
|
||||
// HMP write delay
|
||||
if (_hmp0Delay > 0)
|
||||
{
|
||||
_hmp0Delay++;
|
||||
|
@ -773,9 +764,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
// do the audio sampling
|
||||
if (_hsyncCnt == 36 || _hsyncCnt == 148)
|
||||
{
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2);
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2);
|
||||
AudioClocks++;
|
||||
if (AudioClocks < 2000)
|
||||
{
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2);
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2);
|
||||
AudioClocks++;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the hsync counter
|
||||
|
@ -796,7 +790,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
int topLine = _pal ? _core.Settings.PALTopLine : _core.Settings.NTSCTopLine;
|
||||
int bottomLine = _pal ? _core.Settings.PALBottomLine : _core.Settings.NTSCBottomLine;
|
||||
|
||||
// if vsync occured unexpectedly early, black out the remainer
|
||||
// if vsync occured unexpectedly early, black out the remainder
|
||||
for (; validlines < bottomLine; validlines++)
|
||||
{
|
||||
for (int i = 0; i < 160; i++)
|
||||
|
@ -972,7 +966,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
// write to frame buffer
|
||||
OutputFrame(_currentScanLine);
|
||||
|
||||
FrameEndCallBack?.Invoke(_currentScanLine);
|
||||
New_Frame = true;
|
||||
|
||||
// Clear all from last frame
|
||||
_currentScanLine = 0;
|
||||
|
@ -1337,17 +1331,5 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
{
|
||||
AUDC, AUDF, AUDV
|
||||
}
|
||||
|
||||
private int _frameStartCycles, _frameEndCycles;
|
||||
|
||||
public void BeginAudioFrame()
|
||||
{
|
||||
_frameStartCycles = _core.Cpu.TotalExecutedCycles;
|
||||
}
|
||||
|
||||
public void CompleteAudioFrame()
|
||||
{
|
||||
_frameEndCycles = _core.Cpu.TotalExecutedCycles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,10 +62,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
ser.Sync("vblankEnabled", ref _vblankEnabled);
|
||||
ser.Sync("vsyncEnabled", ref _vsyncEnabled);
|
||||
ser.Sync("CurrentScanLine", ref _currentScanLine);
|
||||
ser.Sync("scanlinebuffer", ref _scanlinebuffer, false);
|
||||
ser.Sync("AudioClocks", ref AudioClocks);
|
||||
ser.Sync("FrameStartCycles", ref _frameStartCycles);
|
||||
ser.Sync("FrameEndCycles", ref _frameEndCycles);
|
||||
ser.Sync("New_Frame", ref New_Frame);
|
||||
|
||||
ser.BeginSection("Player0");
|
||||
_player0.SyncState(ser);
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public partial class Atari7800 : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = _theMachine.CPU.A,
|
||||
["P"] = _theMachine.CPU.P,
|
||||
["PC"] = _theMachine.CPU.PC,
|
||||
["S"] = _theMachine.CPU.S,
|
||||
["X"] = _theMachine.CPU.X,
|
||||
["Y"] = _theMachine.CPU.Y,
|
||||
["Flag B"] = _theMachine.CPU.fB,
|
||||
["Flag C"] = _theMachine.CPU.fC,
|
||||
["Flag D"] = _theMachine.CPU.fD,
|
||||
["Flag I"] = _theMachine.CPU.fI,
|
||||
["Flag N"] = _theMachine.CPU.fN,
|
||||
["Flag V"] = _theMachine.CPU.fV,
|
||||
["Flag Z"] = _theMachine.CPU.fZ
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_theMachine.CPU.A = (byte)value;
|
||||
break;
|
||||
case "P":
|
||||
_theMachine.CPU.P = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
_theMachine.CPU.PC = (ushort)value;
|
||||
break;
|
||||
case "S":
|
||||
_theMachine.CPU.S = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
_theMachine.CPU.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
_theMachine.CPU.Y = (byte)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks
|
||||
{
|
||||
[FeatureNotImplemented]
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles => (int)_theMachine.CPU.Clock;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public partial class Atari7800 : IEmulator
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition { get; private set; }
|
||||
|
||||
public void FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
_frame++;
|
||||
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
// it seems that theMachine.Reset() doesn't clear ram, etc
|
||||
// this should leave hsram intact but clear most other things
|
||||
HardReset();
|
||||
}
|
||||
|
||||
ControlAdapter.Convert(controller, _theMachine.InputState);
|
||||
_theMachine.ComputeNextFrame(_avProvider.Framebuffer);
|
||||
|
||||
_islag = _theMachine.InputState.Lagged;
|
||||
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
|
||||
_avProvider.FillFrameBuffer();
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "A78"; // TODO 2600?
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_frame = 0;
|
||||
_lagcount = 0;
|
||||
_islag = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_avProvider != null)
|
||||
{
|
||||
_avProvider.Dispose();
|
||||
_avProvider = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public partial class Atari7800 : IInputPollable
|
||||
{
|
||||
public int LagCount
|
||||
{
|
||||
get { return _lagcount; }
|
||||
set { _lagcount = value; }
|
||||
}
|
||||
|
||||
public bool IsLagFrame
|
||||
{
|
||||
get { return _islag; }
|
||||
set { _islag = value; }
|
||||
}
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
private bool _islag = true;
|
||||
private int _lagcount;
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using EMU7800.Core;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public partial class Atari7800
|
||||
{
|
||||
private List<MemoryDomain> _MemoryDomains;
|
||||
|
||||
private IMemoryDomains MemoryDomains;
|
||||
|
||||
public void SetupMemoryDomains(HSC7800 hsc7800)
|
||||
{
|
||||
// reset memory domains
|
||||
if (_MemoryDomains == null)
|
||||
{
|
||||
_MemoryDomains = new List<MemoryDomain>();
|
||||
if (_theMachine is Machine7800)
|
||||
{
|
||||
_MemoryDomains.Add(new MemoryDomainDelegate(
|
||||
"RAM", 0x1000, MemoryDomain.Endian.Unknown,
|
||||
delegate(long addr)
|
||||
{
|
||||
if (addr < 0 || addr >= 0x1000)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (addr < 0x800)
|
||||
{
|
||||
return ((Machine7800)_theMachine).RAM1[(ushort)addr];
|
||||
}
|
||||
|
||||
return ((Machine7800)_theMachine).RAM2[(ushort)addr];
|
||||
},
|
||||
|
||||
delegate(long addr, byte val)
|
||||
{
|
||||
if (addr < 0 || addr >= 0x1000)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
else if (addr < 0x800)
|
||||
{
|
||||
((Machine7800)_theMachine).RAM1[(ushort)(addr & 0x800)] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
((Machine7800)_theMachine).RAM2[(ushort)addr] = val;
|
||||
}
|
||||
}, 1));
|
||||
|
||||
_MemoryDomains.Add(new MemoryDomainByteArray(
|
||||
"BIOS ROM", MemoryDomain.Endian.Unknown,
|
||||
_bios, false, 1));
|
||||
|
||||
if (hsc7800 != null)
|
||||
{
|
||||
_MemoryDomains.Add(new MemoryDomainByteArray(
|
||||
"HSC ROM", MemoryDomain.Endian.Unknown, _hsbios, false, 1));
|
||||
|
||||
_MemoryDomains.Add(new MemoryDomainByteArray(
|
||||
"HSC RAM", MemoryDomain.Endian.Unknown, _hsram, true, 1));
|
||||
}
|
||||
|
||||
_MemoryDomains.Add(new MemoryDomainDelegate(
|
||||
"System Bus", 65536, MemoryDomain.Endian.Unknown,
|
||||
delegate(long addr)
|
||||
{
|
||||
if (addr < 0 || addr >= 0x10000)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
return _theMachine.Mem[(ushort)addr];
|
||||
},
|
||||
delegate(long addr, byte val)
|
||||
{
|
||||
if (addr < 0 || addr >= 0x10000)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
_theMachine.Mem[(ushort)addr] = val;
|
||||
}, 1));
|
||||
}
|
||||
else // todo 2600?
|
||||
{
|
||||
}
|
||||
|
||||
MemoryDomains = new MemoryDomainList(_MemoryDomains);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
using EMU7800.Core;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public partial class Atari7800 : ISaveRam
|
||||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
return (byte[])_hsram.Clone();
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
Buffer.BlockCopy(data, 0, _hsram, 0, data.Length);
|
||||
}
|
||||
|
||||
public bool SaveRamModified => _gameInfo.MachineType == MachineType.A7800PAL
|
||||
|| _gameInfo.MachineType == MachineType.A7800NTSC;
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using EMU7800.Core;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public partial class Atari7800 : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => 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();
|
||||
_theMachine.Serialize(new BinaryWriter(ms));
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
|
||||
ser.BeginSection("Atari7800");
|
||||
ser.Sync("core", ref core, false);
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("IsLag", ref _islag);
|
||||
ser.EndSection();
|
||||
if (ser.IsReader)
|
||||
{
|
||||
_theMachine = MachineBase.Deserialize(new BinaryReader(new MemoryStream(core, false)));
|
||||
_avProvider.ConnectToMachine(_theMachine, _gameInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,301 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using EMU7800.Core;
|
||||
using EMU7800.Win;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
[Core(
|
||||
"EMU7800",
|
||||
"",
|
||||
isPorted: true,
|
||||
isReleased: true,
|
||||
portedVersion: "v1.5",
|
||||
portedUrl: "http://emu7800.sourceforge.net/")]
|
||||
[ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))]
|
||||
public partial class Atari7800 : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable
|
||||
{
|
||||
// TODO:
|
||||
// some things don't work when you try to plug in a 2600 game
|
||||
static Atari7800()
|
||||
{
|
||||
// add alpha bits to palette tables
|
||||
for (int i = 0; i < TIATables.NTSCPalette.Length; i++)
|
||||
{
|
||||
TIATables.NTSCPalette[i] |= unchecked((int)0xff000000);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TIATables.PALPalette.Length; i++)
|
||||
{
|
||||
TIATables.PALPalette[i] |= unchecked((int)0xff000000);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MariaTables.NTSCPalette.Length; i++)
|
||||
{
|
||||
MariaTables.NTSCPalette[i] |= unchecked((int)0xff000000);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MariaTables.PALPalette.Length; i++)
|
||||
{
|
||||
MariaTables.PALPalette[i] |= unchecked((int)0xff000000);
|
||||
}
|
||||
}
|
||||
|
||||
public Atari7800(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ser.Register<IVideoProvider>(_avProvider);
|
||||
ser.Register<ISoundProvider>(_avProvider);
|
||||
ServiceProvider = ser;
|
||||
|
||||
CoreComm = comm;
|
||||
byte[] highscoreBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS.");
|
||||
byte[] palBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available.");
|
||||
byte[] ntscBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_NTSC", false, "The game will not run if the correct region BIOS is not available.");
|
||||
|
||||
if (GameProgramLibrary.EMU7800DB == null)
|
||||
{
|
||||
GameProgramLibrary.EMU7800DB = new GameProgramLibrary(new StreamReader(gameDbFn));
|
||||
}
|
||||
|
||||
if (rom.Length % 1024 == 128)
|
||||
{
|
||||
Console.WriteLine("Trimming 128 byte .a78 header...");
|
||||
byte[] newrom = new byte[rom.Length - 128];
|
||||
Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length);
|
||||
rom = newrom;
|
||||
}
|
||||
|
||||
_gameInfo = GameProgramLibrary.EMU7800DB.TryRecognizeRom(rom);
|
||||
CoreComm.RomStatusDetails = _gameInfo.ToString();
|
||||
Console.WriteLine("Rom Determiniation from 7800DB:");
|
||||
Console.WriteLine(_gameInfo.ToString());
|
||||
|
||||
_rom = rom;
|
||||
_hsbios = highscoreBios;
|
||||
_bios = _gameInfo.MachineType == MachineType.A7800PAL ? palBios : ntscBios;
|
||||
_pal = _gameInfo.MachineType == MachineType.A7800PAL || _gameInfo.MachineType == MachineType.A2600PAL;
|
||||
|
||||
if (_bios == null)
|
||||
{
|
||||
throw new MissingFirmwareException("The BIOS corresponding to the region of the game you loaded is required to run Atari 7800 games.");
|
||||
}
|
||||
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public DisplayType Region => _pal ? DisplayType.PAL : DisplayType.NTSC;
|
||||
|
||||
public Atari7800Control ControlAdapter { get; private set; }
|
||||
|
||||
private readonly byte[] _rom;
|
||||
private readonly byte[] _hsbios;
|
||||
private readonly byte[] _bios;
|
||||
private readonly GameProgram _gameInfo;
|
||||
private readonly byte[] _hsram = new byte[2048];
|
||||
private readonly bool _pal;
|
||||
|
||||
private Cart _cart;
|
||||
private MachineBase _theMachine;
|
||||
private int _frame = 0;
|
||||
|
||||
private class ConsoleLogger : ILogger
|
||||
{
|
||||
public void WriteLine(string format, params object[] args)
|
||||
{
|
||||
Console.WriteLine(format, args);
|
||||
}
|
||||
|
||||
public void WriteLine(object value)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
|
||||
public void Write(string format, params object[] args)
|
||||
{
|
||||
Console.Write(format, args);
|
||||
}
|
||||
|
||||
public void Write(object value)
|
||||
{
|
||||
Console.Write(value);
|
||||
}
|
||||
}
|
||||
|
||||
private void HardReset()
|
||||
{
|
||||
_cart = Cart.Create(_rom, _gameInfo.CartType);
|
||||
ILogger logger = new ConsoleLogger();
|
||||
|
||||
HSC7800 hsc7800 = null;
|
||||
if (_hsbios != null)
|
||||
{
|
||||
hsc7800 = new HSC7800(_hsbios, _hsram);
|
||||
}
|
||||
|
||||
Bios7800 bios7800 = new Bios7800(_bios);
|
||||
_theMachine = MachineBase.Create(
|
||||
_gameInfo.MachineType,
|
||||
_cart,
|
||||
bios7800,
|
||||
hsc7800,
|
||||
_gameInfo.LController,
|
||||
_gameInfo.RController,
|
||||
logger);
|
||||
|
||||
_theMachine.Reset();
|
||||
_theMachine.InputState.InputPollCallback = InputCallbacks.Call;
|
||||
|
||||
ControlAdapter = new Atari7800Control(_theMachine);
|
||||
ControllerDefinition = ControlAdapter.ControlType;
|
||||
|
||||
_avProvider.ConnectToMachine(_theMachine, _gameInfo);
|
||||
|
||||
SetupMemoryDomains(hsc7800);
|
||||
}
|
||||
|
||||
#region audio\video
|
||||
|
||||
private MyAVProvider _avProvider = new MyAVProvider();
|
||||
|
||||
private class MyAVProvider : IVideoProvider, ISoundProvider, IDisposable
|
||||
{
|
||||
// to sync exactly with audio as this emulator creates and times it, the frame rate should be exactly 60:1 or 50:1
|
||||
private int _frameHz;
|
||||
|
||||
public FrameBuffer Framebuffer { get; private set; }
|
||||
public void ConnectToMachine(MachineBase m, GameProgram g)
|
||||
{
|
||||
_frameHz = m.FrameHZ;
|
||||
Framebuffer = m.CreateFrameBuffer();
|
||||
BufferWidth = Framebuffer.VisiblePitch;
|
||||
BufferHeight = Framebuffer.Scanlines;
|
||||
_vidbuffer = new int[BufferWidth * BufferHeight];
|
||||
|
||||
uint newsamplerate = (uint)m.SoundSampleFrequency;
|
||||
if (newsamplerate != _samplerate)
|
||||
{
|
||||
// really shouldn't happen (after init), but if it does, we're ready
|
||||
_resampler?.Dispose();
|
||||
_resampler = new SpeexResampler((SpeexResampler.Quality)3, newsamplerate, 44100, newsamplerate, 44100, null, null);
|
||||
_samplerate = newsamplerate;
|
||||
_dcfilter = new DCFilter(256);
|
||||
}
|
||||
|
||||
if (g.MachineType == MachineType.A2600PAL)
|
||||
{
|
||||
_palette = TIATables.PALPalette;
|
||||
}
|
||||
else if (g.MachineType == MachineType.A7800PAL)
|
||||
{
|
||||
_palette = MariaTables.PALPalette;
|
||||
}
|
||||
else if (g.MachineType == MachineType.A2600NTSC)
|
||||
{
|
||||
_palette = TIATables.NTSCPalette;
|
||||
}
|
||||
else
|
||||
{
|
||||
_palette = MariaTables.NTSCPalette;
|
||||
}
|
||||
}
|
||||
|
||||
private uint _samplerate;
|
||||
private int[] _vidbuffer;
|
||||
private SpeexResampler _resampler;
|
||||
private DCFilter _dcfilter;
|
||||
private int[] _palette;
|
||||
|
||||
public void FillFrameBuffer()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* src_ = Framebuffer.VideoBuffer)
|
||||
fixed (int* dst_ = _vidbuffer)
|
||||
fixed (int* pal = _palette)
|
||||
{
|
||||
byte* src = src_;
|
||||
int* dst = dst_;
|
||||
for (int i = 0; i < _vidbuffer.Length; i++)
|
||||
{
|
||||
*dst++ = pal[*src++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 275;
|
||||
public int VirtualHeight => BufferHeight;
|
||||
public int BufferWidth { get; private set; }
|
||||
public int BufferHeight { get; private set; }
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
public int VsyncNumerator => _frameHz;
|
||||
public int VsyncDenominator => 1;
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
int nsampin = Framebuffer.SoundBufferByteLength;
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* src = Framebuffer.SoundBuffer)
|
||||
{
|
||||
for (int i = 0; i < nsampin; i++)
|
||||
{
|
||||
// the buffer values don't really get very large at all,
|
||||
// so this doesn't overflow
|
||||
short s = (short)(src[i] * 200);
|
||||
_resampler.EnqueueSample(s, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_resampler.GetSamplesSync(out samples, out nsamp);
|
||||
_dcfilter.PushThroughSamples(samples, nsamp * 2);
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_resampler?.DiscardSamples();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_resampler != null)
|
||||
{
|
||||
_resampler.Dispose();
|
||||
_resampler = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,411 +0,0 @@
|
|||
using System;
|
||||
|
||||
using EMU7800.Core;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||
{
|
||||
public class Atari7800Control
|
||||
{
|
||||
private static readonly ControllerDefinition Joystick = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Joystick Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
"Pause",
|
||||
|
||||
// ports
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Paddles = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Paddle Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger",
|
||||
"P3 Trigger",
|
||||
"P4 Trigger"
|
||||
},
|
||||
FloatControls = // should be in [0..700000]
|
||||
{
|
||||
"P1 Paddle",
|
||||
"P2 Paddle",
|
||||
"P3 Paddle",
|
||||
"P4 Paddle"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
// what is the center point supposed to be here?
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Keypad = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Keypad Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Keypad1", "P1 Keypad2", "P1 Keypad3",
|
||||
"P1 Keypad4", "P1 Keypad5", "P1 Keypad6",
|
||||
"P1 Keypad7", "P1 Keypad8", "P1 Keypad9",
|
||||
"P1 KeypadA", "P1 Keypad0", "P1 KeypadP",
|
||||
"P2 Keypad1", "P2 Keypad2", "P2 Keypad3",
|
||||
"P2 Keypad4", "P2 Keypad5", "P2 Keypad6",
|
||||
"P2 Keypad7", "P2 Keypad8", "P2 Keypad9",
|
||||
"P2 KeypadA", "P2 Keypad0", "P2 KeypadP",
|
||||
"P3 Keypad1", "P3 Keypad2", "P3 Keypad3",
|
||||
"P3 Keypad4", "P3 Keypad5", "P3 Keypad6",
|
||||
"P3 Keypad7", "P3 Keypad8", "P3 Keypad9",
|
||||
"P3 KeypadA", "P3 Keypad0", "P3 KeypadP",
|
||||
"P4 Keypad1", "P4 Keypad2", "P4 Keypad3",
|
||||
"P4 Keypad4", "P4 Keypad5", "P4 Keypad6",
|
||||
"P4 Keypad7", "P4 Keypad8", "P4 Keypad9",
|
||||
"P4 KeypadA", "P4 Keypad0", "P4 KeypadP"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Driving = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Driving Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger"
|
||||
},
|
||||
FloatControls = // should be in [0..3]
|
||||
{
|
||||
"P1 Driving",
|
||||
"P2 Driving"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
new[] { 0.0f, 0.0f, 3.0f },
|
||||
new[] { 0.0f, 0.0f, 3.0f },
|
||||
new[] { 0.0f, 0.0f, 3.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition BoosterGrip = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Booster Grip Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
// NB: as referenced by the emu, p1t2 = p1t2, p1t3 = p2t2, p2t2 = p3t2, p2t3 = p4t2
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger", "P1 Trigger 2", "P1 Trigger 3",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger", "P2 Trigger 2", "P2 Trigger 3"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition ProLineJoystick = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 ProLine Joystick Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
"Pause",
|
||||
|
||||
// ports
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger", "P1 Trigger 2",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger", "P2 Trigger 2"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Lightgun = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Light Gun Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"Pause",
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger"
|
||||
},
|
||||
FloatControls = // vpos should be actual scanline number. hpos should be in [0..319]??
|
||||
{
|
||||
"P1 VPos", "P1 HPos",
|
||||
"P2 VPos", "P2 HPos"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
// how many scanlines are there again??
|
||||
new[] { 0.0f, 0.0f, 240.0f },
|
||||
new[] { 0.0f, 0.0f, 319.0f },
|
||||
new[] { 0.0f, 0.0f, 240.0f },
|
||||
new[] { 0.0f, 0.0f, 319.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private struct ControlAdapter
|
||||
{
|
||||
public readonly ControllerDefinition Type;
|
||||
public readonly Controller Left;
|
||||
public readonly Controller Right;
|
||||
public readonly Action<IController, InputState> Convert;
|
||||
|
||||
public ControlAdapter(ControllerDefinition type, Controller left, Controller right, Action<IController, InputState> convert)
|
||||
{
|
||||
Type = type;
|
||||
Left = left;
|
||||
Right = right;
|
||||
Convert = convert;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ControlAdapter[] Adapters =
|
||||
{
|
||||
new ControlAdapter(Joystick, Controller.Joystick, Controller.Joystick, ConvertJoystick),
|
||||
new ControlAdapter(Paddles, Controller.Paddles, Controller.Paddles, ConvertPaddles),
|
||||
new ControlAdapter(Keypad, Controller.Keypad, Controller.Keypad, ConvertKeypad),
|
||||
new ControlAdapter(Driving, Controller.Driving, Controller.Driving, ConvertDriving),
|
||||
new ControlAdapter(BoosterGrip, Controller.BoosterGrip, Controller.BoosterGrip, ConvertBoosterGrip),
|
||||
new ControlAdapter(ProLineJoystick, Controller.ProLineJoystick, Controller.ProLineJoystick, ConvertProLineJoystick),
|
||||
new ControlAdapter(Lightgun, Controller.Lightgun, Controller.Lightgun, ConvertLightgun),
|
||||
};
|
||||
|
||||
private static void ConvertConsoleButtons(IController c, InputState s)
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.Reset, c.IsPressed("Reset"));
|
||||
s.RaiseInput(0, MachineInput.Select, c.IsPressed("Select"));
|
||||
s.RaiseInput(0, MachineInput.Color, c.IsPressed("BW"));
|
||||
if (c.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.LeftDifficulty, c.IsPressed("Toggle Left Difficulty"));
|
||||
}
|
||||
|
||||
if (c.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.RightDifficulty, c.IsPressed("Toggle Right Difficulty"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertConsoleButtons7800(IController c, InputState s)
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.Reset, c.IsPressed("Reset"));
|
||||
s.RaiseInput(0, MachineInput.Select, c.IsPressed("Select"));
|
||||
s.RaiseInput(0, MachineInput.Color, c.IsPressed("Pause"));
|
||||
if (c.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.LeftDifficulty, c.IsPressed("Toggle Left Difficulty"));
|
||||
}
|
||||
|
||||
if (c.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.RightDifficulty, c.IsPressed("Toggle Right Difficulty"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertDirections(IController c, InputState s, int p)
|
||||
{
|
||||
string ps = $"P{p + 1} ";
|
||||
s.RaiseInput(p, MachineInput.Up, c.IsPressed(ps + "Up"));
|
||||
s.RaiseInput(p, MachineInput.Down, c.IsPressed(ps + "Down"));
|
||||
s.RaiseInput(p, MachineInput.Left, c.IsPressed(ps + "Left"));
|
||||
s.RaiseInput(p, MachineInput.Right, c.IsPressed(ps + "Right"));
|
||||
}
|
||||
|
||||
private static void ConvertTrigger(IController c, InputState s, int p)
|
||||
{
|
||||
string ps = $"P{p + 1} ";
|
||||
s.RaiseInput(p, MachineInput.Fire, c.IsPressed(ps + "Trigger"));
|
||||
}
|
||||
|
||||
private static void ConvertJoystick(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
}
|
||||
|
||||
private static void ConvertPaddles(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
string ps = $"P{i + 1} ";
|
||||
ConvertTrigger(c, s, i);
|
||||
s.RaisePaddleInput(i, 700000, (int)c.GetFloat(ps + "Trigger"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertKeypad(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
string ps = $"P{i + 1} ";
|
||||
s.RaiseInput(i, MachineInput.NumPad1, c.IsPressed(ps + "Keypad1"));
|
||||
s.RaiseInput(i, MachineInput.NumPad2, c.IsPressed(ps + "Keypad2"));
|
||||
s.RaiseInput(i, MachineInput.NumPad3, c.IsPressed(ps + "Keypad3"));
|
||||
s.RaiseInput(i, MachineInput.NumPad4, c.IsPressed(ps + "Keypad4"));
|
||||
s.RaiseInput(i, MachineInput.NumPad5, c.IsPressed(ps + "Keypad5"));
|
||||
s.RaiseInput(i, MachineInput.NumPad6, c.IsPressed(ps + "Keypad6"));
|
||||
s.RaiseInput(i, MachineInput.NumPad7, c.IsPressed(ps + "Keypad7"));
|
||||
s.RaiseInput(i, MachineInput.NumPad8, c.IsPressed(ps + "Keypad8"));
|
||||
s.RaiseInput(i, MachineInput.NumPad9, c.IsPressed(ps + "Keypad9"));
|
||||
s.RaiseInput(i, MachineInput.NumPadMult, c.IsPressed(ps + "KeypadA"));
|
||||
s.RaiseInput(i, MachineInput.NumPad0, c.IsPressed(ps + "Keypad0"));
|
||||
s.RaiseInput(i, MachineInput.NumPadHash, c.IsPressed(ps + "KeypadP"));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly MachineInput[] Drvlut =
|
||||
{
|
||||
MachineInput.Driving0,
|
||||
MachineInput.Driving1,
|
||||
MachineInput.Driving2,
|
||||
MachineInput.Driving3
|
||||
};
|
||||
|
||||
private static void ConvertDriving(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
s.RaiseInput(0, Drvlut[(int)c.GetFloat("P1 Driving")], true);
|
||||
s.RaiseInput(1, Drvlut[(int)c.GetFloat("P2 Driving")], true);
|
||||
}
|
||||
|
||||
private static void ConvertBoosterGrip(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
|
||||
// weird mapping is intentional
|
||||
s.RaiseInput(0, MachineInput.Fire, c.IsPressed("P1 Trigger"));
|
||||
s.RaiseInput(0, MachineInput.Fire2, c.IsPressed("P1 Trigger 2"));
|
||||
s.RaiseInput(1, MachineInput.Fire2, c.IsPressed("P1 Trigger 3"));
|
||||
s.RaiseInput(1, MachineInput.Fire, c.IsPressed("P2 Trigger"));
|
||||
s.RaiseInput(2, MachineInput.Fire2, c.IsPressed("P2 Trigger 2"));
|
||||
s.RaiseInput(3, MachineInput.Fire2, c.IsPressed("P2 Trigger 3"));
|
||||
}
|
||||
|
||||
private static void ConvertProLineJoystick(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons7800(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
s.RaiseInput(0, MachineInput.Fire, c.IsPressed("P1 Trigger"));
|
||||
s.RaiseInput(0, MachineInput.Fire2, c.IsPressed("P1 Trigger 2"));
|
||||
s.RaiseInput(1, MachineInput.Fire, c.IsPressed("P2 Trigger"));
|
||||
s.RaiseInput(1, MachineInput.Fire2, c.IsPressed("P2 Trigger 2"));
|
||||
}
|
||||
|
||||
private static void ConvertLightgun(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons7800(c, s);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
s.RaiseLightgunPos(0, (int)c.GetFloat("P1 VPos"), (int)c.GetFloat("P1 HPos"));
|
||||
s.RaiseLightgunPos(1, (int)c.GetFloat("P2 VPos"), (int)c.GetFloat("P2 HPos"));
|
||||
}
|
||||
|
||||
public Action<IController, InputState> Convert { get; private set; }
|
||||
|
||||
public ControllerDefinition ControlType { get; private set; }
|
||||
|
||||
public Atari7800Control(MachineBase mac)
|
||||
{
|
||||
var l = mac.InputState.LeftControllerJack;
|
||||
var r = mac.InputState.RightControllerJack;
|
||||
|
||||
foreach (var a in Adapters)
|
||||
{
|
||||
if (a.Left == l && a.Right == r)
|
||||
{
|
||||
Convert = a.Convert;
|
||||
ControlType = a.Type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Couldn't connect Atari 7800 controls \"{l}\" and \"{r}\"");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IEmulator, IVideoProvider
|
||||
public partial class A7800Hawk : IEmulator, IVideoProvider, ISoundProvider
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
GetControllerState(controller);
|
||||
GetConsoleState(controller);
|
||||
|
||||
|
||||
maria.RunFrame();
|
||||
|
||||
if (_islag)
|
||||
|
@ -160,15 +160,25 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
if (tia._hsyncCnt == 113 || tia._hsyncCnt == 340)
|
||||
{
|
||||
tia.Execute(0);
|
||||
|
||||
// even though its clocked seperately, we sample the Pokey here
|
||||
if (is_pokey) { pokey.sample(); }
|
||||
}
|
||||
|
||||
// tick the m6532 timer, which is still active although not recommended to use
|
||||
// also it runs off of the cpu cycle timer
|
||||
// similarly tick the pokey if it is in use
|
||||
if (cpu_cycle== 4)
|
||||
{
|
||||
m6532.Timer.Tick();
|
||||
}
|
||||
|
||||
// the pokey chip ticks at the nominal clock rate (same as maria)
|
||||
if (is_pokey)
|
||||
{
|
||||
pokey.Tick();
|
||||
}
|
||||
|
||||
if (cpu_cycle <= (2 + (slow_access ? 1 : 0)))
|
||||
{
|
||||
cpu_is_haltable = true;
|
||||
|
@ -284,7 +294,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "A7800";
|
||||
public string SystemId => "A78";
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
|
@ -344,5 +354,53 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sound provider
|
||||
|
||||
private int _spf;
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
short[] ret = new short[_spf * 2];
|
||||
|
||||
nsamp = _spf;
|
||||
tia.GetSamples(ret);
|
||||
if (is_pokey)
|
||||
{
|
||||
short[] ret2 = new short[_spf * 2];
|
||||
pokey.GetSamples(ret2);
|
||||
for (int i = 0; i < _spf * 2; i ++)
|
||||
{
|
||||
ret[i] += ret2[i];
|
||||
}
|
||||
}
|
||||
|
||||
samples = ret;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
tia.AudioClocks = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
ser.Sync("A7800_control_register", ref A7800_control_register);
|
||||
ser.Sync("_isPAL", ref _isPAL);
|
||||
ser.Sync("_spf", ref _spf);
|
||||
|
||||
ser.Sync("Maria_regs", ref Maria_regs, false);
|
||||
ser.Sync("RAM", ref RAM, false);
|
||||
|
@ -80,7 +81,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
ser.Sync("small flag", ref small_flag);
|
||||
ser.Sync("pal kara", ref PAL_Kara);
|
||||
ser.Sync("Cart RAM", ref cart_RAM);
|
||||
ser.Sync("pokey", ref pokey);
|
||||
ser.Sync("is_pokey", ref is_pokey);
|
||||
ser.Sync("left_toggle", ref left_toggle);
|
||||
ser.Sync("right_toggle", ref right_toggle);
|
||||
ser.Sync("left_was_pressed", ref left_was_pressed);
|
||||
|
|
|
@ -13,8 +13,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
isPorted: false,
|
||||
isReleased: true)]
|
||||
[ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))]
|
||||
public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable,
|
||||
ISettable<A7800Hawk.A7800Settings, A7800Hawk.A7800SyncSettings>
|
||||
public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable,
|
||||
IRegionable, IBoardInfo, ISettable<A7800Hawk.A7800Settings, A7800Hawk.A7800SyncSettings>
|
||||
{
|
||||
// this register selects between 2600 and 7800 mode in the A7800
|
||||
// however, we already have a 2600 emulator so this core will only be loading A7800 games
|
||||
|
@ -40,7 +40,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
public bool small_flag = false;
|
||||
public bool PAL_Kara = false;
|
||||
public int cart_RAM = 0;
|
||||
public bool pokey = false;
|
||||
public bool is_pokey = false;
|
||||
|
||||
private readonly ITraceable _tracer;
|
||||
|
||||
|
@ -49,6 +49,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
public bool _isPAL;
|
||||
public M6532 m6532;
|
||||
public TIA tia;
|
||||
public Pokey pokey;
|
||||
|
||||
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn, object settings, object syncSettings)
|
||||
{
|
||||
|
@ -57,6 +58,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
maria = new Maria();
|
||||
tia = new TIA();
|
||||
m6532 = new M6532();
|
||||
pokey = new Pokey();
|
||||
|
||||
cpu = new MOS6502X
|
||||
{
|
||||
|
@ -131,7 +133,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
if (dict.ContainsKey("Pokey"))
|
||||
{
|
||||
bool.TryParse(dict["Pokey"], out pokey);
|
||||
bool.TryParse(dict["Pokey"], out is_pokey);
|
||||
}
|
||||
|
||||
// some games will not function with the high score bios
|
||||
|
@ -222,18 +224,22 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
maria.Core = this;
|
||||
m6532.Core = this;
|
||||
tia.Core = this;
|
||||
pokey.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ISoundProvider>(tia);
|
||||
ser.Register<ISoundProvider>(this);
|
||||
ServiceProvider = ser;
|
||||
|
||||
_tracer = new TraceBuffer { Header = cpu.TraceHeader };
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
|
||||
SetupMemoryDomains();
|
||||
HardReset();
|
||||
ser.Register<IDisassemblable>(cpu);
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public string BoardName => mapper.GetType().Name.Replace("Mapper", "");
|
||||
|
||||
public DisplayType Region => _isPAL ? DisplayType.PAL : DisplayType.NTSC;
|
||||
|
||||
private readonly A7800HawkControllerDeck _controllerDeck;
|
||||
|
@ -248,6 +254,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
|
||||
maria.Reset();
|
||||
m6532.Reset();
|
||||
pokey.Reset();
|
||||
|
||||
Maria_regs = new byte[0x20];
|
||||
RAM = new byte[0x1000];
|
||||
|
@ -255,6 +262,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
cpu_cycle = 0;
|
||||
|
||||
_vidbuffer = new int[VirtualWidth * VirtualHeight];
|
||||
|
||||
_spf = (_frameHz > 55) ? 740 : 880;
|
||||
}
|
||||
|
||||
private void ExecFetch(ushort addr)
|
||||
|
|
|
@ -31,6 +31,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
return Core.RAM[0x800 + addr & 0x7FF];
|
||||
}
|
||||
}
|
||||
else if (addr < 0x8000 && Core.is_pokey)
|
||||
{
|
||||
return Core.pokey.ReadReg(addr & 0xF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cartridge and other OPSYS
|
||||
|
@ -75,8 +79,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
Core.RAM[0x800 + addr & 0x7FF] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (addr < 0x8000 && Core.is_pokey)
|
||||
{
|
||||
Core.pokey.WriteReg(addr & 0xF, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cartridge and other OPSYS
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
}
|
||||
else
|
||||
{
|
||||
if (Core.cart_RAM == 0 && !Core.pokey)
|
||||
if (Core.cart_RAM == 0 && !Core.is_pokey)
|
||||
{
|
||||
// return bank 6
|
||||
int temp_addr = addr - 0x4000;
|
||||
|
@ -80,11 +80,11 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
else if (Core.cart_RAM > 0)
|
||||
{
|
||||
// return RAM
|
||||
if (Core.cart_RAM==8 && addr >= 0x6000)
|
||||
if (Core.cart_RAM == 8 && addr >= 0x6000)
|
||||
{
|
||||
return RAM[addr - 0x6000];
|
||||
}
|
||||
else if (Core.cart_RAM==16)
|
||||
else if (Core.cart_RAM == 16)
|
||||
{
|
||||
return RAM[addr - 0x4000];
|
||||
}
|
||||
|
@ -92,12 +92,15 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
{
|
||||
// this would coorespond to reading from 0x4000-0x5FFF with only 8k of RAM
|
||||
// Let's just return FF for now
|
||||
return 0xFF;
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
else if (Core.is_pokey)
|
||||
{
|
||||
return Core.pokey.ReadReg(addr & 0xF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// pokey
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
@ -138,9 +141,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
{
|
||||
bank = (byte)(value & (Core.small_flag ? 0x3 : 0x7));
|
||||
}
|
||||
else if (Core.pokey)
|
||||
else if (Core.is_pokey)
|
||||
{
|
||||
|
||||
Core.pokey.WriteReg(addr & 0xF, value);
|
||||
}
|
||||
else if (Core.cart_RAM > 0)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,316 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// emualtes pokey sound chip
|
||||
// note: A7800 implementation is used only for sound
|
||||
// potentiometers, keyboard, and IRQs are not used in this context
|
||||
/*
|
||||
* Regs 0,2,4,6: Frequency control (divider = value + 1)
|
||||
* Regs 1,3,5,7: Channel control (Bits 0-3 = volume) (bits 4 - 7 control clocking)
|
||||
* Reg 8: Control register
|
||||
*
|
||||
* Reg A: Random number generator
|
||||
*
|
||||
* The registers are write only, except for the RNG none of the things that would return reads are connected
|
||||
* for now return FF
|
||||
*/
|
||||
public class Pokey
|
||||
{
|
||||
public A7800Hawk Core { get; set; }
|
||||
|
||||
public readonly short[] LocalAudioCycles = new short[2000];
|
||||
public int AudioClocks;
|
||||
|
||||
// state variables
|
||||
public byte[] Regs = new byte[16];
|
||||
public int poly4, poly5, poly9, poly17;
|
||||
public int[] ch_div = new int[4];
|
||||
public int[] inc_ch = new int[4];
|
||||
public bool[] ch_out = new bool[4];
|
||||
public bool[] ch_src = new bool[4];
|
||||
public int[] ch_vol = new int[4];
|
||||
public bool high_pass_1;
|
||||
public bool high_pass_2;
|
||||
|
||||
// these are derived values and do not need to be save-stated
|
||||
public bool[] clock_ch = new bool[4];
|
||||
public int bit_xor;
|
||||
|
||||
public Pokey()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void sample()
|
||||
{
|
||||
LocalAudioCycles[AudioClocks] += (short)(ch_vol[0] + ch_vol[1] + ch_vol[2] + ch_vol[3]);
|
||||
AudioClocks++;
|
||||
}
|
||||
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
if (AudioClocks > 0)
|
||||
{
|
||||
var samples31Khz = new short[AudioClocks]; // mono
|
||||
|
||||
for (int i = 0; i < AudioClocks; i++)
|
||||
{
|
||||
samples31Khz[i] = LocalAudioCycles[i];
|
||||
LocalAudioCycles[i] = 0;
|
||||
}
|
||||
|
||||
// convert from 31khz to 44khz
|
||||
for (var i = 0; i < samples.Length / 2; i++)
|
||||
{
|
||||
samples[i * 2] = samples31Khz[(int)(((double)samples31Khz.Length / (double)(samples.Length / 2)) * i)];
|
||||
samples[(i * 2) + 1] = samples[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
AudioClocks = 0;
|
||||
}
|
||||
|
||||
public byte ReadReg(int reg)
|
||||
{
|
||||
byte ret = 0xFF;
|
||||
|
||||
if (reg==0xA)
|
||||
{
|
||||
ret = (byte)(poly17 >> 9);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void WriteReg(int reg, byte value)
|
||||
{
|
||||
Regs[reg] = value;
|
||||
|
||||
// this condition resets poly counters and holds them in place
|
||||
if ((Regs[0xF] & 3) == 0)
|
||||
{
|
||||
poly4 = 0xF;
|
||||
poly5 = 0x1F;
|
||||
poly17 = 0x1FFFF;
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
// clock the 4-5-(9 or 17) bit poly counters
|
||||
// NOTE: These might not be the exact poly implementation, I just picked a maximal one from wikipedia
|
||||
// poly 4 and 5 are known to result in:
|
||||
// poly4 output: 000011101100101
|
||||
// poly5 output: 1101001100000111001000101011110
|
||||
if ((Regs[0xF] & 3) != 0)
|
||||
{
|
||||
bit_xor = ((poly4) ^ (poly4 >> 1)) & 1;
|
||||
poly4 = (poly4 >> 1) | (bit_xor << 3);
|
||||
|
||||
bit_xor = ((poly5 >> 2) ^ poly5) & 1;
|
||||
poly5 = (poly5 >> 1) | (bit_xor << 4);
|
||||
|
||||
if (Regs[8].Bit(7))
|
||||
{
|
||||
// clock only 9 bits of the 17 bit poly
|
||||
poly9 = poly17 >> 8;
|
||||
bit_xor = ((poly9 >> 4) ^ poly9) & 1;
|
||||
poly9 = (poly9 >> 1) | (bit_xor << 8);
|
||||
poly17 = (poly17 & 0xFF) | (poly9 << 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// clock the whole 17 bit poly
|
||||
bit_xor = ((poly17 >> 3) ^ poly17) & 1;
|
||||
poly17 = (poly17 >> 1) | (bit_xor << 16);
|
||||
}
|
||||
}
|
||||
|
||||
clock_ch[0] = clock_ch[1] = clock_ch[2] = clock_ch[3] = false;
|
||||
|
||||
// now that we have the poly counters, check which channels to clock
|
||||
if (Regs[8].Bit(6))
|
||||
{
|
||||
clock_ch[0] = true;
|
||||
clock_ch[2] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
inc_ch[0]++;
|
||||
inc_ch[2]++;
|
||||
if (Regs[8].Bit(0))
|
||||
{
|
||||
if (inc_ch[0] >= 114) { inc_ch[0] = 0; clock_ch[0] = true; }
|
||||
if (inc_ch[2] >= 114) { inc_ch[2] = 0; clock_ch[2] = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inc_ch[0] >= 28) { inc_ch[0] = 0; clock_ch[0] = true; }
|
||||
if (inc_ch[2] >= 28) { inc_ch[2] = 0; clock_ch[2] = true; }
|
||||
}
|
||||
}
|
||||
|
||||
if (Regs[8].Bit(4))
|
||||
{
|
||||
if (clock_ch[0]) { clock_ch[1] = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
inc_ch[1]++;
|
||||
if (Regs[8].Bit(0))
|
||||
{
|
||||
if (inc_ch[1] >= 114) { inc_ch[1] = 0; clock_ch[1] = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inc_ch[1] >= 28) { inc_ch[1] = 0; clock_ch[1] = true; }
|
||||
}
|
||||
}
|
||||
|
||||
if (Regs[8].Bit(3))
|
||||
{
|
||||
if (clock_ch[2]) { clock_ch[3] = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
inc_ch[3]++;
|
||||
if (Regs[8].Bit(0))
|
||||
{
|
||||
if (inc_ch[3] >= 114) { inc_ch[3] = 0; clock_ch[3] = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inc_ch[3] >= 28) { inc_ch[3] = 0; clock_ch[3] = true; }
|
||||
}
|
||||
}
|
||||
|
||||
// first update the high pass filter latch
|
||||
if (clock_ch[2] && Regs[8].Bit(2)) { high_pass_1 = ch_out[0]; }
|
||||
if (clock_ch[3] && Regs[8].Bit(1)) { high_pass_2 = ch_out[1]; }
|
||||
|
||||
// now we know what channels to clock, execute the cycles
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (clock_ch[i])
|
||||
{
|
||||
ch_div[i]++;
|
||||
|
||||
if (ch_div[i] >= (Regs[i * 2] + 1))
|
||||
{
|
||||
ch_div[i] = 0;
|
||||
|
||||
// select the next source based on the channel control register
|
||||
if (Regs[i * 2 + 1].Bit(4))
|
||||
{
|
||||
// forced output always on (used with volume modulation)
|
||||
ch_out[i] = true;
|
||||
}
|
||||
else if ((Regs[i * 2 + 1] & 0xF0) == 0)
|
||||
{
|
||||
// 17 bit poly then 5 bit poly
|
||||
if (ch_src[i])
|
||||
{
|
||||
ch_out[i] = poly5.Bit(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch_out[i] = poly5.Bit(16);
|
||||
}
|
||||
}
|
||||
else if (((Regs[i * 2 + 1] & 0xF0) == 0x20) || ((Regs[i * 2 + 1] & 0xF0) == 0x60))
|
||||
{
|
||||
// 5 bit poly
|
||||
if (ch_src[i])
|
||||
{
|
||||
ch_out[i] = poly5.Bit(4);
|
||||
}
|
||||
}
|
||||
else if ((Regs[i * 2 + 1] & 0xF0) == 0x40)
|
||||
{
|
||||
// 4 bit poly then 5 bit poly
|
||||
if (ch_src[i])
|
||||
{
|
||||
ch_out[i] = poly5.Bit(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
ch_out[i] = poly4.Bit(3);
|
||||
}
|
||||
}
|
||||
else if ((Regs[i * 2 + 1] & 0xF0) == 0x80)
|
||||
{
|
||||
// 17 bit poly
|
||||
if (ch_src[i])
|
||||
{
|
||||
ch_out[i] = poly17.Bit(16);
|
||||
}
|
||||
}
|
||||
else if ((Regs[i * 2 + 1] & 0xF0) == 0xA0)
|
||||
{
|
||||
// tone
|
||||
if (ch_src[i])
|
||||
{
|
||||
ch_out[i] = !ch_out[i];
|
||||
}
|
||||
}
|
||||
else if ((Regs[i * 2 + 1] & 0xF0) == 0xC0)
|
||||
{
|
||||
// 4 bit poly
|
||||
if (ch_src[i])
|
||||
{
|
||||
ch_out[i] = poly4.Bit(3);
|
||||
}
|
||||
}
|
||||
ch_src[i] = !ch_src[i];
|
||||
|
||||
// for channels 1 and 2, an optional high pass filter exists
|
||||
// the filter is just a flip flop and xor combo
|
||||
if ((i == 0 && Regs[8].Bit(2)) || (i == 1 && Regs[8].Bit(1)))
|
||||
{
|
||||
if (i == 0) { ch_vol[0] = (ch_out[0] ^ high_pass_1) ? (Regs[1] & 0xF) : 0; }
|
||||
if (i == 1) { ch_vol[1] = (ch_out[1] ^ high_pass_2) ? (Regs[3] & 0xF) : 0; }
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ch_vol[i] = (ch_out[i] ? (Regs[i * 2 + 1] & 0xF) : 0) * 70;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Regs = new byte[16];
|
||||
poly4 = 0xF;
|
||||
poly5 = 0x1F;
|
||||
poly17 = 0x1FFFF;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Pokey");
|
||||
|
||||
ser.Sync("Regs", ref Regs, false);
|
||||
|
||||
ser.Sync("poly4", ref poly4);
|
||||
ser.Sync("poly5", ref poly5);
|
||||
ser.Sync("poly9", ref poly9);
|
||||
ser.Sync("poly17", ref poly17);
|
||||
ser.Sync("ch_div", ref ch_div, false);
|
||||
ser.Sync("inc_ch", ref inc_ch, false);
|
||||
ser.Sync("ch_out", ref ch_out, false);
|
||||
ser.Sync("ch_src", ref ch_src, false);
|
||||
ser.Sync("ch_vol", ref ch_vol, false);
|
||||
ser.Sync("high_pass_1", ref high_pass_1);
|
||||
ser.Sync("high_pass_2", ref high_pass_2);
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -6,20 +6,17 @@ using BizHawk.Emulation.Common;
|
|||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// Emulates the TIA
|
||||
public partial class TIA : ISoundProvider
|
||||
public partial class TIA
|
||||
{
|
||||
public A7800Hawk Core { get; set; }
|
||||
|
||||
public byte BusState;
|
||||
|
||||
private bool _doTicks;
|
||||
|
||||
private int _spf;
|
||||
|
||||
public int AudioClocks; // not savestated
|
||||
public int _hsyncCnt;
|
||||
private int _capChargeStart;
|
||||
private bool _capCharging;
|
||||
public int AudioClocks; // not savestated
|
||||
|
||||
private readonly Audio[] AUD = { new Audio(), new Audio() };
|
||||
|
||||
|
@ -33,7 +30,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
_capChargeStart = 0;
|
||||
_capCharging = false;
|
||||
AudioClocks = 0;
|
||||
_spf = (Core._frameHz > 55) ? 740 : 880;
|
||||
_doTicks = false;
|
||||
}
|
||||
|
||||
|
@ -45,11 +41,32 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
AudioClocks++;
|
||||
}
|
||||
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
if (AudioClocks > 0)
|
||||
{
|
||||
var samples31Khz = new short[AudioClocks]; // mono
|
||||
|
||||
for (int i = 0; i < AudioClocks; i++)
|
||||
{
|
||||
samples31Khz[i] = LocalAudioCycles[i];
|
||||
LocalAudioCycles[i] = 0;
|
||||
}
|
||||
|
||||
// convert from 31khz to 44khz
|
||||
for (var i = 0; i < samples.Length / 2; i++)
|
||||
{
|
||||
samples[i * 2] = samples31Khz[(int)(((double)samples31Khz.Length / (double)(samples.Length / 2)) * i)];
|
||||
samples[(i * 2) + 1] = samples[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
AudioClocks = 0;
|
||||
}
|
||||
|
||||
public byte ReadMemory(ushort addr, bool peek)
|
||||
{
|
||||
var maskedAddr = (ushort)(addr & 0x000F);
|
||||
byte coll = 0;
|
||||
int mask = 0;
|
||||
|
||||
if (maskedAddr == 0x00) // CXM0P
|
||||
{
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class TIA : ISoundProvider
|
||||
{
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
short[] ret = new short[_spf * 2];
|
||||
nsamp = _spf;
|
||||
GetSamples(ret);
|
||||
samples = ret;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
AudioClocks = 0;
|
||||
}
|
||||
|
||||
// Exposing this as GetSamplesAsync would allow this to provide async sound
|
||||
// However, it does nothing special for async sound so I don't see a point
|
||||
private void GetSamples(short[] samples)
|
||||
{
|
||||
if (AudioClocks > 0)
|
||||
{
|
||||
var samples31Khz = new short[AudioClocks]; // mono
|
||||
|
||||
for (int i = 0; i < AudioClocks; i++)
|
||||
{
|
||||
samples31Khz[i] = LocalAudioCycles[i];
|
||||
LocalAudioCycles[i] = 0;
|
||||
}
|
||||
|
||||
// convert from 31khz to 44khz
|
||||
for (var i = 0; i < samples.Length / 2; i++)
|
||||
{
|
||||
samples[i * 2] = samples31Khz[(int)(((double)samples31Khz.Length / (double)(samples.Length / 2)) * i)];
|
||||
samples[(i * 2) + 1] = samples[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
AudioClocks = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
|||
ser.Sync("Bus_State", ref BusState);
|
||||
|
||||
ser.Sync("Ticks", ref _doTicks);
|
||||
ser.Sync("_spf", ref _spf);
|
||||
|
||||
// some of these things weren't in the state because they weren't needed if
|
||||
// states were always taken at frame boundaries
|
||||
|
|
|
@ -22,10 +22,6 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx
|
|||
|
||||
_ser.Serialize(writer, s);
|
||||
|
||||
// write extra copy of stuff we don't use
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
|
||||
////Console.WriteLine(BizHawk.Common.BufferExtensions.BufferExtensions.HashSHA1(SaveStateBinary()));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
Name = "ColecoVision Basic Controller",
|
||||
BoolButtons = Port1.Definition.BoolButtons
|
||||
.Concat(Port2.Definition.BoolButtons)
|
||||
.Concat(new[]
|
||||
{
|
||||
"Power", "Reset"
|
||||
})
|
||||
.ToList()
|
||||
};
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
public byte Read(IController c, bool left_mode, int wheel)
|
||||
{
|
||||
return 0; // needs checking
|
||||
return 0x7F; // needs checking
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
|
|
@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = _cpu.RegisterA,
|
||||
["AF"] = _cpu.RegisterAF,
|
||||
["B"] = _cpu.RegisterB,
|
||||
["BC"] = _cpu.RegisterBC,
|
||||
["C"] = _cpu.RegisterC,
|
||||
["D"] = _cpu.RegisterD,
|
||||
["DE"] = _cpu.RegisterDE,
|
||||
["E"] = _cpu.RegisterE,
|
||||
["F"] = _cpu.RegisterF,
|
||||
["H"] = _cpu.RegisterH,
|
||||
["HL"] = _cpu.RegisterHL,
|
||||
["I"] = _cpu.RegisterI,
|
||||
["IX"] = _cpu.RegisterIX,
|
||||
["IY"] = _cpu.RegisterIY,
|
||||
["L"] = _cpu.RegisterL,
|
||||
["PC"] = _cpu.RegisterPC,
|
||||
["R"] = _cpu.RegisterR,
|
||||
["Shadow AF"] = _cpu.RegisterShadowAF,
|
||||
["Shadow BC"] = _cpu.RegisterShadowBC,
|
||||
["Shadow DE"] = _cpu.RegisterShadowDE,
|
||||
["Shadow HL"] = _cpu.RegisterShadowHL,
|
||||
["SP"] = _cpu.RegisterSP,
|
||||
["Flag C"] = _cpu.RegisterF.Bit(0),
|
||||
["Flag N"] = _cpu.RegisterF.Bit(1),
|
||||
["Flag P/V"] = _cpu.RegisterF.Bit(2),
|
||||
["Flag 3rd"] = _cpu.RegisterF.Bit(3),
|
||||
["Flag H"] = _cpu.RegisterF.Bit(4),
|
||||
["Flag 5th"] = _cpu.RegisterF.Bit(5),
|
||||
["Flag Z"] = _cpu.RegisterF.Bit(6),
|
||||
["Flag S"] = _cpu.RegisterF.Bit(7)
|
||||
["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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
_cpu.RegisterA = (byte)value;
|
||||
_cpu.Regs[_cpu.A] = (ushort)value;
|
||||
break;
|
||||
case "AF":
|
||||
_cpu.RegisterAF = (byte)value;
|
||||
_cpu.Regs[_cpu.F] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "B":
|
||||
_cpu.RegisterB = (byte)value;
|
||||
_cpu.Regs[_cpu.B] = (ushort)value;
|
||||
break;
|
||||
case "BC":
|
||||
_cpu.RegisterBC = (byte)value;
|
||||
_cpu.Regs[_cpu.C] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "C":
|
||||
_cpu.RegisterC = (byte)value;
|
||||
_cpu.Regs[_cpu.C] = (ushort)value;
|
||||
break;
|
||||
case "D":
|
||||
_cpu.RegisterD = (byte)value;
|
||||
_cpu.Regs[_cpu.D] = (ushort)value;
|
||||
break;
|
||||
case "DE":
|
||||
_cpu.RegisterDE = (byte)value;
|
||||
_cpu.Regs[_cpu.E] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "E":
|
||||
_cpu.RegisterE = (byte)value;
|
||||
_cpu.Regs[_cpu.E] = (ushort)value;
|
||||
break;
|
||||
case "F":
|
||||
_cpu.RegisterF = (byte)value;
|
||||
_cpu.Regs[_cpu.F] = (ushort)value;
|
||||
break;
|
||||
case "H":
|
||||
_cpu.RegisterH = (byte)value;
|
||||
_cpu.Regs[_cpu.H] = (ushort)value;
|
||||
break;
|
||||
case "HL":
|
||||
_cpu.RegisterHL = (byte)value;
|
||||
_cpu.Regs[_cpu.L] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "I":
|
||||
_cpu.RegisterI = (byte)value;
|
||||
_cpu.Regs[_cpu.I] = (ushort)value;
|
||||
break;
|
||||
case "IX":
|
||||
_cpu.RegisterIX = (byte)value;
|
||||
_cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "IY":
|
||||
_cpu.RegisterIY = (byte)value;
|
||||
_cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "L":
|
||||
_cpu.RegisterL = (byte)value;
|
||||
_cpu.Regs[_cpu.L] = (ushort)value;
|
||||
break;
|
||||
case "PC":
|
||||
_cpu.RegisterPC = (ushort)value;
|
||||
_cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "R":
|
||||
_cpu.RegisterR = (byte)value;
|
||||
_cpu.Regs[_cpu.R] = (ushort)value;
|
||||
break;
|
||||
case "Shadow AF":
|
||||
_cpu.RegisterShadowAF = (byte)value;
|
||||
_cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow BC":
|
||||
_cpu.RegisterShadowBC = (byte)value;
|
||||
_cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow DE":
|
||||
_cpu.RegisterShadowDE = (byte)value;
|
||||
_cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "Shadow HL":
|
||||
_cpu.RegisterShadowHL = (byte)value;
|
||||
_cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
case "SP":
|
||||
_cpu.RegisterSP = (byte)value;
|
||||
_cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF);
|
||||
_cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,16 +12,30 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
public void FrameAdvance(IController controller, bool render, bool renderSound)
|
||||
{
|
||||
_controller = controller;
|
||||
_cpu.Debug = _tracer.Enabled;
|
||||
|
||||
// NOTE: Need to research differences between reset and power cycle
|
||||
if (_controller.IsPressed("Power"))
|
||||
{
|
||||
HardReset();
|
||||
}
|
||||
|
||||
if (_controller.IsPressed("Reset"))
|
||||
{
|
||||
SoftReset();
|
||||
}
|
||||
|
||||
_frame++;
|
||||
_isLag = true;
|
||||
PSG.BeginFrame(_cpu.TotalExecutedCycles);
|
||||
|
||||
if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
_cpu.Logger = (s) => _tracer.Put(s);
|
||||
_cpu.TraceCallback = s => _tracer.Put(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpu.TraceCallback = null;
|
||||
}
|
||||
|
||||
byte tempRet1 = ControllerDeck.ReadPort1(controller, true, true);
|
||||
byte tempRet2 = ControllerDeck.ReadPort2(controller, true, true);
|
||||
|
||||
|
|
|
@ -7,53 +7,52 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
{
|
||||
public partial class ColecoVision : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => false;
|
||||
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(Serializer.CreateBinaryWriter(bw));
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(Serializer.CreateBinaryReader(br));
|
||||
}
|
||||
|
||||
public void SaveStateText(TextWriter tw)
|
||||
{
|
||||
SyncState(Serializer.CreateTextWriter(tw));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader tr)
|
||||
{
|
||||
SyncState(Serializer.CreateTextReader(tr));
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
if (_stateBuffer == null)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new BinaryWriter(stream);
|
||||
SaveStateBinary(writer);
|
||||
_stateBuffer = stream.ToArray();
|
||||
writer.Close();
|
||||
return _stateBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var stream = new MemoryStream(_stateBuffer);
|
||||
var writer = new BinaryWriter(stream);
|
||||
SaveStateBinary(writer);
|
||||
writer.Close();
|
||||
return _stateBuffer;
|
||||
}
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("Coleco");
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
_cpu.SyncState(ser);
|
||||
|
||||
ser.BeginSection("Coleco");
|
||||
_vdp.SyncState(ser);
|
||||
PSG.SyncState(ser);
|
||||
ser.Sync("RAM", ref _ram, false);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components;
|
||||
using BizHawk.Emulation.Cores.Components.Z80;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
|
@ -24,6 +24,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
_cpu = new Z80A
|
||||
{
|
||||
FetchMemory = ReadMemory,
|
||||
ReadMemory = ReadMemory,
|
||||
WriteMemory = WriteMemory,
|
||||
ReadHardware = ReadPort,
|
||||
|
@ -53,7 +54,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
SetupMemoryDomains();
|
||||
|
||||
_tracer.Header = _cpu.TraceHeader;
|
||||
ser.Register<IDisassemblable>(new Disassembler());
|
||||
ser.Register<IDisassemblable>(_cpu);
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
}
|
||||
|
||||
|
@ -223,5 +224,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
////Console.WriteLine("Unhandled write at {0:X4}:{1:X2}", addr, value);
|
||||
}
|
||||
|
||||
private void HardReset()
|
||||
{
|
||||
PSG.Reset();
|
||||
_cpu.Reset();
|
||||
}
|
||||
|
||||
private void SoftReset()
|
||||
{
|
||||
PSG.Reset();
|
||||
_cpu.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.Z80;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
|
@ -54,14 +54,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
Cpu.NonMaskableInterrupt = true;
|
||||
}
|
||||
|
||||
Cpu.ExecuteCycles(228);
|
||||
|
||||
Cpu.Interrupt = false;
|
||||
for (int i = 0; i < 228; i++)
|
||||
{
|
||||
Cpu.ExecuteOne();
|
||||
}
|
||||
|
||||
Cpu.FlagI = false;
|
||||
if (Int_pending && scanLine==50)
|
||||
{
|
||||
if (EnableInterrupts)
|
||||
{
|
||||
Cpu.Interrupt = true;
|
||||
Cpu.FlagI = true;
|
||||
Int_pending = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
ser.Serialize(writer, s);
|
||||
|
||||
// write extra copy of stuff we don't use
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
|
||||
//Console.WriteLine(BizHawk.Common.BufferExtensions.BufferExtensions.HashSHA1(SaveStateBinary()));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||
{
|
||||
public partial class Gameboy : ILinkable
|
||||
{
|
||||
public bool LinkConnected { get; private set; }
|
||||
}
|
||||
}
|
|
@ -14,10 +14,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
{
|
||||
var s = SaveState();
|
||||
ser.Serialize(writer, s);
|
||||
|
||||
// write extra copy of stuff we don't use
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
[ServiceNotApplicable(typeof(IDriveLight), typeof(IDriveLight))]
|
||||
public partial class Gameboy : IEmulator, IVideoProvider, ISoundProvider, ISaveRam, IStatable, IInputPollable, ICodeDataLogger,
|
||||
IBoardInfo, IDebuggable, ISettable<Gameboy.GambatteSettings, Gameboy.GambatteSyncSettings>,
|
||||
IGameboyCommon
|
||||
IGameboyCommon, ICycleTiming, ILinkable
|
||||
{
|
||||
[CoreConstructor("GB", "GBC")]
|
||||
public Gameboy(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings, bool deterministic)
|
||||
|
@ -253,7 +253,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
/// number of extra cycles we overran in the last frame
|
||||
/// </summary>
|
||||
private uint frameOverflow = 0;
|
||||
public ulong CycleCount => _cycleCount;
|
||||
public long CycleCount => (long)_cycleCount;
|
||||
public double ClockRate => TICKSPERSECOND;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -496,6 +497,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
}
|
||||
}
|
||||
|
||||
GambattePrinter printer;
|
||||
|
||||
/// <summary>
|
||||
/// set up Printer callback
|
||||
/// </summary>
|
||||
public void SetPrinterCallback(PrinterCallback callback)
|
||||
{
|
||||
// Copying SetScanlineCallback for this check, I assume this is still a bug somewhere
|
||||
if (GambatteState == IntPtr.Zero)
|
||||
{
|
||||
return; // not sure how this is being reached. tried the debugger...
|
||||
}
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
printer = new GambattePrinter(this, callback);
|
||||
LinkConnected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LinkConnected = false;
|
||||
printer.Disconnect();
|
||||
printer = null;
|
||||
}
|
||||
}
|
||||
|
||||
LibGambatte.ScanlineCallback scanlinecb;
|
||||
ScanlineCallback endofframecallback;
|
||||
|
||||
|
|
|
@ -27,10 +27,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
|||
cablediscosignal = _cablediscosignal
|
||||
};
|
||||
ser.Serialize(writer, s);
|
||||
// write extra copy of stuff we don't use
|
||||
// is this needed anymore??
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||
{
|
||||
/// <summary>
|
||||
/// Emulate the gameboy printer in managed code
|
||||
/// </summary>
|
||||
public class GambattePrinter
|
||||
{
|
||||
// A loose c->c# port of SameBoy's printer code
|
||||
|
||||
enum CommandState : byte
|
||||
{
|
||||
GB_PRINTER_COMMAND_MAGIC1,
|
||||
GB_PRINTER_COMMAND_MAGIC2,
|
||||
GB_PRINTER_COMMAND_ID,
|
||||
GB_PRINTER_COMMAND_COMPRESSION,
|
||||
GB_PRINTER_COMMAND_LENGTH_LOW,
|
||||
GB_PRINTER_COMMAND_LENGTH_HIGH,
|
||||
GB_PRINTER_COMMAND_DATA,
|
||||
GB_PRINTER_COMMAND_CHECKSUM_LOW,
|
||||
GB_PRINTER_COMMAND_CHECKSUM_HIGH,
|
||||
GB_PRINTER_COMMAND_ACTIVE,
|
||||
GB_PRINTER_COMMAND_STATUS,
|
||||
}
|
||||
enum CommandID : byte
|
||||
{
|
||||
GB_PRINTER_INIT_COMMAND = 1,
|
||||
GB_PRINTER_START_COMMAND = 2,
|
||||
GB_PRINTER_DATA_COMMAND = 4,
|
||||
GB_PRINTER_NOP_COMMAND = 0xF,
|
||||
}
|
||||
|
||||
const int GB_PRINTER_MAX_COMMAND_LENGTH = 0x280;
|
||||
const int GB_PRINTER_DATA_SIZE = 0x280;
|
||||
|
||||
const ushort SerialIRQAddress = 0x58;
|
||||
|
||||
Gameboy gb;
|
||||
PrinterCallback callback;
|
||||
LibGambatte.LinkCallback linkCallback;
|
||||
|
||||
CommandState command_state;
|
||||
CommandID command_id;
|
||||
|
||||
bool compression;
|
||||
ushort length_left;
|
||||
byte[] command_data = new byte[GB_PRINTER_MAX_COMMAND_LENGTH];
|
||||
ushort command_length;
|
||||
ushort checksum;
|
||||
byte status;
|
||||
|
||||
byte[] image = new byte[160 * 200];
|
||||
ushort image_offset;
|
||||
|
||||
byte compression_run_lenth;
|
||||
bool compression_run_is_compressed;
|
||||
|
||||
public GambattePrinter(Gameboy gb, PrinterCallback callback)
|
||||
{
|
||||
this.gb = gb;
|
||||
this.callback = callback;
|
||||
|
||||
linkCallback = OnSerial;
|
||||
LibGambatte.gambatte_setlinkcallback(gb.GambatteState, linkCallback);
|
||||
|
||||
// connect the cable
|
||||
LibGambatte.gambatte_linkstatus(gb.GambatteState, 259);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
if (gb.GambatteState != IntPtr.Zero)
|
||||
LibGambatte.gambatte_setlinkcallback(gb.GambatteState, null);
|
||||
}
|
||||
|
||||
void OnSerial()
|
||||
{
|
||||
if (LibGambatte.gambatte_linkstatus(gb.GambatteState, 256) != 0) // ClockTrigger
|
||||
{
|
||||
LibGambatte.gambatte_linkstatus(gb.GambatteState, 257); // ack
|
||||
|
||||
byte output = HandleSerial((byte)LibGambatte.gambatte_linkstatus(gb.GambatteState, 258)); // GetOut
|
||||
LibGambatte.gambatte_linkstatus(gb.GambatteState, output); // ShiftIn
|
||||
}
|
||||
}
|
||||
|
||||
byte HandleSerial(byte byte_received)
|
||||
{
|
||||
byte byte_to_send = 0;
|
||||
|
||||
switch (command_state)
|
||||
{
|
||||
case CommandState.GB_PRINTER_COMMAND_MAGIC1:
|
||||
if (byte_received != 0x88)
|
||||
{
|
||||
return byte_to_send;
|
||||
}
|
||||
status &= 254;
|
||||
command_length = 0;
|
||||
checksum = 0;
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_MAGIC2:
|
||||
if (byte_received != 0x33)
|
||||
{
|
||||
if (byte_received != 0x88)
|
||||
{
|
||||
command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
|
||||
}
|
||||
return byte_to_send;
|
||||
}
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_ID:
|
||||
command_id = (CommandID)(byte_received & 0xF);
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_COMPRESSION:
|
||||
compression = (byte_received & 1) != 0;
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_LENGTH_LOW:
|
||||
length_left = byte_received;
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_LENGTH_HIGH:
|
||||
length_left |= (ushort)((byte_received & 3) << 8);
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_DATA:
|
||||
if (command_length != GB_PRINTER_MAX_COMMAND_LENGTH)
|
||||
{
|
||||
if (compression)
|
||||
{
|
||||
if (compression_run_lenth == 0)
|
||||
{
|
||||
compression_run_is_compressed = (byte_received & 0x80) != 0;
|
||||
compression_run_lenth = (byte)((byte_received & 0x7F) + 1 + (compression_run_is_compressed ? 1 : 0));
|
||||
}
|
||||
else if (compression_run_is_compressed)
|
||||
{
|
||||
while (compression_run_lenth > 0)
|
||||
{
|
||||
command_data[command_length++] = byte_received;
|
||||
compression_run_lenth--;
|
||||
if (command_length == GB_PRINTER_MAX_COMMAND_LENGTH)
|
||||
{
|
||||
compression_run_lenth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command_data[command_length++] = byte_received;
|
||||
compression_run_lenth--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command_data[command_length++] = byte_received;
|
||||
}
|
||||
}
|
||||
length_left--;
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW:
|
||||
checksum ^= byte_received;
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_CHECKSUM_HIGH:
|
||||
checksum ^= (ushort)(byte_received << 8);
|
||||
if (checksum != 0)
|
||||
{
|
||||
status |= 1; /* Checksum error*/
|
||||
command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
|
||||
return byte_to_send;
|
||||
}
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_ACTIVE:
|
||||
byte_to_send = 0x81;
|
||||
break;
|
||||
|
||||
case CommandState.GB_PRINTER_COMMAND_STATUS:
|
||||
|
||||
if (((int)command_id & 0xF) == (byte)CommandID.GB_PRINTER_INIT_COMMAND)
|
||||
{
|
||||
/* Games expect INIT commands to return 0? */
|
||||
byte_to_send = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_to_send = status;
|
||||
}
|
||||
|
||||
/* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */
|
||||
if (status == 6)
|
||||
{
|
||||
status = 4; /* Done */
|
||||
}
|
||||
|
||||
command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1;
|
||||
HandleCommand();
|
||||
return byte_to_send;
|
||||
}
|
||||
|
||||
if (command_state >= CommandState.GB_PRINTER_COMMAND_ID && command_state < CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW)
|
||||
{
|
||||
checksum += byte_received;
|
||||
}
|
||||
|
||||
if (command_state != CommandState.GB_PRINTER_COMMAND_DATA)
|
||||
{
|
||||
command_state++;
|
||||
}
|
||||
|
||||
if (command_state == CommandState.GB_PRINTER_COMMAND_DATA)
|
||||
{
|
||||
if (length_left == 0)
|
||||
{
|
||||
command_state++;
|
||||
}
|
||||
}
|
||||
|
||||
return byte_to_send;
|
||||
}
|
||||
|
||||
void HandleCommand()
|
||||
{
|
||||
switch (command_id)
|
||||
{
|
||||
case CommandID.GB_PRINTER_INIT_COMMAND:
|
||||
status = 0;
|
||||
image_offset = 0;
|
||||
break;
|
||||
|
||||
case CommandID.GB_PRINTER_START_COMMAND:
|
||||
if (command_length == 4)
|
||||
{
|
||||
status = 6; /* Printing */
|
||||
uint[] outputImage = new uint[image_offset];
|
||||
|
||||
int palette = command_data[2];
|
||||
uint[] colors = new uint[] {
|
||||
0xFFFFFFFFU,
|
||||
0xFFAAAAAAU,
|
||||
0xFF555555U,
|
||||
0xFF000000U
|
||||
};
|
||||
for (int i = 0; i < image_offset; i++)
|
||||
{
|
||||
outputImage[i] = colors[(palette >> (image[i] * 2)) & 3];
|
||||
}
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
// The native-friendly callback almost seems silly now :P
|
||||
unsafe
|
||||
{
|
||||
fixed (uint* imagePtr = outputImage)
|
||||
{
|
||||
callback((IntPtr)imagePtr, (byte)(image_offset / 160),
|
||||
(byte)(command_data[1] >> 4), (byte)(command_data[1] & 7),
|
||||
(byte)(command_data[3] & 0x7F));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
image_offset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case CommandID.GB_PRINTER_DATA_COMMAND:
|
||||
if (command_length == GB_PRINTER_DATA_SIZE)
|
||||
{
|
||||
image_offset %= (ushort)image.Length;
|
||||
status = 8; /* Received 0x280 bytes */
|
||||
|
||||
int data_index = 0;
|
||||
|
||||
for (int row = 2; row > 0; row--)
|
||||
{
|
||||
for (int tile_x = 0; tile_x < 160 / 8; tile_x++)
|
||||
{
|
||||
for (int y = 0; y < 8; y++, data_index += 2)
|
||||
{
|
||||
for (int x_pixel = 0; x_pixel < 8; x_pixel++)
|
||||
{
|
||||
image[image_offset + tile_x * 8 + x_pixel + y * 160] =
|
||||
(byte)((command_data[data_index] >> 7) | ((command_data[data_index + 1] >> 7) << 1));
|
||||
command_data[data_index] <<= 1;
|
||||
command_data[data_index + 1] <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
image_offset += 8 * 160;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue