Screwball mode Apple II savestates
This commit is contained in:
parent
9024df91f5
commit
6ab8be0a1d
|
@ -119,11 +119,12 @@
|
|||
</Compile>
|
||||
<Compile Include="Calculator\TI83LinkPort.cs" />
|
||||
<Compile Include="Computers\AppleII\AppleII.cs" />
|
||||
<Compile Include="Computers\AppleII\AppleII.IAudioProvider.cs" />
|
||||
<Compile Include="Computers\AppleII\AppleII.IEmulator.cs">
|
||||
<DependentUpon>AppleII.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Computers\AppleII\AppleII.IInputPollable.cs">
|
||||
<DependentUpon>AppleII.cs</DependentUpon>
|
||||
<DependentUpon>AppleII.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Computers\AppleII\AppleII.IMemoryDomains.cs">
|
||||
<DependentUpon>AppleII.cs</DependentUpon>
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
[FeatureNotImplemented]
|
||||
public ISyncSoundProvider SyncSoundProvider
|
||||
{
|
||||
get { return _soundService; }
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using System.IO;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.AppleII
|
||||
{
|
||||
|
@ -7,39 +10,84 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
{
|
||||
public bool BinarySaveStatesPreferred { get { return true; } }
|
||||
|
||||
private class OtherData
|
||||
{
|
||||
public int Frame;
|
||||
public int LagCount;
|
||||
public bool IsLagFrame;
|
||||
public int CurrentDisk;
|
||||
public JObject Core;
|
||||
}
|
||||
private JsonSerializer ser = new JsonSerializer();
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
var w = new JTokenWriter();
|
||||
_machine.Serialize(w);
|
||||
|
||||
var o = new OtherData
|
||||
{
|
||||
Frame = Frame,
|
||||
LagCount = LagCount,
|
||||
IsLagFrame = IsLagFrame,
|
||||
CurrentDisk = CurrentDisk,
|
||||
Core = (JObject)w.Token,
|
||||
};
|
||||
|
||||
var jw = new JsonTextWriter(writer) { Formatting = Newtonsoft.Json.Formatting.Indented };
|
||||
ser.Serialize(jw, o);
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
var o = (OtherData)ser.Deserialize(reader, typeof(OtherData));
|
||||
Frame = o.Frame;
|
||||
LagCount = o.LagCount;
|
||||
IsLagFrame = o.IsLagFrame;
|
||||
CurrentDisk = o.CurrentDisk;
|
||||
|
||||
var r = new JTokenReader(o.Core);
|
||||
try
|
||||
{
|
||||
_machine = Jellyfish.Virtu.Machine.Deserialize(r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
throw;
|
||||
}
|
||||
// should not be needed.
|
||||
// InitDisk();
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
/*
|
||||
writer.Write(Frame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(IsLagFrame);
|
||||
writer.Write(CurrentDisk);
|
||||
_machine.SaveState(writer);
|
||||
*/
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
/*
|
||||
Frame = reader.ReadInt32();
|
||||
LagCount = reader.ReadInt32();
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
CurrentDisk = reader.ReadInt32();
|
||||
InitDisk();
|
||||
_machine.LoadState(reader);
|
||||
*/
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
return new byte[16];
|
||||
|
||||
if (_stateBuffer == null)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
|
|
|
@ -3,45 +3,23 @@ using Jellyfish.Virtu;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.AppleII
|
||||
{
|
||||
public partial class AppleII
|
||||
public partial class AppleII : IVideoProvider
|
||||
{
|
||||
public class BizVideoService : Jellyfish.Virtu.Services.VideoService, IVideoProvider
|
||||
{
|
||||
public int[] fb;
|
||||
private Jellyfish.Virtu.Services.VideoService _V
|
||||
{ get { return _machine.Video.VideoService; } }
|
||||
|
||||
int[] IVideoProvider.GetVideoBuffer() { return fb; }
|
||||
int[] IVideoProvider.GetVideoBuffer() { return _V.fb; }
|
||||
|
||||
// put together, these describe a metric on the screen
|
||||
// they should define the smallest size that the buffer can be placed inside such that:
|
||||
// 1. no actual pixel data is lost
|
||||
// 2. aspect ratio is accurate
|
||||
int IVideoProvider.VirtualWidth { get { return 560; } }
|
||||
int IVideoProvider.VirtualHeight { get { return 384; } }
|
||||
// put together, these describe a metric on the screen
|
||||
// they should define the smallest size that the buffer can be placed inside such that:
|
||||
// 1. no actual pixel data is lost
|
||||
// 2. aspect ratio is accurate
|
||||
int IVideoProvider.VirtualWidth { get { return 560; } }
|
||||
int IVideoProvider.VirtualHeight { get { return 384; } }
|
||||
|
||||
int IVideoProvider.BufferWidth { get { return 560; } }
|
||||
int IVideoProvider.BufferHeight { get { return 384; } }
|
||||
int IVideoProvider.BackgroundColor { get { return 0; } }
|
||||
int IVideoProvider.BufferWidth { get { return 560; } }
|
||||
int IVideoProvider.BufferHeight { get { return 384; } }
|
||||
int IVideoProvider.BackgroundColor { get { return 0; } }
|
||||
|
||||
public BizVideoService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
fb = new int[560 * 384];
|
||||
}
|
||||
|
||||
public override void SetFullScreen(bool isFullScreen)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void SetPixel(int x, int y, uint color)
|
||||
{
|
||||
int i = 560 * y + x;
|
||||
fb[i] = fb[i + 560] = (int)color;
|
||||
}
|
||||
public override void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
isPorted: true,
|
||||
isReleased: false
|
||||
)]
|
||||
public partial class AppleII : IEmulator, IStatable
|
||||
public partial class AppleII : IEmulator
|
||||
{
|
||||
public AppleII(CoreComm comm, IEnumerable<GameInfo> gameInfoSet, IEnumerable<byte[]> romSet, object settings)
|
||||
: this(comm, gameInfoSet.First(), romSet.First(), settings)
|
||||
|
@ -42,27 +42,11 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
|
||||
_machine = new Machine(_appleIIRom, _diskIIRom);
|
||||
|
||||
var vidService = new BizVideoService(_machine);
|
||||
_soundService = new BizAudioService(_machine);
|
||||
var gpService = new Jellyfish.Virtu.Services.GamePortService(_machine);
|
||||
var kbService = new BizKeyboardService(_machine);
|
||||
|
||||
_machine.Services.AddService(typeof(Jellyfish.Virtu.Services.DebugService), new Jellyfish.Virtu.Services.DebugService(_machine));
|
||||
_machine.Services.AddService(typeof(Jellyfish.Virtu.Services.AudioService), _soundService);
|
||||
_machine.Services.AddService(typeof(Jellyfish.Virtu.Services.VideoService), vidService);
|
||||
_machine.Services.AddService(typeof(Jellyfish.Virtu.Services.GamePortService), gpService);
|
||||
_machine.Services.AddService(typeof(Jellyfish.Virtu.Services.KeyboardService), kbService);
|
||||
_machine.BizInitialize();
|
||||
|
||||
(ServiceProvider as BasicServiceProvider).Register<IVideoProvider>(vidService);
|
||||
|
||||
//make a writeable memory stream cloned from the rom.
|
||||
//for junk.dsk the .dsk is important because it determines the format from that
|
||||
var ms = new MemoryStream();
|
||||
ms.Write(_disk1, 0, _disk1.Length);
|
||||
ms.Position = 0;
|
||||
bool writeProtected = false; //!!!!!!!!!!!!!!!!!!!
|
||||
Jellyfish.Virtu.Services.StorageService.LoadFile(ms, stream => _machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", stream, writeProtected));
|
||||
InitDisk();
|
||||
|
||||
SetupMemoryDomains();
|
||||
}
|
||||
|
@ -108,56 +92,31 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
|
||||
//make a writeable memory stream cloned from the rom.
|
||||
//for junk.dsk the .dsk is important because it determines the format from that
|
||||
var ms = new MemoryStream();
|
||||
ms.Write(_disk1, 0, _disk1.Length);
|
||||
ms.Position = 0;
|
||||
bool writeProtected = false; //!!!!!!!!!!!!!!!!!!!
|
||||
Jellyfish.Virtu.Services.StorageService.LoadFile(ms, stream => _machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", stream, writeProtected));
|
||||
_machine.BizNewDisk();
|
||||
|
||||
bool writeProtected = false; //!!!!!!!!!!!!!!!!!!
|
||||
_machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", (byte[])_disk1.Clone(), false);
|
||||
}
|
||||
|
||||
private readonly Machine _machine;
|
||||
private Machine _machine;
|
||||
private byte[] _disk1;
|
||||
private readonly byte[] _appleIIRom;
|
||||
private readonly byte[] _diskIIRom;
|
||||
private readonly BizAudioService _soundService;
|
||||
|
||||
private static readonly ControllerDefinition AppleIIController =
|
||||
new ControllerDefinition
|
||||
{
|
||||
Name = "Apple II Keyboard",
|
||||
BoolButtons =
|
||||
{
|
||||
"Up", "Down", "Left", "Right",
|
||||
"Tab", "Enter", "Escape", "Back", "Space",
|
||||
"Ctrl", "Shift", "Caps",
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I",
|
||||
"J", "K", "L", "M", "N", "O", "P", "Q", "R",
|
||||
"S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"Next Disk", "Previous Disk"
|
||||
}
|
||||
};
|
||||
private static readonly ControllerDefinition AppleIIController;
|
||||
|
||||
private class BizKeyboardService : KeyboardService
|
||||
private static readonly List<string> RealButtons = new List<string>(Keyboard.GetKeyNames());
|
||||
|
||||
private static readonly List<string> ExtraButtons = new List<string>
|
||||
{
|
||||
public BizKeyboardService(Machine _machine) : base(_machine) { }
|
||||
public override bool IsKeyDown(int key)
|
||||
{
|
||||
return key > 0;
|
||||
}
|
||||
}
|
||||
"Previous Disk",
|
||||
"Next Disk",
|
||||
};
|
||||
|
||||
private class BizAudioService : AudioService, ISyncSoundProvider
|
||||
static AppleII()
|
||||
{
|
||||
public BizAudioService(Machine _machine) : base(_machine) { }
|
||||
public override void SetVolume(float volume)
|
||||
{
|
||||
}
|
||||
public void DiscardSamples()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
AppleIIController = new ControllerDefinition { Name = "Apple IIe Keyboard" };
|
||||
AppleIIController.BoolButtons.AddRange(RealButtons);
|
||||
AppleIIController.BoolButtons.AddRange(ExtraButtons);
|
||||
}
|
||||
|
||||
private void FrameAdv(bool render, bool rendersound)
|
||||
|
@ -170,9 +129,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
{
|
||||
DecrementDisk();
|
||||
}
|
||||
|
||||
_machine.Buttons = GetButtons();
|
||||
_machine.BizFrameAdvance();
|
||||
|
||||
_machine.BizFrameAdvance(RealButtons.Where(b => Controller[b]));
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
|
@ -181,59 +139,5 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
|||
Frame++;
|
||||
}
|
||||
|
||||
private Buttons GetButtons()
|
||||
{
|
||||
Jellyfish.Virtu.Buttons ret = 0;
|
||||
if (Controller["Up"]) ret |= Jellyfish.Virtu.Buttons.Up;
|
||||
if (Controller["Down"]) ret |= Jellyfish.Virtu.Buttons.Down;
|
||||
if (Controller["Left"]) ret |= Jellyfish.Virtu.Buttons.Left;
|
||||
if (Controller["Right"]) ret |= Jellyfish.Virtu.Buttons.Right;
|
||||
if (Controller["Tab"]) ret |= Jellyfish.Virtu.Buttons.Tab;
|
||||
if (Controller["Enter"]) ret |= Jellyfish.Virtu.Buttons.Enter;
|
||||
if (Controller["Escape"]) ret |= Jellyfish.Virtu.Buttons.Escape;
|
||||
if (Controller["Back"]) ret |= Jellyfish.Virtu.Buttons.Back;
|
||||
if (Controller["Space"]) ret |= Jellyfish.Virtu.Buttons.Space;
|
||||
if (Controller["Ctrl"]) ret |= Jellyfish.Virtu.Buttons.Ctrl;
|
||||
if (Controller["Shift"]) ret |= Jellyfish.Virtu.Buttons.Shift;
|
||||
if (Controller["Caps"]) ret |= Jellyfish.Virtu.Buttons.Caps;
|
||||
if (Controller["1"]) ret |= Jellyfish.Virtu.Buttons.Key1;
|
||||
if (Controller["2"]) ret |= Jellyfish.Virtu.Buttons.Key2;
|
||||
if (Controller["3"]) ret |= Jellyfish.Virtu.Buttons.Key3;
|
||||
if (Controller["4"]) ret |= Jellyfish.Virtu.Buttons.Key4;
|
||||
if (Controller["5"]) ret |= Jellyfish.Virtu.Buttons.Key5;
|
||||
if (Controller["6"]) ret |= Jellyfish.Virtu.Buttons.Key6;
|
||||
if (Controller["7"]) ret |= Jellyfish.Virtu.Buttons.Key7;
|
||||
if (Controller["8"]) ret |= Jellyfish.Virtu.Buttons.Key8;
|
||||
if (Controller["9"]) ret |= Jellyfish.Virtu.Buttons.Key9;
|
||||
if (Controller["0"]) ret |= Jellyfish.Virtu.Buttons.Key0;
|
||||
if (Controller["A"]) ret |= Jellyfish.Virtu.Buttons.KeyA;
|
||||
if (Controller["B"]) ret |= Jellyfish.Virtu.Buttons.KeyB;
|
||||
if (Controller["C"]) ret |= Jellyfish.Virtu.Buttons.KeyC;
|
||||
if (Controller["D"]) ret |= Jellyfish.Virtu.Buttons.KeyD;
|
||||
if (Controller["E"]) ret |= Jellyfish.Virtu.Buttons.KeyE;
|
||||
if (Controller["F"]) ret |= Jellyfish.Virtu.Buttons.KeyF;
|
||||
if (Controller["G"]) ret |= Jellyfish.Virtu.Buttons.KeyG;
|
||||
if (Controller["H"]) ret |= Jellyfish.Virtu.Buttons.KeyH;
|
||||
if (Controller["I"]) ret |= Jellyfish.Virtu.Buttons.KeyI;
|
||||
if (Controller["J"]) ret |= Jellyfish.Virtu.Buttons.KeyJ;
|
||||
if (Controller["K"]) ret |= Jellyfish.Virtu.Buttons.KeyK;
|
||||
if (Controller["L"]) ret |= Jellyfish.Virtu.Buttons.KeyL;
|
||||
if (Controller["M"]) ret |= Jellyfish.Virtu.Buttons.KeyM;
|
||||
if (Controller["N"]) ret |= Jellyfish.Virtu.Buttons.KeyN;
|
||||
if (Controller["O"]) ret |= Jellyfish.Virtu.Buttons.KeyO;
|
||||
if (Controller["P"]) ret |= Jellyfish.Virtu.Buttons.KeyP;
|
||||
if (Controller["Q"]) ret |= Jellyfish.Virtu.Buttons.KeyQ;
|
||||
if (Controller["R"]) ret |= Jellyfish.Virtu.Buttons.KeyR;
|
||||
if (Controller["S"]) ret |= Jellyfish.Virtu.Buttons.KeyS;
|
||||
if (Controller["T"]) ret |= Jellyfish.Virtu.Buttons.KeyT;
|
||||
if (Controller["U"]) ret |= Jellyfish.Virtu.Buttons.KeyU;
|
||||
if (Controller["V"]) ret |= Jellyfish.Virtu.Buttons.KeyV;
|
||||
if (Controller["W"]) ret |= Jellyfish.Virtu.Buttons.KeyW;
|
||||
if (Controller["X"]) ret |= Jellyfish.Virtu.Buttons.KeyX;
|
||||
if (Controller["Y"]) ret |= Jellyfish.Virtu.Buttons.KeyY;
|
||||
if (Controller["Z"]) ret |= Jellyfish.Virtu.Buttons.KeyZ;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
|
||||
prg_bank_mask_8k = Cart.prg_size / 8 - 1;
|
||||
chr_bank_mask_1k = Cart.chr_size - 1;
|
||||
chr_bank_mask_1k = 0xff; // Cart.chr_size - 1;
|
||||
|
||||
SetMirrorType(EMirrorType.Vertical);
|
||||
|
||||
|
|
|
@ -4,18 +4,17 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed class Cassette : MachineComponent
|
||||
{
|
||||
public Cassette() { }
|
||||
public Cassette(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public bool ReadInput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public void ToggleOutput()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed partial class Cpu : MachineComponent
|
||||
{
|
||||
public Cpu() { }
|
||||
public Cpu(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -169,44 +170,6 @@ namespace Jellyfish.Virtu
|
|||
}
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
Is65C02 = reader.ReadBoolean();
|
||||
IsThrottled = reader.ReadBoolean();
|
||||
Multiplier = reader.ReadInt32();
|
||||
|
||||
RA = reader.ReadInt32();
|
||||
RX = reader.ReadInt32();
|
||||
RY = reader.ReadInt32();
|
||||
RS = reader.ReadInt32();
|
||||
RP = reader.ReadInt32();
|
||||
RPC = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(Is65C02);
|
||||
writer.Write(IsThrottled);
|
||||
writer.Write(Multiplier);
|
||||
|
||||
writer.Write(RA);
|
||||
writer.Write(RX);
|
||||
writer.Write(RY);
|
||||
writer.Write(RS);
|
||||
writer.Write(RP);
|
||||
writer.Write(RPC);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(CultureInfo.InvariantCulture, "A = 0x{0:X2} X = 0x{1:X2} Y = 0x{2:X2} P = 0x{3:X2} S = 0x01{4:X2} PC = 0x{5:X4} EA = 0x{6:X4} CC = {7}",
|
||||
|
@ -214,14 +177,15 @@ namespace Jellyfish.Virtu
|
|||
}
|
||||
|
||||
public int Execute()
|
||||
{
|
||||
CC = 0;
|
||||
{
|
||||
CC = 0;
|
||||
OpCode = _memory.Read(RPC);
|
||||
RPC = (RPC + 1) & 0xFFFF;
|
||||
_executeOpCode[OpCode]();
|
||||
Cycles += CC;
|
||||
|
||||
return CC;
|
||||
|
||||
return CC;
|
||||
}
|
||||
|
||||
#region Core Operand Actions
|
||||
|
@ -3238,6 +3202,7 @@ namespace Jellyfish.Virtu
|
|||
}
|
||||
#endregion
|
||||
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public bool Is65C02 { get { return _is65C02; } set { _is65C02 = value; _executeOpCode = _is65C02 ? ExecuteOpCode65C02 : ExecuteOpCode65N02; } }
|
||||
public bool IsThrottled { get; set; }
|
||||
public int Multiplier { get; set; }
|
||||
|
|
|
@ -6,8 +6,8 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
private const int OpCodeCount = 256;
|
||||
|
||||
private readonly Action[] ExecuteOpCode65N02;
|
||||
private readonly Action[] ExecuteOpCode65C02;
|
||||
private Action[] ExecuteOpCode65N02;
|
||||
private Action[] ExecuteOpCode65C02;
|
||||
|
||||
private const int PC = 0x01;
|
||||
private const int PZ = 0x02;
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public abstract class Disk525
|
||||
{
|
||||
public Disk525() { }
|
||||
protected Disk525(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
Name = name;
|
||||
|
@ -15,43 +16,13 @@ namespace Jellyfish.Virtu
|
|||
IsWriteProtected = isWriteProtected;
|
||||
}
|
||||
|
||||
public static Disk525 CreateDisk(string name, Stream stream, bool isWriteProtected)
|
||||
public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
|
||||
if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) ||
|
||||
name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew
|
||||
{
|
||||
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.Dos);
|
||||
}
|
||||
else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new DiskNib(name, stream, isWriteProtected);
|
||||
}
|
||||
else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new DiskDsk(name, stream, isWriteProtected, SectorSkew.ProDos);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "version")]
|
||||
public static Disk525 LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
string name = reader.ReadString();
|
||||
var dataSize = reader.ReadInt32();
|
||||
var data = reader.ReadBytes(dataSize);
|
||||
bool isWriteProtected = reader.ReadBoolean();
|
||||
|
||||
if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) ||
|
||||
name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew
|
||||
{
|
||||
|
@ -69,19 +40,6 @@ namespace Jellyfish.Virtu
|
|||
return null;
|
||||
}
|
||||
|
||||
public void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(Name);
|
||||
writer.Write(Data.Length);
|
||||
writer.Write(Data);
|
||||
writer.Write(IsWriteProtected);
|
||||
}
|
||||
|
||||
public abstract void ReadTrack(int number, int fraction, byte[] buffer);
|
||||
public abstract void WriteTrack(int number, int fraction, byte[] buffer);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
public sealed class DiskDsk : Disk525
|
||||
{
|
||||
public DiskDsk() { }
|
||||
public DiskDsk(string name, byte[] data, bool isWriteProtected, SectorSkew sectorSkew) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
|
|
|
@ -4,11 +4,13 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.IO;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public sealed class DiskIIController : PeripheralCard
|
||||
{
|
||||
public DiskIIController() { }
|
||||
public DiskIIController(Machine machine, byte[] diskIIRom) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -16,7 +18,7 @@ namespace Jellyfish.Virtu
|
|||
Drive1 = new DiskIIDrive(machine);
|
||||
Drive2 = new DiskIIDrive(machine);
|
||||
|
||||
Drives = new Collection<DiskIIDrive> { Drive1, Drive2 };
|
||||
Drives = new List<DiskIIDrive> { Drive1, Drive2 };
|
||||
|
||||
BootDrive = Drive1;
|
||||
}
|
||||
|
@ -32,50 +34,6 @@ namespace Jellyfish.Virtu
|
|||
_writeMode = false;
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
_latch = reader.ReadInt32();
|
||||
_phaseStates = reader.ReadInt32();
|
||||
_motorOn = reader.ReadBoolean();
|
||||
_driveNumber = reader.ReadInt32();
|
||||
_loadMode = reader.ReadBoolean();
|
||||
_writeMode = reader.ReadBoolean();
|
||||
_driveSpin = reader.ReadBoolean();
|
||||
foreach (var drive in Drives)
|
||||
{
|
||||
DebugService.WriteMessage("Loading machine '{0}'", drive.GetType().Name);
|
||||
drive.LoadState(reader, version);
|
||||
//DebugService.WriteMessage("Loaded machine '{0}'", drive.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(_latch);
|
||||
writer.Write(_phaseStates);
|
||||
writer.Write(_motorOn);
|
||||
writer.Write(_driveNumber);
|
||||
writer.Write(_loadMode);
|
||||
writer.Write(_writeMode);
|
||||
writer.Write(_driveSpin);
|
||||
foreach (var drive in Drives)
|
||||
{
|
||||
DebugService.WriteMessage("Saving machine '{0}'", drive.GetType().Name);
|
||||
drive.SaveState(writer);
|
||||
//DebugService.WriteMessage("Saved machine '{0}'", drive.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
public override int ReadIoRegionC0C0(int address)
|
||||
{
|
||||
|
@ -263,7 +221,7 @@ namespace Jellyfish.Virtu
|
|||
public DiskIIDrive Drive1 { get; private set; }
|
||||
public DiskIIDrive Drive2 { get; private set; }
|
||||
|
||||
public Collection<DiskIIDrive> Drives { get; private set; }
|
||||
public List<DiskIIDrive> Drives { get; private set; }
|
||||
|
||||
public DiskIIDrive BootDrive { get; private set; }
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed class DiskIIDrive : MachineComponent
|
||||
{
|
||||
public DiskIIDrive() { }
|
||||
public DiskIIDrive(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -16,60 +17,11 @@ namespace Jellyfish.Virtu
|
|||
DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
_trackLoaded = reader.ReadBoolean();
|
||||
_trackChanged = reader.ReadBoolean();
|
||||
_trackNumber = reader.ReadInt32();
|
||||
_trackOffset = reader.ReadInt32();
|
||||
if (_trackLoaded)
|
||||
{
|
||||
reader.Read(_trackData, 0, _trackData.Length);
|
||||
}
|
||||
if (reader.ReadBoolean())
|
||||
{
|
||||
DebugService.WriteMessage("Loading machine '{0}'", typeof(Disk525).Name);
|
||||
_disk = Disk525.LoadState(reader, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
_disk = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(_trackLoaded);
|
||||
writer.Write(_trackChanged);
|
||||
writer.Write(_trackNumber);
|
||||
writer.Write(_trackOffset);
|
||||
if (_trackLoaded)
|
||||
{
|
||||
writer.Write(_trackData);
|
||||
}
|
||||
writer.Write(_disk != null);
|
||||
if (_disk != null)
|
||||
{
|
||||
DebugService.WriteMessage("Saving machine '{0}'", _disk.GetType().Name);
|
||||
_disk.SaveState(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertDisk(string name, Stream stream, bool isWriteProtected)
|
||||
public void InsertDisk(string name, byte[] data, bool isWriteProtected)
|
||||
{
|
||||
DebugService.WriteMessage("Inserting disk '{0}'", name);
|
||||
FlushTrack();
|
||||
_disk = Disk525.CreateDisk(name, stream, isWriteProtected);
|
||||
_disk = Disk525.CreateDisk(name, data, isWriteProtected);
|
||||
_trackLoaded = false;
|
||||
}
|
||||
|
||||
|
@ -116,7 +68,9 @@ namespace Jellyfish.Virtu
|
|||
return data;
|
||||
}
|
||||
|
||||
return _random.Next(0x01, 0xFF);
|
||||
return 0x80;
|
||||
// TODO: WTF was this
|
||||
//return _random.Next(0x01, 0xFF);
|
||||
}
|
||||
|
||||
public void Write(int data)
|
||||
|
@ -152,13 +106,14 @@ namespace Jellyfish.Virtu
|
|||
}
|
||||
}
|
||||
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public bool IsWriteProtected { get { return _disk.IsWriteProtected; } }
|
||||
|
||||
private const int TrackNumberMax = 0x44;
|
||||
|
||||
private const int PhaseCount = 4;
|
||||
|
||||
private readonly int[][] DriveArmStepDelta = new int[PhaseCount][];
|
||||
private int[][] DriveArmStepDelta = new int[PhaseCount][];
|
||||
|
||||
private bool _trackLoaded;
|
||||
private bool _trackChanged;
|
||||
|
@ -166,7 +121,5 @@ namespace Jellyfish.Virtu
|
|||
private int _trackOffset;
|
||||
private byte[] _trackData = new byte[Disk525.TrackSize];
|
||||
private Disk525 _disk;
|
||||
|
||||
private Random _random = new Random();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed class DiskNib : Disk525
|
||||
{
|
||||
public DiskNib() { }
|
||||
public DiskNib(string name, byte[] data, bool isWriteProtected) :
|
||||
base(name, data, isWriteProtected)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public class ArrayConverter : JsonConverter
|
||||
{
|
||||
// JSON.NET cannot, when reading, use PreserveReferencesHandling on arrays, although it fully supports it on writing.
|
||||
// stupid decision, but there you have it. we need that to work here.
|
||||
|
||||
// as an added "bonus", this disables base64ing of byte[] arrays.
|
||||
// TODO: optimize the byte/short/int cases.
|
||||
|
||||
// TODO: on serialization, the type of the object is available, but is the expected type (ie, the one that we'll be fed during deserialization) available?
|
||||
// need this to at least detect covariance cases...
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
if (!typeof(Array).IsAssignableFrom(objectType))
|
||||
return false;
|
||||
|
||||
if (objectType.GetArrayRank() > 1)
|
||||
throw new NotImplementedException();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
public override bool CanWrite { get { return true; } }
|
||||
|
||||
int nextRef = 1;
|
||||
Dictionary<object, int> refs = new Dictionary<object, int>();
|
||||
Dictionary<int, Array> readrefs = new Dictionary<int, Array>();
|
||||
|
||||
private static void ReadExpectType(JsonReader reader, JsonToken expected)
|
||||
{
|
||||
if (!reader.Read())
|
||||
throw new InvalidOperationException();
|
||||
if (reader.TokenType != expected)
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return null;
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
ReadExpectType(reader, JsonToken.PropertyName);
|
||||
if (reader.Value.ToString() != "$myRef")
|
||||
throw new InvalidOperationException();
|
||||
ReadExpectType(reader, JsonToken.Integer);
|
||||
int myRef = Convert.ToInt32(reader.Value);
|
||||
|
||||
if (!reader.Read())
|
||||
throw new InvalidOperationException();
|
||||
if (reader.TokenType == JsonToken.EndObject)
|
||||
return readrefs[myRef];
|
||||
else if (reader.TokenType != JsonToken.PropertyName || reader.Value.ToString() != "$myCount")
|
||||
throw new InvalidOperationException();
|
||||
ReadExpectType(reader, JsonToken.Integer);
|
||||
int myCount = Convert.ToInt32(reader.Value);
|
||||
|
||||
ReadExpectType(reader, JsonToken.PropertyName);
|
||||
if (reader.Value.ToString() != "$myVals")
|
||||
throw new InvalidOperationException();
|
||||
ReadExpectType(reader, JsonToken.StartArray);
|
||||
var elementType = objectType.GetElementType();
|
||||
Array ret = Array.CreateInstance(elementType, myCount);
|
||||
for (int i = 0; i < myCount; i++)
|
||||
{
|
||||
if (!reader.Read())
|
||||
throw new InvalidOperationException();
|
||||
ret.SetValue(serializer.Deserialize(reader, elementType), i);
|
||||
}
|
||||
ReadExpectType(reader, JsonToken.EndArray);
|
||||
|
||||
ReadExpectType(reader, JsonToken.EndObject);
|
||||
readrefs[myRef] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
int myRef;
|
||||
if (refs.TryGetValue(value, out myRef))
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("$myRef");
|
||||
writer.WriteValue(myRef);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
myRef = nextRef++;
|
||||
refs.Add(value, myRef);
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("$myRef");
|
||||
writer.WriteValue(myRef);
|
||||
writer.WritePropertyName("$myCount"); // not needed, but avoids us having to make some sort of temp structure on deserialization
|
||||
writer.WriteValue(((Array)value).Length);
|
||||
writer.WritePropertyName("$myVals");
|
||||
writer.WriteStartArray();
|
||||
var elementType = value.GetType().GetElementType();
|
||||
foreach (object o in (Array)value)
|
||||
{
|
||||
serializer.Serialize(writer, o, elementType);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DelegateConverter : JsonConverter
|
||||
{
|
||||
// caveats: if used on anonymous delegates and/or closures, brittle to name changes in the generated classes and methods
|
||||
// brittle to type name changes in general
|
||||
// must be serialized in tree with any real classes referred to by closures
|
||||
|
||||
// TODO: much of this could be made somewhat smarter and more resilient
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(Delegate).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
public override bool CanWrite { get { return true; } }
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var slug = serializer.Deserialize<Slug>(reader);
|
||||
if (slug == null)
|
||||
return null;
|
||||
return slug.GetDelegate();
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var slug = new Slug((Delegate)value);
|
||||
serializer.Serialize(writer, slug);
|
||||
}
|
||||
|
||||
private class Slug
|
||||
{
|
||||
public Type DelegateType;
|
||||
public Type MethodDeclaringType;
|
||||
public string MethodName;
|
||||
public List<Type> MethodParameters;
|
||||
public object Target;
|
||||
|
||||
public Delegate GetDelegate()
|
||||
{
|
||||
var mi = MethodDeclaringType.GetMethod(
|
||||
MethodName,
|
||||
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static,
|
||||
null,
|
||||
MethodParameters.ToArray(),
|
||||
null);
|
||||
|
||||
return Delegate.CreateDelegate(DelegateType, Target, mi);
|
||||
}
|
||||
|
||||
public Slug() { }
|
||||
|
||||
public Slug(Delegate d)
|
||||
{
|
||||
DelegateType = d.GetType();
|
||||
MethodDeclaringType = d.Method.DeclaringType;
|
||||
MethodName = d.Method.Name;
|
||||
MethodParameters = d.Method.GetParameters().Select(p => p.ParameterType).ToList();
|
||||
Target = d.Target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,15 +8,31 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed class GamePort : MachineComponent
|
||||
{
|
||||
// TODO: ressurect this
|
||||
public bool ReadButton0() { return false; }
|
||||
public bool ReadButton1() { return false; }
|
||||
public bool ReadButton2() { return false; }
|
||||
|
||||
public bool Paddle0Strobe { get { return false; } }
|
||||
public bool Paddle1Strobe { get { return false; } }
|
||||
public bool Paddle2Strobe { get { return false; } }
|
||||
public bool Paddle3Strobe { get { return false; } }
|
||||
|
||||
public void TriggerTimers() { }
|
||||
|
||||
public GamePort() { }
|
||||
public GamePort(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
/*
|
||||
_resetPaddle0StrobeEvent = ResetPaddle0StrobeEvent; // cache delegates; avoids garbage
|
||||
_resetPaddle1StrobeEvent = ResetPaddle1StrobeEvent;
|
||||
_resetPaddle2StrobeEvent = ResetPaddle2StrobeEvent;
|
||||
_resetPaddle3StrobeEvent = ResetPaddle3StrobeEvent;
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
public override void Initialize()
|
||||
{
|
||||
_keyboardService = Machine.Services.GetService<KeyboardService>();
|
||||
|
@ -46,137 +62,7 @@ namespace Jellyfish.Virtu
|
|||
Button2TouchHeight = 0.25f;
|
||||
Button2TouchOrder = 1;
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
InvertPaddles = reader.ReadBoolean();
|
||||
SwapPaddles = reader.ReadBoolean();
|
||||
UseShiftKeyMod = reader.ReadBoolean();
|
||||
JoystickDeadZone = reader.ReadSingle();
|
||||
|
||||
UseKeyboard = reader.ReadBoolean();
|
||||
Joystick0UpLeftKey = reader.ReadInt32();
|
||||
Joystick0UpKey = reader.ReadInt32();
|
||||
Joystick0UpRightKey = reader.ReadInt32();
|
||||
Joystick0LeftKey = reader.ReadInt32();
|
||||
Joystick0RightKey = reader.ReadInt32();
|
||||
Joystick0DownLeftKey = reader.ReadInt32();
|
||||
Joystick0DownKey = reader.ReadInt32();
|
||||
Joystick0DownRightKey = reader.ReadInt32();
|
||||
Joystick1UpLeftKey = reader.ReadInt32();
|
||||
Joystick1UpKey = reader.ReadInt32();
|
||||
Joystick1UpRightKey = reader.ReadInt32();
|
||||
Joystick1LeftKey = reader.ReadInt32();
|
||||
Joystick1RightKey = reader.ReadInt32();
|
||||
Joystick1DownLeftKey = reader.ReadInt32();
|
||||
Joystick1DownKey = reader.ReadInt32();
|
||||
Joystick1DownRightKey = reader.ReadInt32();
|
||||
Button0Key = reader.ReadInt32();
|
||||
Button1Key = reader.ReadInt32();
|
||||
Button2Key = reader.ReadInt32();
|
||||
|
||||
UseTouch = reader.ReadBoolean();
|
||||
Joystick0TouchX = reader.ReadSingle();
|
||||
Joystick0TouchY = reader.ReadSingle();
|
||||
Joystick0TouchWidth = reader.ReadSingle();
|
||||
Joystick0TouchHeight = reader.ReadSingle();
|
||||
Joystick0TouchOrder = reader.ReadInt32();
|
||||
Joystick0TouchRadius = reader.ReadSingle();
|
||||
Joystick0TouchKeepLast = reader.ReadBoolean();
|
||||
Joystick1TouchX = reader.ReadSingle();
|
||||
Joystick1TouchY = reader.ReadSingle();
|
||||
Joystick1TouchWidth = reader.ReadSingle();
|
||||
Joystick1TouchHeight = reader.ReadSingle();
|
||||
Joystick1TouchOrder = reader.ReadInt32();
|
||||
Joystick1TouchRadius = reader.ReadSingle();
|
||||
Joystick1TouchKeepLast = reader.ReadBoolean();
|
||||
Button0TouchX = reader.ReadSingle();
|
||||
Button0TouchY = reader.ReadSingle();
|
||||
Button0TouchWidth = reader.ReadSingle();
|
||||
Button0TouchHeight = reader.ReadSingle();
|
||||
Button0TouchOrder = reader.ReadInt32();
|
||||
Button1TouchX = reader.ReadSingle();
|
||||
Button1TouchY = reader.ReadSingle();
|
||||
Button1TouchWidth = reader.ReadSingle();
|
||||
Button1TouchHeight = reader.ReadSingle();
|
||||
Button1TouchOrder = reader.ReadInt32();
|
||||
Button2TouchX = reader.ReadSingle();
|
||||
Button2TouchY = reader.ReadSingle();
|
||||
Button2TouchWidth = reader.ReadSingle();
|
||||
Button2TouchHeight = reader.ReadSingle();
|
||||
Button2TouchOrder = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(InvertPaddles);
|
||||
writer.Write(SwapPaddles);
|
||||
writer.Write(UseShiftKeyMod);
|
||||
writer.Write(JoystickDeadZone);
|
||||
|
||||
writer.Write(UseKeyboard);
|
||||
writer.Write(Joystick0UpLeftKey);
|
||||
writer.Write(Joystick0UpKey);
|
||||
writer.Write(Joystick0UpRightKey);
|
||||
writer.Write(Joystick0LeftKey);
|
||||
writer.Write(Joystick0RightKey);
|
||||
writer.Write(Joystick0DownLeftKey);
|
||||
writer.Write(Joystick0DownKey);
|
||||
writer.Write(Joystick0DownRightKey);
|
||||
writer.Write(Joystick1UpLeftKey);
|
||||
writer.Write(Joystick1UpKey);
|
||||
writer.Write(Joystick1UpRightKey);
|
||||
writer.Write(Joystick1LeftKey);
|
||||
writer.Write(Joystick1RightKey);
|
||||
writer.Write(Joystick1DownLeftKey);
|
||||
writer.Write(Joystick1DownKey);
|
||||
writer.Write(Joystick1DownRightKey);
|
||||
writer.Write(Button0Key);
|
||||
writer.Write(Button1Key);
|
||||
writer.Write(Button2Key);
|
||||
|
||||
writer.Write(UseTouch);
|
||||
writer.Write(Joystick0TouchX);
|
||||
writer.Write(Joystick0TouchY);
|
||||
writer.Write(Joystick0TouchWidth);
|
||||
writer.Write(Joystick0TouchHeight);
|
||||
writer.Write(Joystick0TouchOrder);
|
||||
writer.Write(Joystick0TouchRadius);
|
||||
writer.Write(Joystick0TouchKeepLast);
|
||||
writer.Write(Joystick1TouchX);
|
||||
writer.Write(Joystick1TouchY);
|
||||
writer.Write(Joystick1TouchWidth);
|
||||
writer.Write(Joystick1TouchHeight);
|
||||
writer.Write(Joystick1TouchOrder);
|
||||
writer.Write(Joystick1TouchRadius);
|
||||
writer.Write(Joystick1TouchKeepLast);
|
||||
writer.Write(Button0TouchX);
|
||||
writer.Write(Button0TouchY);
|
||||
writer.Write(Button0TouchWidth);
|
||||
writer.Write(Button0TouchHeight);
|
||||
writer.Write(Button0TouchOrder);
|
||||
writer.Write(Button1TouchX);
|
||||
writer.Write(Button1TouchY);
|
||||
writer.Write(Button1TouchWidth);
|
||||
writer.Write(Button1TouchHeight);
|
||||
writer.Write(Button1TouchOrder);
|
||||
writer.Write(Button2TouchX);
|
||||
writer.Write(Button2TouchY);
|
||||
writer.Write(Button2TouchWidth);
|
||||
writer.Write(Button2TouchHeight);
|
||||
writer.Write(Button2TouchOrder);
|
||||
}
|
||||
|
||||
|
||||
public bool ReadButton0()
|
||||
{
|
||||
return (_gamePortService.IsButton0Down || _keyboardService.IsOpenAppleKeyDown ||
|
||||
|
@ -365,6 +251,6 @@ namespace Jellyfish.Virtu
|
|||
private Action _resetPaddle3StrobeEvent;
|
||||
|
||||
private KeyboardService _keyboardService;
|
||||
private GamePortService _gamePortService;
|
||||
private GamePortService _gamePortService;*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,122 +1,370 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
[Flags]
|
||||
internal enum Keys : ulong
|
||||
{
|
||||
// https://archive.org/stream/Apple_IIe_Technical_Reference_Manual
|
||||
|
||||
// 56 basic keys as described in the reference manual
|
||||
[Description("Delete")]
|
||||
Delete = 1UL,
|
||||
[Description("Left")]
|
||||
Left = 2UL,
|
||||
[Description("Tab")]
|
||||
Tab = 4UL,
|
||||
[Description("Down")]
|
||||
Down = 8UL,
|
||||
[Description("Up")]
|
||||
Up = 16UL,
|
||||
[Description("Return")]
|
||||
Return = 32UL,
|
||||
[Description("Right")]
|
||||
Right = 64UL,
|
||||
[Description("Escape")]
|
||||
Escape = 128UL,
|
||||
[Description("Space")]
|
||||
Space = 256UL,
|
||||
[Description("'")]
|
||||
Apostrophe = 512UL,
|
||||
[Description(",")]
|
||||
Comma = 1024UL,
|
||||
[Description("-")]
|
||||
Dash = 2048UL,
|
||||
[Description(".")]
|
||||
Period = 4096UL,
|
||||
[Description("/")]
|
||||
Slash = 8192UL,
|
||||
[Description("0")]
|
||||
Key0 = 16384UL,
|
||||
[Description("1")]
|
||||
Key1 = 32768UL,
|
||||
[Description("2")]
|
||||
Key2 = 65536UL,
|
||||
[Description("3")]
|
||||
Key3 = 131072UL,
|
||||
[Description("4")]
|
||||
Key4 = 262144UL,
|
||||
[Description("5")]
|
||||
Key5 = 524288UL,
|
||||
[Description("6")]
|
||||
Key6 = 1048576UL,
|
||||
[Description("7")]
|
||||
Key7 = 2097152UL,
|
||||
[Description("8")]
|
||||
Key8 = 4194304UL,
|
||||
[Description("9")]
|
||||
Key9 = 8388608UL,
|
||||
[Description(";")]
|
||||
Semicolon = 16777216UL,
|
||||
[Description("=")]
|
||||
Equals = 33554432UL,
|
||||
[Description("[")]
|
||||
LeftBracket = 67108864UL,
|
||||
[Description("\\")]
|
||||
Backslash = 134217728UL,
|
||||
[Description("]")]
|
||||
RightBracket = 268435456UL,
|
||||
[Description("`")]
|
||||
Backtick = 536870912UL,
|
||||
[Description("A")]
|
||||
A = 1073741824UL,
|
||||
[Description("B")]
|
||||
B = 2147483648UL,
|
||||
[Description("C")]
|
||||
C = 4294967296UL,
|
||||
[Description("D")]
|
||||
D = 8589934592UL,
|
||||
[Description("E")]
|
||||
E = 17179869184UL,
|
||||
[Description("F")]
|
||||
F = 34359738368UL,
|
||||
[Description("G")]
|
||||
G = 68719476736UL,
|
||||
[Description("H")]
|
||||
H = 137438953472UL,
|
||||
[Description("I")]
|
||||
I = 274877906944UL,
|
||||
[Description("J")]
|
||||
J = 549755813888UL,
|
||||
[Description("K")]
|
||||
K = 1099511627776UL,
|
||||
[Description("L")]
|
||||
L = 2199023255552UL,
|
||||
[Description("M")]
|
||||
M = 4398046511104UL,
|
||||
[Description("N")]
|
||||
N = 8796093022208UL,
|
||||
[Description("O")]
|
||||
O = 17592186044416UL,
|
||||
[Description("P")]
|
||||
P = 35184372088832UL,
|
||||
[Description("Q")]
|
||||
Q = 70368744177664UL,
|
||||
[Description("R")]
|
||||
R = 140737488355328UL,
|
||||
[Description("S")]
|
||||
S = 281474976710656UL,
|
||||
[Description("T")]
|
||||
T = 562949953421312UL,
|
||||
[Description("U")]
|
||||
U = 1125899906842624UL,
|
||||
[Description("V")]
|
||||
V = 2251799813685248UL,
|
||||
[Description("W")]
|
||||
W = 4503599627370496UL,
|
||||
[Description("X")]
|
||||
X = 9007199254740992UL,
|
||||
[Description("Y")]
|
||||
Y = 18014398509481984UL,
|
||||
[Description("Z")]
|
||||
Z = 36028797018963968UL,
|
||||
|
||||
// three modifier keys, cannot be read directly
|
||||
[Description("Control")]
|
||||
Control = 72057594037927936UL,
|
||||
[Description("Shift")]
|
||||
Shift = 144115188075855872UL,
|
||||
[Description("Caps Lock")]
|
||||
CapsLock = 288230376151711744UL,
|
||||
|
||||
// three special keys
|
||||
[Description("White Apple")]
|
||||
WhiteApple = 576460752303423488UL, // connected to GAME1
|
||||
[Description("Black Apple")]
|
||||
BlackApple = 1152921504606846976UL, // connected to GAME2
|
||||
[Description("Reset")]
|
||||
Reset = 2305843009213693952UL,
|
||||
}
|
||||
|
||||
|
||||
public sealed class Keyboard : MachineComponent
|
||||
{
|
||||
public Keyboard(Machine machine) :
|
||||
private static readonly uint[] KeyAsciiData = new uint[]
|
||||
{
|
||||
// https://archive.org/stream/Apple_IIe_Technical_Reference_Manual#page/n47/mode/2up
|
||||
// 0xNNCCSSBB normal, control, shift both
|
||||
// keys in same order as above
|
||||
0x7f7f7f7f,
|
||||
0x08080808,
|
||||
0x09090909,
|
||||
0x0a0a0a0a,
|
||||
0x0b0b0b0b,
|
||||
0x0d0d0d0d,
|
||||
0x15151515,
|
||||
0x1b1b1b1b,
|
||||
0x20202020,
|
||||
0x27272222,
|
||||
0x2c2c3c3c,
|
||||
0x2d1f5f1f,
|
||||
0x2e2e3e3e,
|
||||
0x2f2f3f3f,
|
||||
0x30302929, // 0
|
||||
0x31312121,
|
||||
0x32004000,
|
||||
0x33332323,
|
||||
0x34342424,
|
||||
0x35352525,
|
||||
0x361e5e1e,
|
||||
0x37372626,
|
||||
0x38382a2a,
|
||||
0x39392828, // 9
|
||||
0x3b3b3a3a,
|
||||
0x3d3d2b2b,
|
||||
0x5b1b7b1b,
|
||||
0x5c1c7c1c,
|
||||
0x5d1d7d1d,
|
||||
0x60607e7e,
|
||||
|
||||
0x61014101, // a
|
||||
0x62024202,
|
||||
0x63034303,
|
||||
0x64044404,
|
||||
0x65054505,
|
||||
0x66064606,
|
||||
0x67074707,
|
||||
0x68084808,
|
||||
0x69094909,
|
||||
0x6a0a4a0a,
|
||||
0x6b0b4b0b,
|
||||
0x6c0c4c0c,
|
||||
0x6d0d4d0d,
|
||||
0x6e0e4e0e,
|
||||
0x6f0f4f0f,
|
||||
0x70105010,
|
||||
0x71115111,
|
||||
0x72125212,
|
||||
0x73135313,
|
||||
0x74145414,
|
||||
0x75155515,
|
||||
0x76165616,
|
||||
0x77175717,
|
||||
0x78185818,
|
||||
0x79195919,
|
||||
0x7a1a5a1a, // z
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="key">0 - 55</param>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="shift"></param>
|
||||
/// <returns></returns>
|
||||
private static int KeyToAscii(int key, bool control, bool shift)
|
||||
{
|
||||
int s = control ? (shift ? 0 : 16) : (shift ? 8 : 24);
|
||||
return (int)(KeyAsciiData[key] >> s);
|
||||
}
|
||||
|
||||
private static Dictionary<string, Keys> DescriptionsToKeys = new Dictionary<string, Keys>();
|
||||
|
||||
static Keyboard()
|
||||
{
|
||||
for (int i = 0; i < 62; i++)
|
||||
{
|
||||
// http://stackoverflow.com/questions/2650080/how-to-get-c-sharp-enum-description-from-value
|
||||
Keys value = (Keys)(1UL << i);
|
||||
var fi = typeof(Keys).GetField(value.ToString());
|
||||
var attr = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
string name = attr[0].Description;
|
||||
DescriptionsToKeys[name] = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetKeyNames()
|
||||
{
|
||||
return DescriptionsToKeys.Keys.ToList();
|
||||
}
|
||||
|
||||
private static Keys FromStrings(IEnumerable<string> keynames)
|
||||
{
|
||||
Keys ret = 0;
|
||||
foreach (string s in keynames)
|
||||
{
|
||||
ret |= DescriptionsToKeys[s];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Keyboard() { }
|
||||
public Keyboard(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_keyboardService = Machine.Services.GetService<KeyboardService>();
|
||||
|
||||
UseGamePort = true; // Raster Blaster
|
||||
Button2Key = ' ';
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
/// <summary>
|
||||
/// Call this at 60hz with all of the currently pressed keys
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
public void SetKeys(IEnumerable<string> keynames)
|
||||
{
|
||||
Keys keys = FromStrings(keynames);
|
||||
|
||||
DisableResetKey = reader.ReadBoolean();
|
||||
if (keys.HasFlag(Keys.WhiteApple)) { } // TODO: set GAME1
|
||||
if (keys.HasFlag(Keys.BlackApple)) { } // TODO: set GAME2
|
||||
|
||||
UseGamePort = reader.ReadBoolean();
|
||||
Joystick0UpLeftKey = reader.ReadInt32();
|
||||
Joystick0UpKey = reader.ReadInt32();
|
||||
Joystick0UpRightKey = reader.ReadInt32();
|
||||
Joystick0LeftKey = reader.ReadInt32();
|
||||
Joystick0RightKey = reader.ReadInt32();
|
||||
Joystick0DownLeftKey = reader.ReadInt32();
|
||||
Joystick0DownKey = reader.ReadInt32();
|
||||
Joystick0DownRightKey = reader.ReadInt32();
|
||||
Joystick1UpLeftKey = reader.ReadInt32();
|
||||
Joystick1UpKey = reader.ReadInt32();
|
||||
Joystick1UpRightKey = reader.ReadInt32();
|
||||
Joystick1LeftKey = reader.ReadInt32();
|
||||
Joystick1RightKey = reader.ReadInt32();
|
||||
Joystick1DownLeftKey = reader.ReadInt32();
|
||||
Joystick1DownKey = reader.ReadInt32();
|
||||
Joystick1DownRightKey = reader.ReadInt32();
|
||||
Button0Key = reader.ReadUInt64();
|
||||
Button1Key = reader.ReadInt32();
|
||||
Button2Key = reader.ReadInt32();
|
||||
}
|
||||
if (keys.HasFlag(Keys.Reset) && keys.HasFlag(Keys.Control)) { } // TODO: reset console
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
bool control = keys.HasFlag(Keys.Control);
|
||||
bool shift = keys.HasFlag(Keys.Shift);
|
||||
|
||||
writer.Write(DisableResetKey);
|
||||
bool caps = keys.HasFlag(Keys.CapsLock);
|
||||
if (caps && !CurrentCapsLockState) // leading edge: toggle capslock
|
||||
{
|
||||
CapsActive ^= true;
|
||||
}
|
||||
CurrentCapsLockState = caps;
|
||||
shift ^= CapsActive;
|
||||
|
||||
// work with only the first 56 real keys
|
||||
long k = (long)keys & 0xffffffffffffffL;
|
||||
|
||||
IsAnyKeyDown = k != 0;
|
||||
|
||||
if (!IsAnyKeyDown)
|
||||
{
|
||||
CurrentKeyPressed = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: on real hardware, multiple keys pressed in physical would cause a conflict
|
||||
// that would be somehow resolved by the scan pattern. we don't emulate that.
|
||||
|
||||
// instead, just arbitrarily choose the lowest key in our list
|
||||
|
||||
// BSF
|
||||
int NewKeyPressed = 0;
|
||||
while ((k & 1) == 0)
|
||||
{
|
||||
k >>= 1;
|
||||
NewKeyPressed++;
|
||||
}
|
||||
|
||||
if (NewKeyPressed != CurrentKeyPressed)
|
||||
{
|
||||
// strobe, start new repeat cycle
|
||||
Strobe = true;
|
||||
Latch = KeyToAscii(NewKeyPressed, control, shift);
|
||||
FramesToRepeat = KeyRepeatStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check for repeat
|
||||
FramesToRepeat--;
|
||||
if (FramesToRepeat == 0)
|
||||
{
|
||||
Strobe = true;
|
||||
Latch = KeyToAscii(NewKeyPressed, control, shift);
|
||||
FramesToRepeat = KeyRepeatRate;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentKeyPressed = NewKeyPressed;
|
||||
}
|
||||
|
||||
writer.Write(UseGamePort);
|
||||
writer.Write(Joystick0UpLeftKey);
|
||||
writer.Write(Joystick0UpKey);
|
||||
writer.Write(Joystick0UpRightKey);
|
||||
writer.Write(Joystick0LeftKey);
|
||||
writer.Write(Joystick0RightKey);
|
||||
writer.Write(Joystick0DownLeftKey);
|
||||
writer.Write(Joystick0DownKey);
|
||||
writer.Write(Joystick0DownRightKey);
|
||||
writer.Write(Joystick1UpLeftKey);
|
||||
writer.Write(Joystick1UpKey);
|
||||
writer.Write(Joystick1UpRightKey);
|
||||
writer.Write(Joystick1LeftKey);
|
||||
writer.Write(Joystick1RightKey);
|
||||
writer.Write(Joystick1DownLeftKey);
|
||||
writer.Write(Joystick1DownKey);
|
||||
writer.Write(Joystick1DownRightKey);
|
||||
writer.Write(Button0Key);
|
||||
writer.Write(Button1Key);
|
||||
writer.Write(Button2Key);
|
||||
}
|
||||
|
||||
public void ResetStrobe()
|
||||
{
|
||||
Strobe = false;
|
||||
}
|
||||
|
||||
public bool DisableResetKey { get; set; }
|
||||
|
||||
public bool UseGamePort { get; set; }
|
||||
public int Joystick0UpLeftKey { get; set; }
|
||||
public int Joystick0UpKey { get; set; }
|
||||
public int Joystick0UpRightKey { get; set; }
|
||||
public int Joystick0LeftKey { get; set; }
|
||||
public int Joystick0RightKey { get; set; }
|
||||
public int Joystick0DownLeftKey { get; set; }
|
||||
public int Joystick0DownKey { get; set; }
|
||||
public int Joystick0DownRightKey { get; set; }
|
||||
public int Joystick1UpLeftKey { get; set; }
|
||||
public int Joystick1UpKey { get; set; }
|
||||
public int Joystick1UpRightKey { get; set; }
|
||||
public int Joystick1LeftKey { get; set; }
|
||||
public int Joystick1RightKey { get; set; }
|
||||
public int Joystick1DownLeftKey { get; set; }
|
||||
public int Joystick1DownKey { get; set; }
|
||||
public int Joystick1DownRightKey { get; set; }
|
||||
public ulong Button0Key { get; set; }
|
||||
public int Button1Key { get; set; }
|
||||
public int Button2Key { get; set; }
|
||||
|
||||
public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } }
|
||||
public bool IsShiftKeyDown { get { return _keyboardService.IsShiftKeyDown; } }
|
||||
public bool IsControlKeyDown { get { return _keyboardService.IsControlKeyDown; } }
|
||||
public int Latch { get { return _latch; } set { _latch = value; Strobe = true; } }
|
||||
|
||||
/// <summary>
|
||||
/// true if any of the 56 basic keys are pressed
|
||||
/// </summary>
|
||||
public bool IsAnyKeyDown { get; private set; }
|
||||
/// <summary>
|
||||
/// the currently latched key; 7 bits.
|
||||
/// </summary>
|
||||
public int Latch { get; private set; }
|
||||
public bool Strobe { get; private set; }
|
||||
|
||||
private KeyboardService _keyboardService;
|
||||
/// <summary>
|
||||
/// true if caps lock is active
|
||||
/// </summary>
|
||||
public bool CapsActive { get; private set; }
|
||||
|
||||
private int _latch;
|
||||
private bool CurrentCapsLockState;
|
||||
|
||||
/// <summary>
|
||||
/// 0-55, -1 = none
|
||||
/// </summary>
|
||||
private int CurrentKeyPressed;
|
||||
|
||||
private int FramesToRepeat;
|
||||
|
||||
private const int KeyRepeatRate = 6; // 10hz
|
||||
private const int KeyRepeatStart = 40; // ~666ms?
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,391 +1,190 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Jellyfish.Virtu.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
public enum MachineState { Stopped = 0, Starting, Running, Pausing, Paused, Stopping }
|
||||
|
||||
public enum Buttons : ulong
|
||||
{
|
||||
Up = 0x0000000000001,
|
||||
Down = 0x0000000000002,
|
||||
Left = 0x0000000000004,
|
||||
Right = 0x0000000000008,
|
||||
Tab = 0x0000000000010,
|
||||
Enter = 0x0000000000020,
|
||||
Escape = 0x0000000000040,
|
||||
Back = 0x0000000000080,
|
||||
Space = 0x0000000000100,
|
||||
Ctrl = 0x0000000000200,
|
||||
Shift = 0x0000000000400,
|
||||
Caps = 0x0000000000800,
|
||||
Key1 = 0x0000000001000,
|
||||
Key2 = 0x0000000002000,
|
||||
Key3 = 0x0000000004000,
|
||||
Key4 = 0x0000000008000,
|
||||
Key5 = 0x0000000010000,
|
||||
Key6 = 0x0000000020000,
|
||||
Key7 = 0x0000000040000,
|
||||
Key8 = 0x0000000080000,
|
||||
Key9 = 0x0000000100000,
|
||||
Key0 = 0x0000000200000,
|
||||
KeyA = 0x0000001000000,
|
||||
KeyB = 0x0000002000000,
|
||||
KeyC = 0x0000004000000,
|
||||
KeyD = 0x0000008000000,
|
||||
KeyE = 0x0000010000000,
|
||||
KeyF = 0x0000020000000,
|
||||
KeyG = 0x0000040000000,
|
||||
KeyH = 0x0000080000000,
|
||||
KeyI = 0x0000100000000,
|
||||
KeyJ = 0x0000200000000,
|
||||
KeyK = 0x0000400000000,
|
||||
KeyL = 0x0000800000000,
|
||||
KeyM = 0x0001000000000,
|
||||
KeyN = 0x0002000000000,
|
||||
KeyO = 0x0004000000000,
|
||||
KeyP = 0x0008000000000,
|
||||
KeyQ = 0x0010000000000,
|
||||
KeyR = 0x0020000000000,
|
||||
KeyS = 0x0040000000000,
|
||||
KeyT = 0x0080000000000,
|
||||
KeyU = 0x0100000000000,
|
||||
KeyV = 0x0200000000000,
|
||||
KeyW = 0x0400000000000,
|
||||
KeyX = 0x0800000000000,
|
||||
KeyY = 0x1000000000000,
|
||||
KeyZ = 0x2000000000000
|
||||
}
|
||||
|
||||
public sealed class Machine : IDisposable
|
||||
{
|
||||
public Machine(byte[] appleIIe, byte[] diskIIRom)
|
||||
{
|
||||
public sealed class Machine : IDisposable
|
||||
{
|
||||
public Machine(byte[] appleIIe, byte[] diskIIRom)
|
||||
{
|
||||
Events = new MachineEvents();
|
||||
Services = new MachineServices();
|
||||
|
||||
Cpu = new Cpu(this);
|
||||
Memory = new Memory(this, appleIIe);
|
||||
Keyboard = new Keyboard(this);
|
||||
GamePort = new GamePort(this);
|
||||
Cassette = new Cassette(this);
|
||||
Speaker = new Speaker(this);
|
||||
Video = new Video(this);
|
||||
NoSlotClock = new NoSlotClock(this);
|
||||
Cpu = new Cpu(this);
|
||||
Memory = new Memory(this, appleIIe);
|
||||
Keyboard = new Keyboard(this);
|
||||
GamePort = new GamePort(this);
|
||||
Cassette = new Cassette(this);
|
||||
Speaker = new Speaker(this);
|
||||
Video = new Video(this);
|
||||
NoSlotClock = new NoSlotClock(this);
|
||||
|
||||
var emptySlot = new PeripheralCard(this);
|
||||
Slot1 = emptySlot;
|
||||
Slot2 = emptySlot;
|
||||
Slot3 = emptySlot;
|
||||
Slot4 = emptySlot;
|
||||
Slot5 = emptySlot;
|
||||
Slot6 = new DiskIIController(this, diskIIRom);
|
||||
Slot7 = emptySlot;
|
||||
var emptySlot = new PeripheralCard(this);
|
||||
Slot1 = emptySlot;
|
||||
Slot2 = emptySlot;
|
||||
Slot3 = emptySlot;
|
||||
Slot4 = emptySlot;
|
||||
Slot5 = emptySlot;
|
||||
Slot6 = new DiskIIController(this, diskIIRom);
|
||||
Slot7 = emptySlot;
|
||||
|
||||
Slots = new Collection<PeripheralCard> { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
Components = new Collection<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
Slots = new List<PeripheralCard> { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
Components = new List<MachineComponent> { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 };
|
||||
|
||||
BootDiskII = Slots.OfType<DiskIIController>().Last();
|
||||
BootDiskII = Slots.OfType<DiskIIController>().Last();
|
||||
}
|
||||
|
||||
//Thread = new Thread(Run) { Name = "Machine" };
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pauseEvent.Close();
|
||||
_unpauseEvent.Close();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Resetting machine '{0}'", component.GetType().Name);
|
||||
component.Reset();
|
||||
//_debugService.WriteMessage("Reset machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
//[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
|
||||
//public void Start()
|
||||
//{
|
||||
// _debugService = Services.GetService<DebugService>();
|
||||
// _storageService = Services.GetService<StorageService>();
|
||||
|
||||
// _debugService.WriteMessage("Starting machine");
|
||||
// State = MachineState.Starting;
|
||||
// Thread.Start();
|
||||
//}
|
||||
|
||||
//[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
|
||||
//public void Pause()
|
||||
//{
|
||||
// _debugService.WriteMessage("Pausing machine");
|
||||
// State = MachineState.Pausing;
|
||||
// _pauseEvent.WaitOne();
|
||||
// State = MachineState.Paused;
|
||||
// _debugService.WriteMessage("Paused machine");
|
||||
//}
|
||||
|
||||
//[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
|
||||
//public void Unpause()
|
||||
//{
|
||||
// _debugService.WriteMessage("Running machine");
|
||||
// State = MachineState.Running;
|
||||
// _unpauseEvent.Set();
|
||||
//}
|
||||
|
||||
//[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
|
||||
//public void Stop()
|
||||
//{
|
||||
// _debugService.WriteMessage("Stopping machine");
|
||||
// State = MachineState.Stopping;
|
||||
// _unpauseEvent.Set();
|
||||
// if (Thread.IsAlive)
|
||||
// {
|
||||
// Thread.Join();
|
||||
// }
|
||||
// State = MachineState.Stopped;
|
||||
// _debugService.WriteMessage("Stopped machine");
|
||||
//}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Initializing machine '{0}'", component.GetType().Name);
|
||||
component.Initialize();
|
||||
//_debugService.WriteMessage("Initialized machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadState()
|
||||
{
|
||||
#if WINDOWS
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
if (args.Length > 1)
|
||||
{
|
||||
string name = args[1];
|
||||
Func<string, Action<Stream>, bool> loader = StorageService.LoadFile;
|
||||
|
||||
if (name.StartsWith("res://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
name = name.Substring(6);
|
||||
loader = StorageService.LoadResource;
|
||||
}
|
||||
|
||||
if (name.EndsWith(".bin", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loader(name, stream => LoadState(stream));
|
||||
}
|
||||
else if (name.EndsWith(".prg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loader(name, stream => Memory.LoadPrg(stream));
|
||||
}
|
||||
else if (name.EndsWith(".xex", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
loader(name, stream => Memory.LoadXex(stream));
|
||||
}
|
||||
else
|
||||
{
|
||||
loader(name, stream => BootDiskII.BootDrive.InsertDisk(name, stream, false));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!_storageService.Load(Machine.StateFileName, stream => LoadState(stream)))
|
||||
{
|
||||
StorageService.LoadResource("Disks/Default.dsk", stream => BootDiskII.BootDrive.InsertDisk("Default.dsk", stream, false));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: don't copy paste
|
||||
public void LoadState(BinaryReader reader)
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
string signature = reader.ReadString();
|
||||
var version = new Version(reader.ReadString());
|
||||
if ((signature != StateSignature) || (version != new Version(Machine.Version))) // avoid state version mismatch (for now)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Loading machine '{0}'", component.GetType().Name);
|
||||
component.LoadState(reader, version);
|
||||
//_debugService.WriteMessage("Loaded machine '{0}'", component.GetType().Name);
|
||||
DebugService.WriteMessage("Resetting machine '{0}'", component.GetType().Name);
|
||||
component.Reset();
|
||||
//DebugService.WriteMessage("Reset machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadState(Stream stream)
|
||||
{
|
||||
using (var reader = new BinaryReader(stream))
|
||||
{
|
||||
string signature = reader.ReadString();
|
||||
var version = new Version(reader.ReadString());
|
||||
if ((signature != StateSignature) || (version != new Version(Machine.Version))) // avoid state version mismatch (for now)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Loading machine '{0}'", component.GetType().Name);
|
||||
component.LoadState(reader, version);
|
||||
//_debugService.WriteMessage("Loaded machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveState()
|
||||
{
|
||||
_storageService.Save(Machine.StateFileName, stream => SaveState(stream));
|
||||
}
|
||||
|
||||
public void SaveState(BinaryWriter writer)
|
||||
private void Initialize()
|
||||
{
|
||||
writer.Write(StateSignature);
|
||||
writer.Write(Machine.Version);
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Saving machine '{0}'", component.GetType().Name);
|
||||
component.SaveState(writer);
|
||||
//_debugService.WriteMessage("Saved machine '{0}'", component.GetType().Name);
|
||||
DebugService.WriteMessage("Initializing machine '{0}'", component.GetType().Name);
|
||||
component.Initialize();
|
||||
//DebugService.WriteMessage("Initialized machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveState(Stream stream)
|
||||
{
|
||||
using (var writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write(StateSignature);
|
||||
writer.Write(Machine.Version);
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Saving machine '{0}'", component.GetType().Name);
|
||||
component.SaveState(writer);
|
||||
//_debugService.WriteMessage("Saved machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Uninitialize()
|
||||
{
|
||||
foreach (var component in Components)
|
||||
{
|
||||
DebugService.WriteMessage("Uninitializing machine '{0}'", component.GetType().Name);
|
||||
component.Uninitialize();
|
||||
//DebugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void Uninitialize()
|
||||
{
|
||||
foreach (var component in Components)
|
||||
{
|
||||
_debugService.WriteMessage("Uninitializing machine '{0}'", component.GetType().Name);
|
||||
component.Uninitialize();
|
||||
//_debugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
//[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")]
|
||||
//private void Run() // machine thread
|
||||
//{
|
||||
// Initialize();
|
||||
// Reset();
|
||||
// LoadState();
|
||||
//
|
||||
// _debugService.WriteMessage("Running machine");
|
||||
// State = MachineState.Running;
|
||||
// do
|
||||
// {
|
||||
// do
|
||||
// {
|
||||
// Events.HandleEvents(Cpu.Execute());
|
||||
// }
|
||||
// while (State == MachineState.Running);
|
||||
//
|
||||
// if (State == MachineState.Pausing)
|
||||
// {
|
||||
// _pauseEvent.Set();
|
||||
// _unpauseEvent.WaitOne();
|
||||
// }
|
||||
// }
|
||||
// while (State != MachineState.Stopping);
|
||||
//
|
||||
// SaveState();
|
||||
// Uninitialize();
|
||||
//}
|
||||
public void BizInitialize()
|
||||
{
|
||||
Initialize();
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void BizInitialize()
|
||||
{
|
||||
_debugService = Services.GetService<DebugService>();
|
||||
_storageService = Services.GetService<StorageService>();
|
||||
public void BizFrameAdvance(IEnumerable<string> buttons)
|
||||
{
|
||||
Lagged = true;
|
||||
|
||||
Initialize();
|
||||
Reset();
|
||||
}
|
||||
Keyboard.SetKeys(buttons);
|
||||
|
||||
public void BizNewDisk()
|
||||
{
|
||||
_storageService = Services.GetService<StorageService>();
|
||||
}
|
||||
//frame begins at vsync.. beginning of vblank
|
||||
while (Video.IsVBlank)
|
||||
{
|
||||
/*
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendFormat("{0} ", Cpu);
|
||||
for (int i = 0; i < 256; i++)
|
||||
sb.AppendFormat("{0:x2} ", Memory.Read(i));
|
||||
tw.WriteLine(sb.ToString());*/
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
}
|
||||
//now, while not vblank, we're in a frame
|
||||
while (!Video.IsVBlank)
|
||||
{
|
||||
/*
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendFormat("{0} ", Cpu);
|
||||
for (int i = 0; i < 256; i++)
|
||||
sb.AppendFormat("{0:x2} ", Memory.Read(i));
|
||||
tw.WriteLine(sb.ToString()); */
|
||||
|
||||
public void BizFrameAdvance()
|
||||
{
|
||||
Lagged = true;
|
||||
Services.GetService<KeyboardService>().Update();
|
||||
Services.GetService<GamePortService>().Update();
|
||||
//frame begins at vsync.. beginning of vblank
|
||||
while (Video.IsVBlank)
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
//now, while not vblank, we're in a frame
|
||||
while (!Video.IsVBlank)
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
|
||||
}
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
}
|
||||
}
|
||||
|
||||
public void BizShutdown()
|
||||
{
|
||||
Uninitialize();
|
||||
}
|
||||
public void BizShutdown()
|
||||
{
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
public const string Version = "0.9.4.0";
|
||||
private static JsonSerializer CreateSerializer()
|
||||
{
|
||||
var ser = new JsonSerializer
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.All, // leaving out Array is a very important problem, and means that we can't rely on a directly shared array to work.
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
|
||||
};
|
||||
|
||||
public MachineEvents Events { get; private set; }
|
||||
public MachineServices Services { get; private set; }
|
||||
public MachineState State { get { return _state; } private set { _state = value; } }
|
||||
ser.Converters.Add(new DelegateConverter());
|
||||
ser.Converters.Add(new ArrayConverter());
|
||||
var cr = new DefaultContractResolver();
|
||||
cr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic;
|
||||
ser.ContractResolver = cr;
|
||||
|
||||
public Cpu Cpu { get; private set; }
|
||||
public Memory Memory { get; private set; }
|
||||
public Keyboard Keyboard { get; private set; }
|
||||
public GamePort GamePort { get; private set; }
|
||||
public Cassette Cassette { get; private set; }
|
||||
public Speaker Speaker { get; private set; }
|
||||
public Video Video { get; private set; }
|
||||
public NoSlotClock NoSlotClock { get; private set; }
|
||||
return ser;
|
||||
}
|
||||
|
||||
public PeripheralCard Slot1 { get; private set; }
|
||||
public PeripheralCard Slot2 { get; private set; }
|
||||
public PeripheralCard Slot3 { get; private set; }
|
||||
public PeripheralCard Slot4 { get; private set; }
|
||||
public PeripheralCard Slot5 { get; private set; }
|
||||
public PeripheralCard Slot6 { get; private set; }
|
||||
public PeripheralCard Slot7 { get; private set; }
|
||||
public void Serialize(JsonWriter w)
|
||||
{
|
||||
CreateSerializer().Serialize(w, this);
|
||||
}
|
||||
|
||||
public Collection<PeripheralCard> Slots { get; private set; }
|
||||
public Collection<MachineComponent> Components { get; private set; }
|
||||
public static Machine Deserialize(JsonReader r)
|
||||
{
|
||||
var ret = CreateSerializer().Deserialize<Machine>(r);
|
||||
|
||||
// for some unknown reason, these particular references get nuked by JSON.NET on deserializating
|
||||
foreach (var c in ret.Components)
|
||||
{
|
||||
c.Machine = ret;
|
||||
}
|
||||
ret.BootDiskII.Drive1.Machine = ret;
|
||||
ret.BootDiskII.Drive2.Machine = ret;
|
||||
|
||||
public DiskIIController BootDiskII { get; private set; }
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Thread Thread { get; private set; }
|
||||
public const string Version = "0.9.4.0";
|
||||
|
||||
public Buttons Buttons;
|
||||
public MachineEvents Events { get; private set; }
|
||||
|
||||
private const string StateFileName = "State.bin";
|
||||
private const string StateSignature = "Virtu";
|
||||
public Cpu Cpu { get; private set; }
|
||||
public Memory Memory { get; private set; }
|
||||
public Keyboard Keyboard { get; private set; }
|
||||
public GamePort GamePort { get; private set; }
|
||||
public Cassette Cassette { get; private set; }
|
||||
public Speaker Speaker { get; private set; }
|
||||
public Video Video { get; private set; }
|
||||
public NoSlotClock NoSlotClock { get; private set; }
|
||||
|
||||
private DebugService _debugService;
|
||||
private StorageService _storageService;
|
||||
private volatile MachineState _state;
|
||||
public PeripheralCard Slot1 { get; private set; }
|
||||
public PeripheralCard Slot2 { get; private set; }
|
||||
public PeripheralCard Slot3 { get; private set; }
|
||||
public PeripheralCard Slot4 { get; private set; }
|
||||
public PeripheralCard Slot5 { get; private set; }
|
||||
public PeripheralCard Slot6 { get; private set; }
|
||||
public PeripheralCard Slot7 { get; private set; }
|
||||
|
||||
private AutoResetEvent _pauseEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _unpauseEvent = new AutoResetEvent(false);
|
||||
public IList<PeripheralCard> Slots { get; private set; }
|
||||
public IList<MachineComponent> Components { get; private set; }
|
||||
|
||||
public DiskIIController BootDiskII { get; private set; }
|
||||
|
||||
public bool Lagged { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,10 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public abstract class MachineComponent
|
||||
{
|
||||
public MachineComponent() { }
|
||||
protected MachineComponent(Machine machine)
|
||||
{
|
||||
Machine = machine;
|
||||
|
||||
_debugService = new Lazy<DebugService>(() => Machine.Services.GetService<DebugService>());
|
||||
_machine = machine;
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
|
@ -22,21 +21,17 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
}
|
||||
|
||||
public virtual void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void SaveState(BinaryWriter writer)
|
||||
{
|
||||
}
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
private Machine _machine;
|
||||
|
||||
protected Machine Machine { get; private set; }
|
||||
protected DebugService DebugService { get { return _debugService.Value; } }
|
||||
|
||||
private Lazy<DebugService> _debugService;
|
||||
public Machine Machine
|
||||
{
|
||||
get { return _machine; }
|
||||
set { _machine = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
|
@ -25,6 +26,8 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public void AddEvent(int delta, Action action)
|
||||
{
|
||||
//Console.WriteLine("+{0} @ {1}", action.Method.Name, delta);
|
||||
|
||||
var node = _used.First;
|
||||
for (; node != null; node = node.Next)
|
||||
{
|
||||
|
@ -68,23 +71,37 @@ namespace Jellyfish.Virtu
|
|||
for (var node = _used.First; node != null; node = node.Next)
|
||||
{
|
||||
delta += node.Value.Delta;
|
||||
if (object.ReferenceEquals(node.Value.Action, action)) // assumes delegate cached
|
||||
{
|
||||
return delta;
|
||||
}
|
||||
|
||||
var other = node.Value.Action;
|
||||
|
||||
if (other.Method == action.Method && other.Target == action.Target)
|
||||
{
|
||||
//Console.WriteLine("={0} @ {1}", action.Method.Name, delta);
|
||||
return delta;
|
||||
}
|
||||
|
||||
// our delegate serializer doesn't preserve reference equality
|
||||
//if (object.ReferenceEquals(node.Value.Action, action)) // assumes delegate cached
|
||||
//{
|
||||
// return delta;
|
||||
//}
|
||||
}
|
||||
|
||||
return 0;
|
||||
//Console.WriteLine("=???? @ 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void HandleEvents(int delta)
|
||||
{
|
||||
//Console.WriteLine("[{0}]", delta);
|
||||
|
||||
var node = _used.First;
|
||||
node.Value.Delta -= delta;
|
||||
|
||||
while (node.Value.Delta <= 0)
|
||||
{
|
||||
node.Value.Action();
|
||||
//Console.WriteLine("!{0} @ {1}", node.Value.Action.Method.Name, node.Value.Delta);
|
||||
node.Value.Action();
|
||||
RemoveEvent(node);
|
||||
node = _used.First;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
public sealed partial class Memory : MachineComponent
|
||||
{
|
||||
public Memory() { }
|
||||
public Memory(Machine machine, byte[] appleIIe) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -89,7 +90,7 @@ namespace Jellyfish.Virtu
|
|||
_writeRomRegionD0FF = WriteRomRegionD0FF;
|
||||
}
|
||||
|
||||
private readonly byte[] _appleIIe;
|
||||
private byte[] _appleIIe;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
@ -138,55 +139,6 @@ namespace Jellyfish.Virtu
|
|||
MapRegionD0FF();
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
_state = reader.ReadInt32();
|
||||
_slotRegionC8CF = reader.ReadInt32();
|
||||
|
||||
reader.Read(_ramMainRegion0001, 0, _ramMainRegion0001.Length);
|
||||
reader.Read(_ramMainRegion02BF, 0, _ramMainRegion02BF.Length);
|
||||
reader.Read(_ramMainBank1RegionD0DF, 0, _ramMainBank1RegionD0DF.Length);
|
||||
reader.Read(_ramMainBank2RegionD0DF, 0, _ramMainBank2RegionD0DF.Length);
|
||||
reader.Read(_ramMainRegionE0FF, 0, _ramMainRegionE0FF.Length);
|
||||
reader.Read(_ramAuxRegion0001, 0, _ramAuxRegion0001.Length);
|
||||
reader.Read(_ramAuxRegion02BF, 0, _ramAuxRegion02BF.Length);
|
||||
reader.Read(_ramAuxBank1RegionD0DF, 0, _ramAuxBank1RegionD0DF.Length);
|
||||
reader.Read(_ramAuxBank2RegionD0DF, 0, _ramAuxBank2RegionD0DF.Length);
|
||||
reader.Read(_ramAuxRegionE0FF, 0, _ramAuxRegionE0FF.Length);
|
||||
|
||||
MapRegion0001();
|
||||
MapRegion02BF();
|
||||
MapRegionC0CF();
|
||||
MapRegionD0FF();
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(_state);
|
||||
writer.Write(_slotRegionC8CF);
|
||||
|
||||
writer.Write(_ramMainRegion0001);
|
||||
writer.Write(_ramMainRegion02BF);
|
||||
writer.Write(_ramMainBank1RegionD0DF);
|
||||
writer.Write(_ramMainBank2RegionD0DF);
|
||||
writer.Write(_ramMainRegionE0FF);
|
||||
writer.Write(_ramAuxRegion0001);
|
||||
writer.Write(_ramAuxRegion02BF);
|
||||
writer.Write(_ramAuxBank1RegionD0DF);
|
||||
writer.Write(_ramAuxBank2RegionD0DF);
|
||||
writer.Write(_ramAuxRegionE0FF);
|
||||
}
|
||||
|
||||
public void LoadPrg(Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
|
@ -282,8 +234,6 @@ namespace Jellyfish.Virtu
|
|||
return _video.ReadFloatingBus();
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")]
|
||||
private int ReadIoRegionC0C0(int address)
|
||||
{
|
||||
Machine.Lagged = false;
|
||||
|
|
|
@ -101,6 +101,6 @@ namespace Jellyfish.Virtu
|
|||
Video.ModeC, Video.ModeD, Video.Mode1, Video.Mode2, Video.ModeE, Video.ModeF, Video.Mode1, Video.Mode2
|
||||
};
|
||||
|
||||
private readonly Action<int, byte>[][][] WriteRamModeBankRegion;
|
||||
private Action<int, byte>[][][] WriteRamModeBankRegion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed class NoSlotClock : MachineComponent
|
||||
{
|
||||
public NoSlotClock() { }
|
||||
public NoSlotClock(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -18,34 +19,6 @@ namespace Jellyfish.Virtu
|
|||
_comparisonRegister = new RingRegister(ClockInitSequence, 0x1);
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
_clockEnabled = reader.ReadBoolean();
|
||||
_writeEnabled = reader.ReadBoolean();
|
||||
_clockRegister = new RingRegister(reader.ReadUInt64(), reader.ReadUInt64());
|
||||
_comparisonRegister = new RingRegister(reader.ReadUInt64(), reader.ReadUInt64());
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(_clockEnabled);
|
||||
writer.Write(_writeEnabled);
|
||||
writer.Write(_clockRegister.Data);
|
||||
writer.Write(_clockRegister.Mask);
|
||||
writer.Write(_comparisonRegister.Data);
|
||||
writer.Write(_comparisonRegister.Mask);
|
||||
}
|
||||
|
||||
public int Read(int address, int data)
|
||||
{
|
||||
// this may read or write the clock
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
{
|
||||
public class PeripheralCard : MachineComponent
|
||||
{
|
||||
public PeripheralCard() { }
|
||||
public PeripheralCard(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
|
|
|
@ -5,12 +5,12 @@ using Jellyfish.Library;
|
|||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class AudioService : MachineService
|
||||
/// <summary>
|
||||
/// this isn't really a "service" anymore, just a helper for the speaker class
|
||||
/// </summary>
|
||||
public class AudioService
|
||||
{
|
||||
protected AudioService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
public AudioService() { }
|
||||
|
||||
public void Output(int data) // machine thread
|
||||
{
|
||||
|
@ -25,21 +25,16 @@ namespace Jellyfish.Virtu.Services
|
|||
private short[] buff = new short[4096];
|
||||
private int pos = 0;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
public void Clear()
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
public abstract void SetVolume(float volume);
|
||||
|
||||
}
|
||||
|
||||
public void GetSamples(out short[] samples, out int nsamp)
|
||||
{
|
||||
samples = buff;
|
||||
nsamp = pos / 2;
|
||||
pos = 0;
|
||||
|
||||
Console.WriteLine(nsamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,22 @@ using Jellyfish.Library;
|
|||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public class DebugService : MachineService
|
||||
/// <summary>
|
||||
/// this isn't really a "service" anymore
|
||||
/// </summary>
|
||||
public static class DebugService
|
||||
{
|
||||
public DebugService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public void WriteMessage(string message)
|
||||
public static void WriteMessage(string message)
|
||||
{
|
||||
OnWriteMessage(FormatMessage(message));
|
||||
}
|
||||
|
||||
public void WriteMessage(string format, params object[] args)
|
||||
public static void WriteMessage(string format, params object[] args)
|
||||
{
|
||||
OnWriteMessage(FormatMessage(format, args));
|
||||
}
|
||||
|
||||
protected virtual void OnWriteMessage(string message)
|
||||
private static void OnWriteMessage(string message)
|
||||
{
|
||||
#if SILVERLIGHT
|
||||
Debug.WriteLine(message);
|
||||
|
@ -33,7 +31,7 @@ namespace Jellyfish.Virtu.Services
|
|||
#endif
|
||||
}
|
||||
|
||||
private string FormatMessage(string format, params object[] args)
|
||||
private static string FormatMessage(string format, params object[] args)
|
||||
{
|
||||
var message = new StringBuilder(256);
|
||||
message.AppendFormat(CultureInfo.InvariantCulture, "[{0} T{1:X3} Virtu] ", DateTime.Now.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture), Thread.CurrentThread.ManagedThreadId);
|
||||
|
@ -55,9 +53,5 @@ namespace Jellyfish.Virtu.Services
|
|||
|
||||
return message.ToString();
|
||||
}
|
||||
|
||||
public static DebugService Default { get { return _default.Value; } }
|
||||
|
||||
private static readonly Lazy<DebugService> _default = new Lazy<DebugService>(() => new DebugService(null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,333 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public class GamePortService : MachineService
|
||||
{
|
||||
public GamePortService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected
|
||||
}
|
||||
|
||||
public virtual void Update() // main thread
|
||||
{
|
||||
var keyboard = Machine.Keyboard;
|
||||
|
||||
if (keyboard.UseGamePort)
|
||||
{
|
||||
//UpdateKey(keyboard.Joystick0UpKey, IsJoystick0Up, ref _isJoystick0UpKeyDown, ref _wasJoystick0UpKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0LeftKey, IsJoystick0Left, ref _isJoystick0LeftKeyDown, ref _wasJoystick0LeftKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0RightKey, IsJoystick0Right, ref _isJoystick0RightKeyDown, ref _wasJoystick0RightKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0DownKey, IsJoystick0Down, ref _isJoystick0DownKeyDown, ref _wasJoystick0DownKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0UpLeftKey, IsJoystick0Up && IsJoystick0Left, ref _isJoystick0UpLeftKeyDown, ref _wasJoystick0UpLeftKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0UpRightKey, IsJoystick0Up && IsJoystick0Right, ref _isJoystick0UpRightKeyDown, ref _wasJoystick0UpRightKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0DownLeftKey, IsJoystick0Down && IsJoystick0Left, ref _isJoystick0DownLeftKeyDown, ref _wasJoystick0DownLeftKeyDown);
|
||||
//UpdateKey(keyboard.Joystick0DownRightKey, IsJoystick0Down && IsJoystick0Right, ref _isJoystick0DownRightKeyDown, ref _wasJoystick0DownRightKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1UpKey, IsJoystick1Up, ref _isJoystick1UpKeyDown, ref _wasJoystick1UpKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1LeftKey, IsJoystick1Left, ref _isJoystick1LeftKeyDown, ref _wasJoystick1LeftKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1RightKey, IsJoystick1Right, ref _isJoystick1RightKeyDown, ref _wasJoystick1RightKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1DownKey, IsJoystick1Down, ref _isJoystick1DownKeyDown, ref _wasJoystick1DownKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1UpLeftKey, IsJoystick1Up && IsJoystick1Left, ref _isJoystick1UpLeftKeyDown, ref _wasJoystick1UpLeftKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1UpRightKey, IsJoystick1Up && IsJoystick1Right, ref _isJoystick1UpRightKeyDown, ref _wasJoystick1UpRightKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1DownLeftKey, IsJoystick1Down && IsJoystick1Left, ref _isJoystick1DownLeftKeyDown, ref _wasJoystick1DownLeftKeyDown);
|
||||
//UpdateKey(keyboard.Joystick1DownRightKey, IsJoystick1Down && IsJoystick1Right, ref _isJoystick1DownRightKeyDown, ref _wasJoystick1DownRightKeyDown);
|
||||
|
||||
//all the keys are going through this one thing atm
|
||||
UpdateKey(keyboard.Button0Key, IsButton0Down, ref _isButton0KeyDown, ref _wasButton0KeyDown);
|
||||
//UpdateKey(keyboard.Button1Key, IsButton1Down, ref _isButton1KeyDown, ref _wasButton1KeyDown);
|
||||
//UpdateKey(keyboard.Button2Key, IsButton2Down, ref _isButton2KeyDown, ref _wasButton2KeyDown);
|
||||
|
||||
|
||||
/*
|
||||
if (_lastKey > 0) // repeat last key
|
||||
{
|
||||
long time = DateTime.UtcNow.Ticks;
|
||||
if (time - _lastTime >= _repeatTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_repeatTime = RepeatSpeed;
|
||||
keyboard.Latch = GetAsciiKey((Buttons)_lastKey, Machine.Keyboard.IsControlKeyDown, Machine.Keyboard.IsShiftKeyDown, false);
|
||||
}
|
||||
}
|
||||
* */
|
||||
}
|
||||
}
|
||||
|
||||
//static int t = 0;
|
||||
|
||||
private void UpdateKey(ulong key, bool isActive, ref bool isKeyDown, ref bool wasKeyDown)
|
||||
{
|
||||
wasKeyDown = isKeyDown;
|
||||
isKeyDown = (key > 0);// && isActive;
|
||||
|
||||
if (isKeyDown != wasKeyDown)
|
||||
{
|
||||
if (isKeyDown)
|
||||
{
|
||||
_lastKey = key;
|
||||
_lastTime = DateTime.UtcNow.Ticks;
|
||||
_repeatTime = RepeatDelay;
|
||||
Machine.Keyboard.Latch = GetAsciiKey((Buttons)key, Machine.Keyboard.IsControlKeyDown, Machine.Keyboard.IsShiftKeyDown, false);
|
||||
}
|
||||
else if (key == _lastKey)
|
||||
{
|
||||
_lastKey = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static int GetAsciiKey(Buttons bizKey, bool bizCtrl, bool bizShift, bool bizCaps)
|
||||
{
|
||||
|
||||
bool control = bizCtrl;
|
||||
bool shift = bizShift;
|
||||
bool capsLock = bizCaps;
|
||||
|
||||
switch (bizKey)
|
||||
{
|
||||
case 0:
|
||||
return 0x00;
|
||||
case Buttons.Left:
|
||||
return 0x08;
|
||||
|
||||
case Buttons.Tab:
|
||||
return 0x09;
|
||||
|
||||
case Buttons.Down:
|
||||
return 0x0A;
|
||||
|
||||
case Buttons.Up:
|
||||
return 0x0B;
|
||||
|
||||
case Buttons.Enter:
|
||||
return 0x0D;
|
||||
|
||||
case Buttons.Right:
|
||||
return 0x15;
|
||||
|
||||
case Buttons.Escape:
|
||||
return 0x1B;
|
||||
|
||||
case Buttons.Back:
|
||||
return control ? -1 : 0x7F;
|
||||
|
||||
case Buttons.Space:
|
||||
return ' ';
|
||||
|
||||
case Buttons.Key1:
|
||||
return shift ? '!' : '1';
|
||||
|
||||
case Buttons.Key2:
|
||||
return control ? 0x00 : shift ? '@' : '2';
|
||||
|
||||
case Buttons.Key3:
|
||||
return shift ? '#' : '3';
|
||||
|
||||
case Buttons.Key4:
|
||||
return shift ? '$' : '4';
|
||||
|
||||
case Buttons.Key5:
|
||||
return shift ? '%' : '5';
|
||||
|
||||
case Buttons.Key6:
|
||||
return control ? 0x1E : shift ? '^' : '6';
|
||||
|
||||
case Buttons.Key7:
|
||||
return shift ? '&' : '7';
|
||||
|
||||
case Buttons.Key8:
|
||||
return shift ? '*' : '8';
|
||||
|
||||
case Buttons.Key9:
|
||||
return shift ? '(' : '9';
|
||||
|
||||
case Buttons.Key0:
|
||||
return shift ? ')' : '0';
|
||||
|
||||
case Buttons.KeyA:
|
||||
return control ? 0x01 : capsLock ? 'A' : 'a';
|
||||
|
||||
case Buttons.KeyB:
|
||||
return control ? 0x02 : capsLock ? 'B' : 'b';
|
||||
|
||||
case Buttons.KeyC:
|
||||
return control ? 0x03 : capsLock ? 'C' : 'c';
|
||||
|
||||
case Buttons.KeyD:
|
||||
return control ? 0x04 : capsLock ? 'D' : 'd';
|
||||
|
||||
case Buttons.KeyE:
|
||||
return control ? 0x05 : capsLock ? 'E' : 'e';
|
||||
|
||||
case Buttons.KeyF:
|
||||
return control ? 0x06 : capsLock ? 'F' : 'f';
|
||||
|
||||
case Buttons.KeyG:
|
||||
return control ? 0x07 : capsLock ? 'G' : 'g';
|
||||
|
||||
case Buttons.KeyH:
|
||||
return control ? 0x08 : capsLock ? 'H' : 'h';
|
||||
|
||||
case Buttons.KeyI:
|
||||
return control ? 0x09 : capsLock ? 'I' : 'i';
|
||||
|
||||
case Buttons.KeyJ:
|
||||
return control ? 0x0A : capsLock ? 'J' : 'j';
|
||||
|
||||
case Buttons.KeyK:
|
||||
return control ? 0x0B : capsLock ? 'K' : 'k';
|
||||
|
||||
case Buttons.KeyL:
|
||||
return control ? 0x0C : capsLock ? 'L' : 'l';
|
||||
|
||||
case Buttons.KeyM:
|
||||
return control ? 0x0D : capsLock ? 'M' : 'm';
|
||||
|
||||
case Buttons.KeyN:
|
||||
return control ? 0x0E : capsLock ? 'N' : 'n';
|
||||
|
||||
case Buttons.KeyO:
|
||||
return control ? 0x0F : capsLock ? 'O' : 'o';
|
||||
|
||||
case Buttons.KeyP:
|
||||
return control ? 0x10 : capsLock ? 'P' : 'p';
|
||||
|
||||
case Buttons.KeyQ:
|
||||
return control ? 0x11 : capsLock ? 'Q' : 'q';
|
||||
|
||||
case Buttons.KeyR:
|
||||
return control ? 0x12 : capsLock ? 'R' : 'r';
|
||||
|
||||
case Buttons.KeyS:
|
||||
return control ? 0x13 : capsLock ? 'S' : 's';
|
||||
|
||||
case Buttons.KeyT:
|
||||
return control ? 0x14 : capsLock ? 'T' : 't';
|
||||
|
||||
case Buttons.KeyU:
|
||||
return control ? 0x15 : capsLock ? 'U' : 'u';
|
||||
|
||||
case Buttons.KeyV:
|
||||
return control ? 0x16 : capsLock ? 'V' : 'v';
|
||||
|
||||
case Buttons.KeyW:
|
||||
return control ? 0x17 : capsLock ? 'W' : 'w';
|
||||
|
||||
case Buttons.KeyX:
|
||||
return control ? 0x18 : capsLock ? 'X' : 'x';
|
||||
|
||||
case Buttons.KeyY:
|
||||
return control ? 0x19 : capsLock ? 'Y' : 'y';
|
||||
|
||||
case Buttons.KeyZ:
|
||||
return control ? 0x1A : capsLock ? 'Z' : 'z';
|
||||
//TODO: Get around to supporting those keys too
|
||||
/*
|
||||
case Key.Oem1:
|
||||
return shift ? ':' : ';';
|
||||
|
||||
case Key.Oem2:
|
||||
return shift ? '?' : '/';
|
||||
|
||||
case Key.Oem3:
|
||||
return shift ? '~' : '`';
|
||||
|
||||
case Key.Oem4:
|
||||
return shift ? '{' : '[';
|
||||
|
||||
case Key.Oem5:
|
||||
return control ? 0x1C : shift ? '|' : '\\';
|
||||
|
||||
case Key.Oem6:
|
||||
return control ? 0x1D : shift ? '}' : ']';
|
||||
|
||||
case Key.Oem7:
|
||||
return shift ? '"' : '\'';
|
||||
|
||||
case Key.OemMinus:
|
||||
return control ? 0x1F : shift ? '_' : '-';
|
||||
|
||||
case Key.OemPlus:
|
||||
return shift ? '+' : '=';
|
||||
|
||||
case Key.OemComma:
|
||||
return shift ? '<' : ',';
|
||||
|
||||
case Key.OemPeriod:
|
||||
return shift ? '>' : '.';
|
||||
* */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int Paddle0 { get; protected set; }
|
||||
public int Paddle1 { get; protected set; }
|
||||
public int Paddle2 { get; protected set; }
|
||||
public int Paddle3 { get; protected set; }
|
||||
|
||||
public bool IsJoystick0Up { get; protected set; }
|
||||
public bool IsJoystick0Left { get; protected set; }
|
||||
public bool IsJoystick0Right { get; protected set; }
|
||||
public bool IsJoystick0Down { get; protected set; }
|
||||
|
||||
public bool IsJoystick1Up { get; protected set; }
|
||||
public bool IsJoystick1Left { get; protected set; }
|
||||
public bool IsJoystick1Right { get; protected set; }
|
||||
public bool IsJoystick1Down { get; protected set; }
|
||||
|
||||
public bool IsButton0Down { get; protected set; }
|
||||
public bool IsButton1Down { get; protected set; }
|
||||
public bool IsButton2Down { get; protected set; }
|
||||
|
||||
private static readonly long RepeatDelay = TimeSpan.FromMilliseconds(500).Ticks;
|
||||
private static readonly long RepeatSpeed = TimeSpan.FromMilliseconds(32).Ticks;
|
||||
|
||||
//private bool _isJoystick0UpLeftKeyDown;
|
||||
//private bool _isJoystick0UpKeyDown;
|
||||
//private bool _isJoystick0UpRightKeyDown;
|
||||
//private bool _isJoystick0LeftKeyDown;
|
||||
//private bool _isJoystick0RightKeyDown;
|
||||
//private bool _isJoystick0DownLeftKeyDown;
|
||||
//private bool _isJoystick0DownKeyDown;
|
||||
//private bool _isJoystick0DownRightKeyDown;
|
||||
//private bool _isJoystick1UpLeftKeyDown;
|
||||
//private bool _isJoystick1UpKeyDown;
|
||||
//private bool _isJoystick1UpRightKeyDown;
|
||||
//private bool _isJoystick1LeftKeyDown;
|
||||
//private bool _isJoystick1RightKeyDown;
|
||||
//private bool _isJoystick1DownLeftKeyDown;
|
||||
//private bool _isJoystick1DownKeyDown;
|
||||
//private bool _isJoystick1DownRightKeyDown;
|
||||
private bool _isButton0KeyDown;
|
||||
//private bool _isButton1KeyDown;
|
||||
//private bool _isButton2KeyDown;
|
||||
|
||||
//private bool _wasJoystick0UpLeftKeyDown;
|
||||
//private bool _wasJoystick0UpKeyDown;
|
||||
//private bool _wasJoystick0UpRightKeyDown;
|
||||
//private bool _wasJoystick0LeftKeyDown;
|
||||
//private bool _wasJoystick0RightKeyDown;
|
||||
//private bool _wasJoystick0DownLeftKeyDown;
|
||||
//private bool _wasJoystick0DownKeyDown;
|
||||
//private bool _wasJoystick0DownRightKeyDown;
|
||||
//private bool _wasJoystick1UpLeftKeyDown;
|
||||
//private bool _wasJoystick1UpKeyDown;
|
||||
//private bool _wasJoystick1UpRightKeyDown;
|
||||
//private bool _wasJoystick1LeftKeyDown;
|
||||
//private bool _wasJoystick1RightKeyDown;
|
||||
//private bool _wasJoystick1DownLeftKeyDown;
|
||||
//private bool _wasJoystick1DownKeyDown;
|
||||
//private bool _wasJoystick1DownRightKeyDown;
|
||||
private bool _wasButton0KeyDown;
|
||||
//private bool _wasButton1KeyDown;
|
||||
//private bool _wasButton2KeyDown;
|
||||
|
||||
private ulong _lastKey;
|
||||
private long _lastTime;
|
||||
private long _repeatTime;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.IO.IsolatedStorage;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public class IsolatedStorageService : StorageService
|
||||
{
|
||||
public IsolatedStorageService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnLoad(string fileName, Action<Stream> reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
using (var store = GetStore())
|
||||
{
|
||||
using (var stream = store.OpenFile(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
reader(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSave(string fileName, Action<Stream> writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
using (var store = GetStore())
|
||||
{
|
||||
using (var stream = store.OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
writer(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
|
||||
protected virtual IsolatedStorageFile GetStore()
|
||||
{
|
||||
return IsolatedStorageFile.GetUserStoreForApplication();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class KeyboardService : MachineService
|
||||
{
|
||||
protected KeyboardService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract bool IsKeyDown(int key);
|
||||
|
||||
public virtual void Update() // main thread
|
||||
{
|
||||
var keyboard = Machine.Keyboard;
|
||||
var buttons = Machine.Buttons;
|
||||
|
||||
keyboard.Button0Key = (ulong)buttons;
|
||||
|
||||
if (IsResetKeyDown && !keyboard.DisableResetKey)
|
||||
{
|
||||
if (!_resetKeyDown)
|
||||
{
|
||||
_resetKeyDown = true; // entering reset; pause until key released
|
||||
//TODO ADELIKAT : HANDLE RESET DIFFERENTLY
|
||||
//Machine.Pause();
|
||||
//Machine.Reset();
|
||||
}
|
||||
}
|
||||
else if (_resetKeyDown)
|
||||
{
|
||||
_resetKeyDown = false; // leaving reset
|
||||
//TODO ADELIKAT : HANDLE RESET DIFFERENTLY
|
||||
//Machine.Unpause();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAnyKeyDown { get { return Machine.Buttons > 0; }}
|
||||
public bool IsControlKeyDown { get { return Machine.Buttons.HasFlag(Buttons.Ctrl); }}
|
||||
public bool IsShiftKeyDown { get { return Machine.Buttons.HasFlag(Buttons.Shift); }}
|
||||
|
||||
public bool IsOpenAppleKeyDown { get; protected set; }
|
||||
public bool IsCloseAppleKeyDown { get; protected set; }
|
||||
|
||||
protected bool IsResetKeyDown { get; set; }
|
||||
|
||||
private bool _resetKeyDown;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using Jellyfish.Library;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class MachineService : DisposableBase
|
||||
{
|
||||
protected MachineService(Machine machine)
|
||||
{
|
||||
Machine = machine;
|
||||
|
||||
_debugService = new Lazy<DebugService>(() => Machine.Services.GetService<DebugService>());
|
||||
}
|
||||
|
||||
protected Machine Machine { get; private set; }
|
||||
protected DebugService DebugService { get { return _debugService.Value; } }
|
||||
|
||||
private Lazy<DebugService> _debugService;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public sealed class MachineServices : IServiceProvider
|
||||
{
|
||||
public void AddService(Type serviceType, MachineService serviceProvider)
|
||||
{
|
||||
if (serviceType == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceType");
|
||||
}
|
||||
if (_serviceProviders.ContainsKey(serviceType))
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType");
|
||||
}
|
||||
if (serviceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceProvider");
|
||||
}
|
||||
if (!serviceType.IsAssignableFrom(serviceProvider.GetType()))
|
||||
{
|
||||
throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName));
|
||||
}
|
||||
|
||||
_serviceProviders.Add(serviceType, serviceProvider);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
public T GetService<T>()
|
||||
{
|
||||
return (T)((IServiceProvider)this).GetService(typeof(T));
|
||||
}
|
||||
|
||||
public void RemoveService(Type serviceType)
|
||||
{
|
||||
_serviceProviders.Remove(serviceType);
|
||||
}
|
||||
|
||||
object IServiceProvider.GetService(Type serviceType)
|
||||
{
|
||||
return _serviceProviders.ContainsKey(serviceType) ? _serviceProviders[serviceType] : null;
|
||||
}
|
||||
|
||||
private Dictionary<Type, MachineService> _serviceProviders = new Dictionary<Type, MachineService>();
|
||||
}
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class StorageService : MachineService
|
||||
{
|
||||
protected StorageService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public bool Load(string fileName, Action<Stream> reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
DebugService.WriteMessage("Loading file '{0}'", fileName);
|
||||
OnLoad(fileName, reader);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !WINDOWS
|
||||
[SecuritySafeCritical]
|
||||
#endif
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public static bool LoadFile(Stream stream, Action<Stream> reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DebugService.Default.WriteMessage("Loading file '{0}'", "STREAM");
|
||||
{
|
||||
reader(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.Default.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !WINDOWS
|
||||
[SecuritySafeCritical]
|
||||
#endif
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public static bool LoadFile(FileInfo fileInfo, Action<Stream> reader)
|
||||
{
|
||||
if (fileInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("fileInfo");
|
||||
}
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DebugService.Default.WriteMessage("Loading file '{0}'", fileInfo.Name);
|
||||
using (var stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
reader(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.Default.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public static bool LoadResource(string resourceName, Action<Stream> reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DebugService.Default.WriteMessage("Loading resource '{0}'", resourceName);
|
||||
using (var stream = File.OpenRead(resourceName))
|
||||
reader(stream);
|
||||
//using (var stream = GetResourceStream(resourceName))
|
||||
//{
|
||||
// reader(stream);
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.Default.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public bool Save(string fileName, Action<Stream> writer)
|
||||
{
|
||||
try
|
||||
{
|
||||
DebugService.WriteMessage("Saving file '{0}'", fileName);
|
||||
OnSave(fileName, writer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !WINDOWS
|
||||
[SecuritySafeCritical]
|
||||
#endif
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public static bool SaveFile(string fileName, Action<Stream> writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DebugService.Default.WriteMessage("Saving file '{0}'", fileName);
|
||||
using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
writer(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.Default.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !WINDOWS
|
||||
[SecuritySafeCritical]
|
||||
#endif
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public static bool SaveFile(FileInfo fileInfo, Action<Stream> writer)
|
||||
{
|
||||
if (fileInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException("fileInfo");
|
||||
}
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DebugService.Default.WriteMessage("Saving file '{0}'", fileInfo.Name);
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
writer(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugService.Default.WriteMessage(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void OnLoad(string fileName, Action<Stream> reader);
|
||||
|
||||
protected abstract void OnSave(string fileName, Action<Stream> writer);
|
||||
|
||||
private static Stream GetResourceStream(string resourceName)
|
||||
{
|
||||
resourceName = "Jellyfish.Virtu." + resourceName.Replace('/', '.');
|
||||
var resourceStream = typeof(StorageService).Assembly.GetManifestResourceStream(resourceName);
|
||||
if (resourceStream == null)
|
||||
{
|
||||
throw new FileNotFoundException(string.Format(CultureInfo.CurrentUICulture, Strings.ResourceNotFound, resourceName));
|
||||
}
|
||||
|
||||
return resourceStream;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,25 @@
|
|||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
public abstract class VideoService : MachineService
|
||||
/// <summary>
|
||||
/// this isn't really a "service" anymore, just a helper for the video class
|
||||
/// </summary>
|
||||
public class VideoService
|
||||
{
|
||||
protected VideoService(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
}
|
||||
public VideoService()
|
||||
{
|
||||
fb = new int[560 * 384];
|
||||
}
|
||||
public VideoService(int[] fb)
|
||||
{
|
||||
this.fb = fb;
|
||||
}
|
||||
|
||||
public virtual void SetFullScreen(bool isFullScreen)
|
||||
{
|
||||
}
|
||||
public int[] fb;
|
||||
|
||||
public abstract void SetPixel(int x, int y, uint color);
|
||||
public abstract void Update(); // main thread
|
||||
public void SetPixel(int x, int y, uint color)
|
||||
{
|
||||
int i = 560 * y + x;
|
||||
fb[i] = fb[i + 560] = (int)color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
public sealed class Speaker : MachineComponent
|
||||
{
|
||||
public Speaker() { }
|
||||
public Speaker(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -14,39 +15,17 @@ namespace Jellyfish.Virtu
|
|||
|
||||
public override void Initialize()
|
||||
{
|
||||
_audioService = Machine.Services.GetService<AudioService>();
|
||||
AudioService = new Services.AudioService();
|
||||
|
||||
Volume = 0.5f;
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_audioService.Reset();
|
||||
_isHigh = false;
|
||||
_highCycles = _totalCycles = 0;
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
Volume = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(Volume);
|
||||
}
|
||||
|
||||
public void ToggleOutput()
|
||||
{
|
||||
UpdateCycles();
|
||||
|
@ -56,7 +35,8 @@ namespace Jellyfish.Virtu
|
|||
private void FlushOutputEvent()
|
||||
{
|
||||
UpdateCycles();
|
||||
_audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation
|
||||
// TODO: better than simple decimation here!!
|
||||
AudioService.Output(_highCycles * short.MaxValue / _totalCycles);
|
||||
_highCycles = _totalCycles = 0;
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
|
||||
|
@ -73,20 +53,15 @@ namespace Jellyfish.Virtu
|
|||
_lastCycles = Machine.Cpu.Cycles;
|
||||
}
|
||||
|
||||
public float Volume { get { return _volume; } set { _volume = value; _audioService.SetVolume(_volume); } }
|
||||
|
||||
private const int CyclesPerFlush = 23;
|
||||
|
||||
private Action _flushOutputEvent;
|
||||
|
||||
private AudioService _audioService;
|
||||
|
||||
private bool _isHigh;
|
||||
private int _highCycles;
|
||||
private int _totalCycles;
|
||||
private long _lastCycles;
|
||||
private float _volume;
|
||||
|
||||
public AudioService AudioService { get { return _audioService; } }
|
||||
public AudioService AudioService { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
public sealed partial class Video : MachineComponent
|
||||
{
|
||||
public Video() { }
|
||||
public Video(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
|
@ -27,7 +28,7 @@ namespace Jellyfish.Virtu
|
|||
public override void Initialize()
|
||||
{
|
||||
_memory = Machine.Memory;
|
||||
_videoService = Machine.Services.GetService<VideoService>();
|
||||
VideoService = new Services.VideoService();
|
||||
|
||||
//#if SILVERLIGHT || WPF
|
||||
_colorBlack = 0xFF000000; // BGRA
|
||||
|
@ -68,7 +69,6 @@ namespace Jellyfish.Virtu
|
|||
//#endif
|
||||
SetPalette();
|
||||
|
||||
IsFullScreen = false;
|
||||
IsMonochrome = false;
|
||||
ScannerOptions = ScannerOptions.None;
|
||||
|
||||
|
@ -86,71 +86,6 @@ namespace Jellyfish.Virtu
|
|||
FlushScreen();
|
||||
}
|
||||
|
||||
public override void LoadState(BinaryReader reader, Version version)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
_colorBlack = reader.ReadUInt32();
|
||||
_colorDarkBlue = reader.ReadUInt32();
|
||||
_colorDarkGreen = reader.ReadUInt32();
|
||||
_colorMediumBlue = reader.ReadUInt32();
|
||||
_colorBrown = reader.ReadUInt32();
|
||||
_colorLightGrey = reader.ReadUInt32();
|
||||
_colorGreen = reader.ReadUInt32();
|
||||
_colorAquamarine = reader.ReadUInt32();
|
||||
_colorDeepRed = reader.ReadUInt32();
|
||||
_colorPurple = reader.ReadUInt32();
|
||||
_colorDarkGrey = reader.ReadUInt32();
|
||||
_colorLightBlue = reader.ReadUInt32();
|
||||
_colorOrange = reader.ReadUInt32();
|
||||
_colorPink = reader.ReadUInt32();
|
||||
_colorYellow = reader.ReadUInt32();
|
||||
_colorWhite = reader.ReadUInt32();
|
||||
_colorMonochrome = reader.ReadUInt32();
|
||||
SetPalette();
|
||||
|
||||
IsFullScreen = reader.ReadBoolean();
|
||||
IsMonochrome = reader.ReadBoolean();
|
||||
ScannerOptions = (ScannerOptions)reader.ReadInt32();
|
||||
|
||||
SetCharSet();
|
||||
DirtyScreen();
|
||||
FlushScreen();
|
||||
}
|
||||
|
||||
public override void SaveState(BinaryWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException("writer");
|
||||
}
|
||||
|
||||
writer.Write(_colorBlack);
|
||||
writer.Write(_colorDarkBlue);
|
||||
writer.Write(_colorDarkGreen);
|
||||
writer.Write(_colorMediumBlue);
|
||||
writer.Write(_colorBrown);
|
||||
writer.Write(_colorLightGrey);
|
||||
writer.Write(_colorGreen);
|
||||
writer.Write(_colorAquamarine);
|
||||
writer.Write(_colorDeepRed);
|
||||
writer.Write(_colorPurple);
|
||||
writer.Write(_colorDarkGrey);
|
||||
writer.Write(_colorLightBlue);
|
||||
writer.Write(_colorOrange);
|
||||
writer.Write(_colorPink);
|
||||
writer.Write(_colorYellow);
|
||||
writer.Write(_colorWhite);
|
||||
writer.Write(_colorMonochrome);
|
||||
|
||||
writer.Write(IsFullScreen);
|
||||
writer.Write(IsMonochrome);
|
||||
writer.Write((int)ScannerOptions);
|
||||
}
|
||||
|
||||
public void DirtyCell(int addressOffset)
|
||||
{
|
||||
_isCellDirty[CellIndex[addressOffset]] = true;
|
||||
|
@ -1061,7 +996,7 @@ namespace Jellyfish.Virtu
|
|||
|
||||
private void SetPixel(int x, int y, int color)
|
||||
{
|
||||
_videoService.SetPixel(x, 2 * y, _colorPalette[color]);
|
||||
VideoService.SetPixel(x, 2 * y, _colorPalette[color]);
|
||||
}
|
||||
|
||||
private void SetScanner()
|
||||
|
@ -1083,25 +1018,41 @@ namespace Jellyfish.Virtu
|
|||
_cyclesPerFlash = VSyncsPerFlash * _cyclesPerVSync;
|
||||
}
|
||||
|
||||
public uint ColorBlack { get { return _colorBlack; } set { _colorBlack = value; SetPalette(); } }
|
||||
public uint ColorDarkBlue { get { return _colorDarkBlue; } set { _colorDarkBlue = value; SetPalette(); } }
|
||||
public uint ColorDarkGreen { get { return _colorDarkGreen; } set { _colorDarkGreen = value; SetPalette(); } }
|
||||
public uint ColorMediumBlue { get { return _colorMediumBlue; } set { _colorMediumBlue = value; SetPalette(); } }
|
||||
public uint ColorBrown { get { return _colorBrown; } set { _colorBrown = value; SetPalette(); } }
|
||||
public uint ColorLightGrey { get { return _colorLightGrey; } set { _colorLightGrey = value; SetPalette(); } }
|
||||
public uint ColorGreen { get { return _colorGreen; } set { _colorGreen = value; SetPalette(); } }
|
||||
public uint ColorAquamarine { get { return _colorAquamarine; } set { _colorAquamarine = value; SetPalette(); } }
|
||||
public uint ColorDeepRed { get { return _colorDeepRed; } set { _colorDeepRed = value; SetPalette(); } }
|
||||
public uint ColorPurple { get { return _colorPurple; } set { _colorPurple = value; SetPalette(); } }
|
||||
public uint ColorDarkGrey { get { return _colorDarkGrey; } set { _colorDarkGrey = value; SetPalette(); } }
|
||||
public uint ColorLightBlue { get { return _colorLightBlue; } set { _colorLightBlue = value; SetPalette(); } }
|
||||
public uint ColorOrange { get { return _colorOrange; } set { _colorOrange = value; SetPalette(); } }
|
||||
public uint ColorPink { get { return _colorPink; } set { _colorPink = value; SetPalette(); } }
|
||||
public uint ColorYellow { get { return _colorYellow; } set { _colorYellow = value; SetPalette(); } }
|
||||
public uint ColorWhite { get { return _colorWhite; } set { _colorWhite = value; SetPalette(); } }
|
||||
public uint ColorMonochrome { get { return _colorMonochrome; } set { _colorMonochrome = value; SetPalette(); } }
|
||||
|
||||
public bool IsFullScreen { get { return _isFullScreen; } set { _isFullScreen = value; _videoService.SetFullScreen(_isFullScreen); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorBlack { get { return _colorBlack; } set { _colorBlack = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorDarkBlue { get { return _colorDarkBlue; } set { _colorDarkBlue = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorDarkGreen { get { return _colorDarkGreen; } set { _colorDarkGreen = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorMediumBlue { get { return _colorMediumBlue; } set { _colorMediumBlue = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorBrown { get { return _colorBrown; } set { _colorBrown = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorLightGrey { get { return _colorLightGrey; } set { _colorLightGrey = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorGreen { get { return _colorGreen; } set { _colorGreen = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorAquamarine { get { return _colorAquamarine; } set { _colorAquamarine = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorDeepRed { get { return _colorDeepRed; } set { _colorDeepRed = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorPurple { get { return _colorPurple; } set { _colorPurple = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorDarkGrey { get { return _colorDarkGrey; } set { _colorDarkGrey = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorLightBlue { get { return _colorLightBlue; } set { _colorLightBlue = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorOrange { get { return _colorOrange; } set { _colorOrange = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorPink { get { return _colorPink; } set { _colorPink = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorYellow { get { return _colorYellow; } set { _colorYellow = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorWhite { get { return _colorWhite; } set { _colorWhite = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public uint ColorMonochrome { get { return _colorMonochrome; } set { _colorMonochrome = value; SetPalette(); } }
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public bool IsMonochrome { get { return _isMonochrome; } set { _isMonochrome = value; DirtyScreen(); } }
|
||||
public ScannerOptions ScannerOptions { get { return _scannerOptions; } set { _scannerOptions = value; SetScanner(); } }
|
||||
|
||||
|
@ -1113,7 +1064,7 @@ namespace Jellyfish.Virtu
|
|||
private Action _resetVSyncEvent;
|
||||
|
||||
private Memory _memory;
|
||||
private VideoService _videoService;
|
||||
public VideoService VideoService { get; private set; }
|
||||
|
||||
private uint _colorBlack;
|
||||
private uint _colorDarkBlue;
|
||||
|
@ -1132,7 +1083,6 @@ namespace Jellyfish.Virtu
|
|||
private uint _colorYellow;
|
||||
private uint _colorWhite;
|
||||
private uint _colorMonochrome;
|
||||
private bool _isFullScreen;
|
||||
private bool _isMonochrome;
|
||||
private bool _isTextInversed;
|
||||
private ScannerOptions _scannerOptions;
|
||||
|
|
|
@ -1627,7 +1627,7 @@ namespace Jellyfish.Virtu
|
|||
public const int ModeE = 0xE;
|
||||
public const int ModeF = 0xF;
|
||||
|
||||
private readonly Action<int>[] FlushRowMode;
|
||||
private Action<int>[] FlushRowMode;
|
||||
|
||||
private const int Width = 560;
|
||||
private const int Height = VLineEnterVBlank;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -31,6 +31,9 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\..\References\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
|
@ -43,6 +46,7 @@
|
|||
<Compile Include="Cassette.cs" />
|
||||
<Compile Include="Cpu.cs" />
|
||||
<Compile Include="CpuData.cs" />
|
||||
<Compile Include="ExtraConverters.cs" />
|
||||
<Compile Include="Disk525.cs" />
|
||||
<Compile Include="DiskDsk.cs" />
|
||||
<Compile Include="DiskIIController.cs" />
|
||||
|
@ -64,12 +68,6 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\AudioService.cs" />
|
||||
<Compile Include="Services\DebugService.cs" />
|
||||
<Compile Include="Services\GamePortService.cs" />
|
||||
<Compile Include="Services\IsolatedStorageService.cs" />
|
||||
<Compile Include="Services\KeyboardService.cs" />
|
||||
<Compile Include="Services\MachineService.cs" />
|
||||
<Compile Include="Services\MachineServices.cs" />
|
||||
<Compile Include="Services\StorageService.cs" />
|
||||
<Compile Include="Services\VideoService.cs" />
|
||||
<Compile Include="Speaker.cs" />
|
||||
<Compile Include="Video.cs" />
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue