using BizHawk.Common; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components.Z80A; using System; namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { /// /// The abstract class that all emulated models will inherit from /// * Main properties / fields / contruction* /// public abstract partial class SpectrumBase { // 128 and up only protected int ROMPaged = 0; protected bool SHADOWPaged; public int RAMPaged; protected bool PagingDisabled; // +3/+2A only protected bool SpecialPagingMode; protected int PagingConfiguration; /// /// The calling ZXSpectrum class (piped in via constructor) /// public ZXSpectrum Spectrum { get; set; } /// /// Reference to the instantiated Z80 cpu (piped in via constructor) /// public Z80A CPU { get; set; } /// /// ROM and extended info /// public RomData RomData { get; set; } /// /// The emulated ULA device /// public ULABase ULADevice { get; set; } /// /// The spectrum buzzer/beeper /// public Buzzer BuzzerDevice { get; set; } /// /// Device representing the AY-3-8912 chip found in the 128k and up spectrums /// public AY38912 AYDevice { get; set; } /// /// The spectrum keyboard /// public virtual IKeyboard KeyboardDevice { get; set; } /// /// The spectrum datacorder device /// public virtual DatacorderDevice TapeDevice { get; set; } /// /// The tape provider /// //public virtual ITapeProvider TapeProvider { get; set; } /// /// Kempston joystick /// public virtual KempstonJoystick KempstonDevice { get; set; } /// /// Signs whether the frame has ended /// public bool FrameCompleted; /// /// Overflow from the previous frame (in Z80 cycles) /// public int OverFlow; /// /// The total number of frames rendered /// public int FrameCount; /// /// The current cycle (T-State) that we are at in the frame /// public int _frameCycles; /// /// Stores where we are in the frame after each CPU cycle /// public int LastFrameStartCPUTick; /// /// Gets the current frame cycle according to the CPU tick count /// public virtual int CurrentFrameCycle => CPU.TotalExecutedCycles - LastFrameStartCPUTick; /// /// Mask constants /// protected const int BORDER_BIT = 0x07; protected const int EAR_BIT = 0x10; protected const int MIC_BIT = 0x08; protected const int TAPE_BIT = 0x40; protected const int AY_SAMPLE_RATE = 16; /// /// Executes a single frame /// public virtual void ExecuteFrame() { FrameCompleted = false; BuzzerDevice.StartFrame(); if (AYDevice != null) AYDevice.StartFrame(); PollInput(); while (CurrentFrameCycle < ULADevice.FrameLength) // UlaFrameCycleCount) { // check for interrupt ULADevice.CheckForInterrupt(CurrentFrameCycle); // run a single CPU instruction CPU.ExecuteOne(); // update AY if (AYDevice != null) AYDevice.UpdateSound(CurrentFrameCycle); } // we have reached the end of a frame LastFrameStartCPUTick = CPU.TotalExecutedCycles - OverFlow; // paint the buffer if needed if (ULADevice.needsPaint) ULADevice.UpdateScreenBuffer(ULADevice.FrameLength); BuzzerDevice.EndFrame(); //TapeDevice.CPUFrameCompleted(); FrameCount++; // setup for next frame ULADevice.ResetInterrupt(); FrameCompleted = true; } /// /// Hard reset of the emulated machine /// public virtual void HardReset() { //ResetBorder(); ULADevice.ResetInterrupt(); } /// /// Soft reset of the emulated machine /// public virtual void SoftReset() { //ResetBorder(); ULADevice.ResetInterrupt(); } public void SyncState(Serializer ser) { ser.BeginSection("ZXMachine"); ser.Sync("FrameCompleted", ref FrameCompleted); ser.Sync("OverFlow", ref OverFlow); ser.Sync("FrameCount", ref FrameCount); ser.Sync("_frameCycles", ref _frameCycles); ser.Sync("LastFrameStartCPUTick", ref LastFrameStartCPUTick); ser.Sync("LastULAOutByte", ref LastULAOutByte); ser.Sync("ROM0", ref ROM0, false); ser.Sync("ROM1", ref ROM1, false); ser.Sync("ROM2", ref ROM2, false); ser.Sync("ROM3", ref ROM3, false); ser.Sync("RAM0", ref RAM0, false); ser.Sync("RAM1", ref RAM1, false); ser.Sync("RAM2", ref RAM2, false); ser.Sync("RAM3", ref RAM3, false); ser.Sync("RAM4", ref RAM4, false); ser.Sync("RAM5", ref RAM5, false); ser.Sync("RAM6", ref RAM6, false); ser.Sync("RAM7", ref RAM7, false); ser.Sync("ROMPaged", ref ROMPaged); ser.Sync("SHADOWPaged", ref SHADOWPaged); ser.Sync("RAMPaged", ref RAMPaged); ser.Sync("PagingDisabled", ref PagingDisabled); ser.Sync("SpecialPagingMode", ref SpecialPagingMode); ser.Sync("PagingConfiguration", ref PagingConfiguration); RomData.SyncState(ser); KeyboardDevice.SyncState(ser); BuzzerDevice.SyncState(ser); ULADevice.SyncState(ser); if (AYDevice != null) AYDevice.SyncState(ser); TapeDevice.SyncState(ser); ser.EndSection(); ReInitMemory(); } } }