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 sealed class Machine : IDisposable { /// /// for deserialization only!! /// public Machine() { } public Machine(byte[] appleIIe, byte[] diskIIRom) { Events = new MachineEvents(); 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; Slots = new List { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; Components = new List { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; BootDiskII = Slots.OfType().Last(); } public void Dispose() { } 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); } } 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 Uninitialize() { foreach (var component in Components) { DebugService.WriteMessage("Uninitializing machine '{0}'", component.GetType().Name); component.Uninitialize(); //DebugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name); } } public void BizInitialize() { Initialize(); Reset(); } public void BizFrameAdvance(IEnumerable buttons) { Lagged = true; DriveLight = false; Keyboard.SetKeys(buttons); //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()); */ Events.HandleEvents(Cpu.Execute()); } } public void BizShutdown() { Uninitialize(); } private static JsonSerializer CreateSerializer() { // TODO: converters could be cached for speedup 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, }; ser.Converters.Add(new TypeTypeConverter(new[] { // all expected Types to convert are either in this assembly or mscorlib typeof(Machine).Assembly, typeof(object).Assembly })); ser.Converters.Add(new DelegateConverter()); ser.Converters.Add(new ArrayConverter()); var cr = new DefaultContractResolver(); cr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic; ser.ContractResolver = cr; return ser; } public void Serialize(JsonWriter w) { CreateSerializer().Serialize(w, this); } public static Machine Deserialize(JsonReader r) { return CreateSerializer().Deserialize(r); } public const string Version = "0.9.4.0"; public MachineEvents Events { get; private set; } 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; } 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 IList Slots { get; private set; } public IList Components { get; private set; } public DiskIIController BootDiskII { get; private set; } public bool Lagged { get; set; } public bool DriveLight { get; set; } public IDictionary GetCpuFlagsAndRegisters() { return new Dictionary { { "A", Cpu.RA }, { "X", Cpu.RX }, { "Y", Cpu.RY }, { "S", Cpu.RS }, { "PC", Cpu.RPC }, { "Flag C", Cpu.FlagC ? 1 : 0 }, { "Flag Z", Cpu.FlagZ ? 1 : 0 }, { "Flag I", Cpu.FlagI ? 1 : 0 }, { "Flag D", Cpu.FlagD ? 1 : 0 }, { "Flag B", Cpu.FlagB ? 1 : 0 }, { "Flag V", Cpu.FlagV ? 1 : 0 }, { "Flag N", Cpu.FlagN ? 1 : 0 }, { "Flag T", Cpu.FlagT ? 1 : 0 } }; } } }