using System.Collections.Generic; using System.Linq; using BizHawk.Emulation.Common; using Jellyfish.Virtu; namespace BizHawk.Emulation.Cores.Computers.AppleII { [Core( "Virtu", "fool", isPorted: true, isReleased: true)] [ServiceNotApplicable(typeof(ISaveRam), typeof(IRegionable), typeof(IBoardInfo))] public partial class AppleII : IEmulator, ISoundProvider, IVideoProvider, IStatable, IDriveLight { static AppleII() { AppleIIController = new ControllerDefinition { Name = "Apple IIe Keyboard" }; AppleIIController.BoolButtons.AddRange(RealButtons); AppleIIController.BoolButtons.AddRange(ExtraButtons); } public AppleII(CoreComm comm, IEnumerable gameInfoSet, IEnumerable romSet, Settings settings) : this(comm, gameInfoSet.First(), romSet.First(), settings) { _romSet = romSet.ToList(); } [CoreConstructor("AppleII")] public AppleII(CoreComm comm, GameInfo game, byte[] rom, Settings settings) { var ser = new BasicServiceProvider(this); ServiceProvider = ser; CoreComm = comm; _tracer = new TraceBuffer { Header = "6502: PC, opcode, register (A, X, Y, P, SP, Cy), flags (NVTBDIZC)" }; _disk1 = rom; _romSet.Add(rom); _appleIIRom = comm.CoreFileProvider.GetFirmware( SystemId, "AppleIIe", true, "The Apple IIe BIOS firmware is required"); _diskIIRom = comm.CoreFileProvider.GetFirmware( SystemId, "DiskII", true, "The DiskII firmware is required"); _machine = new Machine(_appleIIRom, _diskIIRom); _machine.BizInitialize(); // make a writeable memory stream cloned from the rom. // for junk.dsk the .dsk is important because it determines the format from that InitDisk(); ser.Register(_tracer); SetCallbacks(); InitSaveStates(); SetupMemoryDomains(); PutSettings(settings ?? new Settings()); } private static readonly ControllerDefinition AppleIIController; private readonly List _romSet = new List(); private readonly ITraceable _tracer; private Machine _machine; private byte[] _disk1; private readonly byte[] _appleIIRom; private readonly byte[] _diskIIRom; public int CurrentDisk { get; private set; } public int DiskCount => _romSet.Count; public void SetDisk(int discNum) { CurrentDisk = discNum; InitDisk(); } private void IncrementDisk() { CurrentDisk++; if (CurrentDisk >= _romSet.Count) { CurrentDisk = 0; } InitDisk(); } private void DecrementDisk() { CurrentDisk--; if (CurrentDisk < 0) { CurrentDisk = _romSet.Count - 1; } InitDisk(); } private void InitDisk() { _disk1 = _romSet[CurrentDisk]; // make a writeable memory stream cloned from the rom. // for junk.dsk the .dsk is important because it determines the format from that _machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", (byte[])_disk1.Clone(), false); } private static readonly List RealButtons = new List(Keyboard.GetKeyNames() .Where(k => k != "White Apple") // Hack because these buttons aren't wired up yet .Where(k => k != "Black Apple") .Where(k => k != "Reset")); private static readonly List ExtraButtons = new List { "Previous Disk", "Next Disk", }; public bool DriveLightEnabled => true; public bool DriveLightOn => _machine.DriveLight; private bool _nextPressed; private bool _prevPressed; private void TracerWrapper(string[] content) { _tracer.Put(new TraceInfo { Disassembly = content[0], RegisterInfo = content[1] }); } private void FrameAdv(IController controller, bool render, bool rendersound) { if (_tracer.Enabled) { _machine.Cpu.TraceCallback = TracerWrapper; } else { _machine.Cpu.TraceCallback = null; } if (controller.IsPressed("Next Disk") && !_nextPressed) { _nextPressed = true; IncrementDisk(); } else if (controller.IsPressed("Previous Disk") && !_prevPressed) { _prevPressed = true; DecrementDisk(); } if (!controller.IsPressed("Next Disk")) { _nextPressed = false; } if (!controller.IsPressed("Previous Disk")) { _prevPressed = false; } _machine.BizFrameAdvance(RealButtons.Where(controller.IsPressed)); if (IsLagFrame) { LagCount++; } Frame++; } private void SetCallbacks() { _machine.Memory.ReadCallback = (addr) => MemoryCallbacks.CallReads(addr, "System Bus"); _machine.Memory.WriteCallback = (addr) => MemoryCallbacks.CallWrites(addr, "System Bus"); _machine.Memory.ExecuteCallback = (addr) => MemoryCallbacks.CallExecutes(addr, "System Bus"); _machine.Memory.InputCallback = InputCallbacks.Call; } } }