From 9a15cbf4d4f2187a608bdf802eb2b5e0cf8f1c79 Mon Sep 17 00:00:00 2001 From: Matt Burgess Date: Thu, 31 May 2018 17:54:57 +0100 Subject: [PATCH 01/51] ZXHawk: new ULA implementation --- .../BizHawk.Emulation.Cores.csproj | 3 + .../SinclairSpectrum/Machine/CPUMonitor.cs | 187 +++ .../Machine/SpectrumBase.Memory.cs | 14 +- .../Machine/SpectrumBase.Port.cs | 81 +- .../SinclairSpectrum/Machine/SpectrumBase.cs | 29 +- .../Computers/SinclairSpectrum/Machine/ULA.cs | 1008 +++++++++++++++++ .../SinclairSpectrum/Machine/ULABase.cs | 100 +- .../Machine/ZXSpectrum128K/ZX128.Memory.cs | 60 +- .../Machine/ZXSpectrum128K/ZX128.Port.cs | 25 +- .../Machine/ZXSpectrum128K/ZX128.ULA.cs | 6 +- .../Machine/ZXSpectrum128K/ZX128.cs | 6 +- .../ZX128Plus2a.Memory.cs | 78 +- .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 20 +- .../ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs | 6 +- .../ZXSpectrum128KPlus2a/ZX128Plus2a.cs | 6 +- .../ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 78 +- .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 22 +- .../ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs | 6 +- .../Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs | 6 +- .../Machine/ZXSpectrum16K/ZX16.cs | 18 +- .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 44 +- .../Machine/ZXSpectrum48K/ZX48.Port.cs | 53 +- .../Machine/ZXSpectrum48K/ZX48.Screen.cs | 49 + .../Machine/ZXSpectrum48K/ZX48.ULA.cs | 37 +- .../Machine/ZXSpectrum48K/ZX48.cs | 5 +- .../Computers/SinclairSpectrum/ZXSpectrum.cs | 1 + 26 files changed, 1728 insertions(+), 220 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 6aa7c1e3c1..36b6f5462a 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -261,6 +261,8 @@ + + @@ -1434,6 +1436,7 @@ + diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs new file mode 100644 index 0000000000..25a03161fc --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -0,0 +1,187 @@ +using BizHawk.Emulation.Cores.Components.Z80A; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + public class CPUMonitor + { + private SpectrumBase _machine; + private Z80A _cpu; + public MachineType machineType = MachineType.ZXSpectrum48; + + public CPUMonitor(SpectrumBase machine) + { + _machine = machine; + _cpu = _machine.CPU; + } + + public ushort[] cur_instr => _cpu.cur_instr; + public int instr_pntr => _cpu.instr_pntr; + public ushort RegPC => _cpu.RegPC; + public long TotalExecutedCycles => _cpu.TotalExecutedCycles; + + /// + /// Called when the first byte of an instruction is fetched + /// + /// + public void OnExecFetch(ushort firstByte) + { + // fetch instruction without incrementing pc + //_cpu.FetchInstruction(_cpu.FetchMemory(firstByte)); + } + + /// + /// A CPU monitor cycle + /// + public void Cycle() + { + if (portContending) + { + RunPortContention(); + } + } + + #region Port Contention + + public int portContCounter = 0; + public bool portContending = false; + public ushort lastPortAddr; + + /// + /// Perfors the actual port contention (if necessary) + /// + private void RunPortContention() + { + //return; + bool lowBitSet = false; + bool highByte407f = false; + + int offset = 0; // _machine.ULADevice.contentionOffset; // -5;// 57;// - 10; + var c = _machine.CurrentFrameCycle; + var t = _machine.ULADevice.FrameLength; + int f = (int)c + offset; + if (f >= t) + f = f - t; + else if (f < 0) + f = t + f; + + if ((lastPortAddr & 0x0001) != 0) + lowBitSet = true; + + portContCounter--; + + switch (machineType) + { + case MachineType.ZXSpectrum16: + case MachineType.ZXSpectrum48: + + if ((lastPortAddr & 0xc000) == 0x4000) + highByte407f = true; + + if (highByte407f) + { + // high byte 40-7f + if (lowBitSet) + { + // high byte 40-7f + // low bit set + // C:1, C:1, C:1, C:1 + switch (portContCounter) + { + case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 1: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 0: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + default: + portContCounter = 0; + portContending = false; + break; + } + } + else + { + // high byte 40-7f + // low bit reset + // C:1, C:3 + switch (portContCounter) + { + case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 1: break; + case 0: break; + default: + portContCounter = 0; + portContending = false; + break; + } + } + } + else + { + // high byte not 40-7f + if (lowBitSet) + { + // high byte not 40-7f + // low bit set + // N:4 + switch (portContCounter) + { + case 3: break; + case 2: break; + case 1: break; + case 0: break; + default: + portContCounter = 0; + portContending = false; + break; + } + } + else + { + // high byte not 40-7f + // low bit reset + // N:1, C:3 + switch (portContCounter) + { + case 3: break; + case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 1: break; + case 0: break; + default: + portContCounter = 0; + portContending = false; + break; + } + } + } + break; + + case MachineType.ZXSpectrum128: + case MachineType.ZXSpectrum128Plus2: + break; + + case MachineType.ZXSpectrum128Plus2a: + case MachineType.ZXSpectrum128Plus3: + break; + } + } + + /// + /// Starts the port contention process + /// + /// + public void ContendPort(ushort port) + { + portContending = true; + portContCounter = 4; + lastPortAddr = port; + } + + #endregion + + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs index 5c31caeb7b..5a8455bc34 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs @@ -89,8 +89,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #endregion - - #region Memory Related Methods /// @@ -153,9 +151,21 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public virtual byte FetchScreenMemory(ushort addr) { var value = ReadBus((ushort)((addr & 0x3FFF) + 0x4000)); + //var value = ReadBus(addr); return value; } + /// + /// Contends memory if necessary + /// + public abstract void ContendMemory(ushort addr); + + /// + /// Checks whether supplied address is in a potentially contended bank + /// + /// + public abstract bool IsContended(ushort addr); + #endregion #region Helper Methods diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs index 13e5d5ec5c..f71aee74a8 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs @@ -40,88 +40,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// Increments the CPU totalCycles counter by the tStates value specified /// /// - public virtual void PortContention(int tStates) - { - CPU.TotalExecutedCycles += tStates; - } + //public virtual void PortContention(int tStates) + //{ + // CPU.TotalExecutedCycles += tStates; + //} /// /// Simulates IO port contention based on the supplied address /// This method is for 48k and 128k/+2 machines only and should be overridden for other models /// /// - public virtual void ContendPortAddress(ushort addr) - { - return; - - /* - It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port. As is the case with memory access, - this can be lengthened by the ULA. There are two effects which occur here: - - If the port address being accessed has its low bit reset, the ULA is required to supply the result, which leads to a delay if it is - currently busy handling the screen. - The address of the port being accessed is placed on the data bus. If this is in the range 0x4000 to 0x7fff, the ULA treats this as an - attempted access to contended memory and therefore introduces a delay. If the port being accessed is between 0xc000 and 0xffff, - this effect does not apply, even on a 128K machine if a contended memory bank is paged into the range 0xc000 to 0xffff. - - These two effects combine to lead to the following contention patterns: - - High byte | | - in 40 - 7F? | Low bit | Contention pattern - ------------+---------+------------------- - No | Reset | N:1, C:3 - No | Set | N:4 - Yes | Reset | C:1, C:3 - Yes | Set | C:1, C:1, C:1, C:1 - - The 'Contention pattern' column should be interpreted from left to right. An "N:n" entry means that no delay is applied at this cycle, and the Z80 continues uninterrupted for 'n' T states. A "C:n" entry means that the ULA halts the Z80; the delay is exactly the same as would occur for a contended memory access at this cycle (eg 6 T states at cycle 14335, 5 at 14336, etc on the 48K machine). After this delay, the Z80 then continues for 'n' cycles. - */ - - // is the low bit reset (i.e. is this addressing the ULA)? - bool lowBit = (addr & 0x0001) != 0; - - if ((addr & 0xc000) == 0x4000 || (addr & 0xc000) == 0xC000) - { - // high byte is in 40 - 7F - if (lowBit) - { - // lowbit is set - // C:1, C:1, C:1, C:1 - for (int i = 0; i < 4; i++) - { - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - CPU.TotalExecutedCycles++; - } - } - else - { - // low bit is reset - // C:1, C:3 - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - CPU.TotalExecutedCycles++; - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - CPU.TotalExecutedCycles += 3; - } - } - else - { - // high byte is NOT in 40 - 7F - if (lowBit) - { - // lowbit is set - // C:1, C:1, C:1, C:1 - CPU.TotalExecutedCycles += 4; - } - else - { - // lowbit is reset - // N:1, C:3 - CPU.TotalExecutedCycles++; - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - CPU.TotalExecutedCycles += 3; - } - } - } + public abstract void ContendPort(ushort addr); } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index 7ba831e9a7..1a8ff0a328 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -32,7 +32,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// The emulated ULA device /// - public ULABase ULADevice { get; set; } + //public ULABase ULADevice { get; set; } + public ULA ULADevice { get; set; } + + /// + /// Monitors CPU cycles + /// + public CPUMonitor CPUMon { get; set; } /// /// The spectrum buzzer/beeper @@ -152,9 +158,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (_renderSound) { - //BuzzerDevice.StartFrame(); - //TapeBuzzer.StartFrame(); - if (AYDevice != null) AYDevice.StartFrame(); } @@ -169,23 +172,23 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // run a single CPU instruction CPU.ExecuteOne(); + CPUMon.Cycle(); + // cycle the tape device if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) TapeDevice.TapeCycle(); } + OverFlow = (int)CurrentFrameCycle - ULADevice.FrameLength; + // we have reached the end of a frame LastFrameStartCPUTick = CPU.TotalExecutedCycles - OverFlow; - // paint the buffer if needed - if (ULADevice.needsPaint && _render) - ULADevice.UpdateScreenBuffer(ULADevice.FrameLength); + // paint the buffer at end of frame + if (_render) + ULADevice.RenderScreen(ULADevice.FrameLength); - if (_renderSound) - { - //BuzzerDevice.EndFrame(); - //TapeBuzzer.EndFrame(); - } + ULADevice.LastTState = 0; if (AYDevice != null) AYDevice.EndFrame(); @@ -194,7 +197,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // setup for next frame ULADevice.ResetInterrupt(); - + if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) TapeDevice.EndFrame(); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs new file mode 100644 index 0000000000..72bd3bc3ba --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -0,0 +1,1008 @@ +using BizHawk.Common; +using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + /// + /// 3rd attempt at a base ULA implementation + /// + public abstract class ULA : IVideoProvider + { + #region Other Devices + + /// + /// The emulated spectrum + /// + protected SpectrumBase _machine; + + /// + /// The CPU monitor class + /// + protected CPUMonitor CPUMon; + + #endregion + + #region Construction & Initialisation + + public ULA (SpectrumBase machine) + { + _machine = machine; + CPUMon = _machine.CPUMon; + borderType = _machine.Spectrum.SyncSettings.BorderType; + } + + #endregion + + #region Palettes + + /// + /// The standard ULA palette + /// + private static readonly int[] ULAPalette = + { + Colors.ARGB(0x00, 0x00, 0x00), // Black + Colors.ARGB(0x00, 0x00, 0xD7), // Blue + Colors.ARGB(0xD7, 0x00, 0x00), // Red + Colors.ARGB(0xD7, 0x00, 0xD7), // Magenta + Colors.ARGB(0x00, 0xD7, 0x00), // Green + Colors.ARGB(0x00, 0xD7, 0xD7), // Cyan + Colors.ARGB(0xD7, 0xD7, 0x00), // Yellow + Colors.ARGB(0xD7, 0xD7, 0xD7), // White + Colors.ARGB(0x00, 0x00, 0x00), // Bright Black + Colors.ARGB(0x00, 0x00, 0xFF), // Bright Blue + Colors.ARGB(0xFF, 0x00, 0x00), // Bright Red + Colors.ARGB(0xFF, 0x00, 0xFF), // Bright Magenta + Colors.ARGB(0x00, 0xFF, 0x00), // Bright Green + Colors.ARGB(0x00, 0xFF, 0xFF), // Bright Cyan + Colors.ARGB(0xFF, 0xFF, 0x00), // Bright Yellow + Colors.ARGB(0xFF, 0xFF, 0xFF), // Bright White + }; + + #endregion + + #region Timing + + /// + /// The CPU speed + /// + public int ClockSpeed; + + /// + /// Length of frame in T-State cycles + /// + public int FrameCycleLength; + + /// + /// The T-State at which the interrupt should be raised within the frame + /// + public int InterruptStartTime; + + /// + /// The period for which the interrupt should he held + /// (simulated /INT pin held low) + /// + public int InterruptLength; + + /// + /// The time in T-States for one scanline to complete + /// + public int ScanlineTime; + + /// + /// T-States at the left border + /// + public int BorderLeftTime; + + /// + /// T-States at the right border + /// + public int BorderRightTime; + + public int FirstPaperLine; + public int FirstPaperTState; + public bool Border4T; + public int Border4TStage; + + #endregion + + #region Interrupt Generation + + /// + /// Signs that an interrupt has been raised in this frame. + /// + protected bool InterruptRaised; + + /// + /// Signs that the interrupt signal has been revoked + /// + protected bool InterruptRevoked; + + /// + /// Resets the interrupt - this should happen every frame in order to raise + /// the VBLANK interrupt in the proceding frame + /// + public virtual void ResetInterrupt() + { + InterruptRaised = false; + InterruptRevoked = false; + } + + /// + /// Generates an interrupt in the current phase if needed + /// + /// + public virtual void CheckForInterrupt(long currentCycle) + { + if (InterruptRevoked) + { + // interrupt has already been handled + return; + } + + if (currentCycle < InterruptStartTime) + { + // interrupt does not need to be raised yet + return; + } + + if (currentCycle >= InterruptStartTime + InterruptLength) + { + // interrupt should have already been raised and the cpu may or + // may not have caught it. The time has passed so revoke the signal + InterruptRevoked = true; + _machine.CPU.FlagI = false; + return; + } + + if (InterruptRaised) + { + // INT is raised but not yet revoked + // CPU has NOT handled it yet + return; + } + + // Raise the interrupt + InterruptRaised = true; + _machine.CPU.FlagI = true; + + CalcFlashCounter(); + } + + /// + /// Flash processing + /// + public void CalcFlashCounter() + { + flashCounter++; + + if (flashCounter > 15) + { + flashOn = !flashOn; + flashCounter = 0; + } + } + + #endregion + + #region Screen Layout + + /// + /// Total pixels in one display row + /// + protected int ScreenWidth; + /// + /// Total pixels in one display column + /// + protected int ScreenHeight; + /// + /// Total pixels in top border + /// + protected int BorderTopHeight; + /// + /// Total pixels in bottom border + /// + protected int BorderBottomHeight; + /// + /// Total pixels in left border width + /// + protected int BorderLeftWidth; + /// + /// Total pixels in right border width + /// + protected int BorderRightWidth; + /// + /// Total pixels in one scanline + /// + protected int ScanLineWidth; + + #endregion + + #region State + + /// + /// The last T-State cycle at which the screen was rendered + /// + public int LastTState; + + /// + /// Flash state + /// + public bool flashOn; + + private int flashCounter; + + protected byte fetchB1; + protected byte fetchA1; + protected byte fetchB2; + protected byte fetchA2; + protected int ink; + protected int paper; + protected int fetchBorder; + protected int bright; + protected int flash; + + public int palPaper; + public int palInk; + + public int BorderColor = 7; + + #endregion + + #region Conversions + + public int FrameLength => FrameCycleLength; + + #endregion + + #region Rendering Configuration + + /// + /// Holds all information regarding rendering the screen based on the current T-State + /// + public RenderTable RenderingTable; + + /// + /// Holds all information regarding rendering the screen based on the current T-State + /// + public class RenderTable + { + /// + /// The ULA device + /// + private ULA _ula; + + /// + /// Array of rendercycle entries + /// Starting from the interrupt + /// + public RenderCycle[] Renderer; + + /// + /// The emulated machine + /// + public MachineType _machineType; + + /// + /// Constructor + /// + /// + public RenderTable(ULA ula, MachineType machineType) + { + _ula = ula; + _machineType = machineType; + Renderer = new RenderCycle[_ula.FrameCycleLength]; + InitRenderer(machineType); + } + + /// + /// Initializes the renderer + /// + /// + private void InitRenderer(MachineType machineType) + { + for (var t = 0; t < _ula.FrameCycleLength; t++) + { + var tStateScreen = t + _ula.InterruptStartTime; + + if (tStateScreen < 0) + tStateScreen += _ula.FrameCycleLength; + else if (tStateScreen >= _ula.FrameCycleLength) + tStateScreen -= _ula.FrameCycleLength; + + CalculateRenderItem(t, tStateScreen / _ula.ScanlineTime, tStateScreen % _ula.ScanlineTime); + } + + CreateContention(machineType); + } + + private void CalculateRenderItem(int item, int line, int pix) + { + Renderer[item] = new RenderCycle(); + + Renderer[item].RAction = RenderAction.None; + int pitchWidth = _ula.ScreenWidth + _ula.BorderRightWidth + _ula.BorderLeftWidth; + + int scrPix = pix - _ula.FirstPaperTState; + int scrLin = line - _ula.FirstPaperLine; + + if ((line >= (_ula.FirstPaperLine - _ula.BorderTopHeight)) && (line < (_ula.FirstPaperLine + 192 + _ula.BorderBottomHeight)) && + (pix >= (_ula.FirstPaperTState - _ula.BorderLeftTime)) && (pix < (_ula.FirstPaperTState + 128 + _ula.BorderRightTime))) + { + // visibleArea (vertical) + if ((line >= _ula.FirstPaperLine) && (line < (_ula.FirstPaperLine + 192)) && + (pix >= _ula.FirstPaperTState) && (pix < (_ula.FirstPaperTState + 128))) + { + // pixel area + switch (scrPix & 7) + { + case 0: + Renderer[item].RAction = RenderAction.Shift1AndFetchByte2; // shift 1 + fetch B2 + // +4 = prefetch! + Renderer[item].ByteAddress = CalculateByteAddress(scrPix + 4, scrLin); + break; + case 1: + Renderer[item].RAction = RenderAction.Shift1AndFetchAttribute2; // shift 1 + fetch A2 + // +3 = prefetch! + Renderer[item].AttributeAddress = CalculateAttributeAddress(scrPix + 3, scrLin); + break; + case 2: + Renderer[item].RAction = RenderAction.Shift1; // shift 1 + break; + case 3: + Renderer[item].RAction = RenderAction.Shift1Last; // shift 1 (last) + break; + case 4: + Renderer[item].RAction = RenderAction.Shift2; // shift 2 + break; + case 5: + Renderer[item].RAction = RenderAction.Shift2; // shift 2 + break; + case 6: + if (pix < (_ula.FirstPaperTState + 128 - 2)) + { + Renderer[item].RAction = RenderAction.Shift2AndFetchByte1; // shift 2 + fetch B2 + } + else + { + Renderer[item].RAction = RenderAction.Shift2; // shift 2 + } + + // +2 = prefetch! + Renderer[item].ByteAddress = CalculateByteAddress(scrPix + 2, scrLin); + break; + case 7: + if (pix < (_ula.FirstPaperTState + 128 - 2)) + { + //??? + Renderer[item].RAction = RenderAction.Shift2AndFetchAttribute1; // shift 2 + fetch A2 + } + else + { + Renderer[item].RAction = RenderAction.Shift2; // shift 2 + } + + // +1 = prefetch! + Renderer[item].AttributeAddress = CalculateAttributeAddress(scrPix + 1, scrLin); + break; + } + } + else if ((line >= _ula.FirstPaperLine) && (line < (_ula.FirstPaperLine + 192)) && + (pix == (_ula.FirstPaperTState - 2))) // border & fetch B1 + { + Renderer[item].RAction = RenderAction.BorderAndFetchByte1; // border & fetch B1 + // +2 = prefetch! + Renderer[item].ByteAddress = CalculateByteAddress(scrPix + 2, scrLin); + } + else if ((line >= _ula.FirstPaperLine) && (line < (_ula.FirstPaperLine + 192)) && + (pix == (_ula.FirstPaperTState - 1))) // border & fetch A1 + { + Renderer[item].RAction = RenderAction.BorderAndFetchAttribute1; // border & fetch A1 + // +1 = prefetch! + Renderer[item].AttributeAddress = CalculateAttributeAddress(scrPix + 1, scrLin); + } + else + { + Renderer[item].RAction = RenderAction.Border; // border + } + + int wy = line - (_ula.FirstPaperLine - _ula.BorderTopHeight); + int wx = (pix - (_ula.FirstPaperTState - _ula.BorderLeftTime)) * 2; + Renderer[item].LineOffset = wy * pitchWidth + wx; + } + } + + private void CreateContention(MachineType machineType) + { + int[] conPattern = new int[8]; + + switch (machineType) + { + case MachineType.ZXSpectrum16: + case MachineType.ZXSpectrum48: + case MachineType.ZXSpectrum128: + case MachineType.ZXSpectrum128Plus2: + conPattern = new int[] { 6, 5, 4, 3, 2, 1, 0, 0 }; + break; + + case MachineType.ZXSpectrum128Plus2a: + case MachineType.ZXSpectrum128Plus3: + conPattern = new int[] { 1, 0, 7, 6, 5, 4, 3, 2 }; + break; + } + + // calculate contention values + for (int t = 0; t < _ula.FrameCycleLength; t++) + { + int shifted = (t + 1) + _ula.InterruptStartTime; + if (shifted < 0) + shifted += _ula.FrameCycleLength; + shifted %= _ula.FrameCycleLength; + + Renderer[t].ContentionValue = 0; + + int line = shifted / _ula.ScanlineTime; + int pix = shifted % _ula.ScanlineTime; + if (line < _ula.FirstPaperLine || line >= (_ula.FirstPaperLine + 192)) + { + Renderer[t].ContentionValue = 0; + continue; + } + int scrPix = pix - _ula.FirstPaperTState; + if (scrPix < 0 || scrPix >= 128) + { + Renderer[t].ContentionValue = 0; + continue; + } + int pixByte = scrPix % 8; + + Renderer[t].ContentionValue = conPattern[pixByte]; + } + + // calculate floating bus values + for (int t = 0; t < _ula.FrameCycleLength; t++) + { + int shifted = (t + 1) + _ula.InterruptStartTime; + if (shifted < 0) + shifted += _ula.FrameCycleLength; + shifted %= _ula.FrameCycleLength; + + Renderer[t].FloatingBusAddress = 0; + + int line = shifted / _ula.ScanlineTime; + int pix = shifted % _ula.ScanlineTime; + if (line < _ula.FirstPaperLine || line >= (_ula.FirstPaperLine + 192)) + { + Renderer[t].FloatingBusAddress = 0; + continue; + } + int scrPix = pix - _ula.FirstPaperTState; + if (scrPix < 0 || scrPix >= 128) + { + Renderer[t].FloatingBusAddress = 0; + continue; + } + + int pixByte = scrPix % 8; + int chunk = scrPix % 16; + + switch (chunk) + { + case 0: + case 2: + Renderer[t].FloatingBusAddress = CalculateByteAddress(scrPix, line); + break; + case 1: + case 3: + Renderer[t].FloatingBusAddress = CalculateAttributeAddress(scrPix, line); + break; + } + } + } + + private ushort CalculateByteAddress(int x, int y) + { + x >>= 2; + var vp = x | (y << 5); + return (ushort)((vp & 0x181F) | ((vp & 0x0700) >> 3) | ((vp & 0x00E0) << 3)); + } + + private ushort CalculateAttributeAddress(int x, int y) + { + x >>= 2; + var ap = x | ((y >> 3) << 5); + return (ushort)(6144 + ap); + } + + /// + /// Render/contention information for a single T-State + /// + public class RenderCycle + { + /// + /// The ULA render action at this T-State + /// + public RenderAction RAction; + /// + /// The contention value at this T-State + /// + public int ContentionValue; + /// + /// The screen byte address at this T-State + /// + public ushort ByteAddress; + /// + /// The screen attribute address at this T-State + /// + public ushort AttributeAddress; + /// + /// The byte address returned by the floating bus at this T-State + /// + public ushort FloatingBusAddress; + /// + /// The offset + /// + public int LineOffset; + } + + public enum RenderAction + { + None, + Border, + BorderAndFetchByte1, + BorderAndFetchAttribute1, + Shift1AndFetchByte2, + Shift1AndFetchAttribute2, + Shift1, + Shift1Last, + Shift2, + Shift2Last, + Shift2AndFetchByte1, + Shift2AndFetchAttribute1 + } + } + + #endregion + + #region Render Methods + + /// + /// Renders to the screen buffer based on the current cycle + /// + /// + public void RenderScreen(int toCycle) + { + // check boundaries + if (toCycle > FrameCycleLength) + toCycle = FrameCycleLength; + if (LastTState > toCycle) + LastTState = 0; + + // render the required number of cycles + for (int t = LastTState; t < toCycle; t++) + { + if (!Border4T || (t & 3) == Border4TStage) + { + fetchBorder = BorderColor; + } + else + { + + } + + //fetchBorder = BorderColor; + + // get the table entry + var item = RenderingTable.Renderer[t]; + + switch (item.RAction) + { + case RenderTable.RenderAction.None: + break; + + case RenderTable.RenderAction.Border: + ScreenBuffer[item.LineOffset] = ULAPalette[fetchBorder]; + ScreenBuffer[item.LineOffset + 1] = ULAPalette[fetchBorder]; + break; + + case RenderTable.RenderAction.BorderAndFetchByte1: + ScreenBuffer[item.LineOffset] = ULAPalette[fetchBorder]; + ScreenBuffer[item.LineOffset + 1] = ULAPalette[fetchBorder]; + fetchB1 = _machine.FetchScreenMemory(item.ByteAddress); + break; + + case RenderTable.RenderAction.BorderAndFetchAttribute1: + ScreenBuffer[item.LineOffset] = ULAPalette[fetchBorder]; + ScreenBuffer[item.LineOffset + 1] = ULAPalette[fetchBorder]; + fetchA1 = _machine.FetchScreenMemory(item.AttributeAddress); + ProcessInkPaper(fetchA1); + break; + + case RenderTable.RenderAction.Shift1AndFetchByte2: + ScreenBuffer[item.LineOffset] = ((fetchB1 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB1 & 0x40) != 0) ? palInk : palPaper; + fetchB1 <<= 2; + fetchB2 = _machine.FetchScreenMemory(item.ByteAddress); + break; + + case RenderTable.RenderAction.Shift1AndFetchAttribute2: + ScreenBuffer[item.LineOffset] = ((fetchB1 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB1 & 0x40) != 0) ? palInk : palPaper; + fetchB1 <<= 2; + fetchA2 = _machine.FetchScreenMemory(item.AttributeAddress); + break; + + case RenderTable.RenderAction.Shift1: + ScreenBuffer[item.LineOffset] = ((fetchB1 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB1 & 0x40) != 0) ? palInk : palPaper; + fetchB1 <<= 2; + break; + + case RenderTable.RenderAction.Shift1Last: + ScreenBuffer[item.LineOffset] = ((fetchB1 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB1 & 0x40) != 0) ? palInk : palPaper; + fetchB1 <<= 2; + ProcessInkPaper(fetchA2); + break; + + case RenderTable.RenderAction.Shift2: + ScreenBuffer[item.LineOffset] = ((fetchB2 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB2 & 0x40) != 0) ? palInk : palPaper; + fetchB2 <<= 2; + break; + + case RenderTable.RenderAction.Shift2AndFetchByte1: + ScreenBuffer[item.LineOffset] = ((fetchB2 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB2 & 0x40) != 0) ? palInk : palPaper; + fetchB2 <<= 2; + fetchB1 = _machine.FetchScreenMemory(item.ByteAddress); + break; + + case RenderTable.RenderAction.Shift2AndFetchAttribute1: + ScreenBuffer[item.LineOffset] = ((fetchB2 & 0x80) != 0) ? palInk : palPaper; + ScreenBuffer[item.LineOffset + 1] = ((fetchB2 & 0x40) != 0) ? palInk : palPaper; + fetchB2 <<= 2; + fetchA1 = _machine.FetchScreenMemory(item.AttributeAddress); + ProcessInkPaper(fetchA1); + break; + } + } + + LastTState = toCycle; + } + + private void ProcessInkPaper(byte attrData) + { + bright = (attrData & 0x40) >> 3; + flash = (attrData & 0x80) >> 7; + ink = (attrData & 0x07); + paper = ((attrData >> 3) & 0x7); + + palInk = ULAPalette[ink + bright]; + palPaper = ULAPalette[paper + bright]; + + // swap paper and ink when flash is on + if (flashOn && (flash != 0)) + { + int temp = palInk; + palInk = palPaper; + palPaper = temp; + } + } + + /// + /// Returns floating bus value (if available) + /// + /// + /// + public void ReadFloatingBus(int tstate, ref int result) + { + var item = RenderingTable.Renderer[tstate]; + + switch (RenderingTable._machineType) + { + case MachineType.ZXSpectrum16: + case MachineType.ZXSpectrum48: + case MachineType.ZXSpectrum128: + case MachineType.ZXSpectrum128Plus2: + /* + if (item.FloatingBusAddress > 0) + { + result = _machine.FetchScreenMemory(item.FloatingBusAddress); + //result = 0x00; + } + */ + switch (item.RAction) + { + case RenderTable.RenderAction.BorderAndFetchByte1: + case RenderTable.RenderAction.Shift1AndFetchByte2: + case RenderTable.RenderAction.Shift2AndFetchByte1: + result = _machine.FetchScreenMemory(item.ByteAddress); + break; + case RenderTable.RenderAction.BorderAndFetchAttribute1: + case RenderTable.RenderAction.Shift1AndFetchAttribute2: + case RenderTable.RenderAction.Shift2AndFetchAttribute1: + result = _machine.FetchScreenMemory(item.AttributeAddress); + break; + default: + //result = _machine.FetchScreenMemory(fetchA2); + break; + } + + + break; + + case MachineType.ZXSpectrum128Plus2a: + case MachineType.ZXSpectrum128Plus3: + break; + } + } + + #endregion + + #region Contention + + /// + /// Returns the contention value for the current t-state + /// + /// + public int GetContentionValue() + { + return RenderingTable.Renderer[_machine.CurrentFrameCycle].ContentionValue; + } + + /// + /// Returns the contention value for the supplied t-state + /// + /// + public int GetContentionValue(int tstate) + { + if (tstate >= FrameCycleLength) + tstate -= FrameCycleLength; + + if (tstate < 0) + tstate += FrameCycleLength; + + return RenderingTable.Renderer[tstate].ContentionValue; + } + + #endregion + + #region IVideoProvider + + /// + /// Video output buffer + /// + public int[] ScreenBuffer; + + private int _virtualWidth; + private int _virtualHeight; + private int _bufferWidth; + private int _bufferHeight; + + public int BackgroundColor + { + get { return ULAPalette[7]; } //ULAPalette[borderColour]; } + } + + public int VirtualWidth + { + get { return _virtualWidth; } + set { _virtualWidth = value; } + } + + public int VirtualHeight + { + get { return _virtualHeight; } + set { _virtualHeight = value; } + } + + public int BufferWidth + { + get { return _bufferWidth; } + set { _bufferWidth = value; } + } + + public int BufferHeight + { + get { return _bufferHeight; } + set { _bufferHeight = value; } + } + + public int VsyncNumerator + { + get { return ClockSpeed * 50; }// ClockSpeed; } + set { } + } + + public int VsyncDenominator + { + get { return ClockSpeed; }//FrameLength; } + } + + public int[] GetVideoBuffer() + { + switch (borderType) + { + // Full side borders, no top or bottom border (giving *almost* 16:9 output) + case ZXSpectrum.BorderType.Widescreen: + // we are cropping out the top and bottom borders + var startPixelsToCrop = ScanLineWidth * BorderTopHeight; + var endPixelsToCrop = ScanLineWidth * BorderBottomHeight; + int index = 0; + for (int i = startPixelsToCrop; i < ScreenBuffer.Length - endPixelsToCrop; i++) + { + croppedBuffer[index++] = ScreenBuffer[i]; + } + return croppedBuffer; + + // The full spectrum border + case ZXSpectrum.BorderType.Full: + return ScreenBuffer; + + case ZXSpectrum.BorderType.Medium: + // all border sizes now 24 + var lR = BorderLeftWidth - 24; + var rR = BorderRightWidth - 24; + var tR = BorderTopHeight - 24; + var bR = BorderBottomHeight - 24; + var startP = ScanLineWidth * tR; + var endP = ScanLineWidth * bR; + + int index2 = 0; + // line by line + for (int i = startP; i < ScreenBuffer.Length - endP; i += ScreenWidth + BorderLeftWidth + BorderRightWidth) + { + // each pixel in each line + for (int p = lR; p < ScreenWidth + BorderLeftWidth + BorderRightWidth - rR; p++) + { + if (index2 == croppedBuffer.Length) + break; + croppedBuffer[index2++] = ScreenBuffer[i + p]; + } + } + + return croppedBuffer; + + case ZXSpectrum.BorderType.Small: + // all border sizes now 24 + var lR_ = BorderLeftWidth - 10; + var rR_ = BorderRightWidth - 10; + var tR_ = BorderTopHeight - 10; + var bR_ = BorderBottomHeight - 10; + var startP_ = ScanLineWidth * tR_; + var endP_ = ScanLineWidth * bR_; + + int index2_ = 0; + // line by line + for (int i = startP_; i < ScreenBuffer.Length - endP_; i += ScreenWidth + BorderLeftWidth + BorderRightWidth) + { + // each pixel in each line + for (int p = lR_; p < ScreenWidth + BorderLeftWidth + BorderRightWidth - rR_; p++) + { + if (index2_ == croppedBuffer.Length) + break; + croppedBuffer[index2_++] = ScreenBuffer[i + p]; + } + } + + return croppedBuffer; + + case ZXSpectrum.BorderType.None: + // all border sizes now 24 + var lR__ = BorderLeftWidth; + var rR__ = BorderRightWidth; + var tR__ = BorderTopHeight; + var bR__ = BorderBottomHeight; + var startP__ = ScanLineWidth * tR__; + var endP__ = ScanLineWidth * bR__; + + int index2__ = 0; + // line by line + for (int i = startP__; i < ScreenBuffer.Length - endP__; i += ScreenWidth + BorderLeftWidth + BorderRightWidth) + { + // each pixel in each line + for (int p = lR__; p < ScreenWidth + BorderLeftWidth + BorderRightWidth - rR__; p++) + { + if (index2__ == croppedBuffer.Length) + break; + croppedBuffer[index2__++] = ScreenBuffer[i + p]; + } + } + + return croppedBuffer; + } + + return ScreenBuffer; + } + + protected void SetupScreenSize() + { + switch (borderType) + { + case ZXSpectrum.BorderType.Full: + BufferWidth = ScreenWidth + BorderLeftWidth + BorderRightWidth; + BufferHeight = ScreenHeight + BorderTopHeight + BorderBottomHeight; + VirtualHeight = BufferHeight; + VirtualWidth = BufferWidth; + ScreenBuffer = new int[BufferWidth * BufferHeight]; + break; + + case ZXSpectrum.BorderType.Widescreen: + BufferWidth = ScreenWidth + BorderLeftWidth + BorderRightWidth; + BufferHeight = ScreenHeight; + VirtualHeight = BufferHeight; + VirtualWidth = BufferWidth; + croppedBuffer = new int[BufferWidth * BufferHeight]; + break; + + case ZXSpectrum.BorderType.Medium: + BufferWidth = ScreenWidth + (24) + (24); + BufferHeight = ScreenHeight + (24) + (24); + VirtualHeight = BufferHeight; + VirtualWidth = BufferWidth; + croppedBuffer = new int[BufferWidth * BufferHeight]; + break; + + case ZXSpectrum.BorderType.Small: + BufferWidth = ScreenWidth + (10) + (10); + BufferHeight = ScreenHeight + (10) + (10); + VirtualHeight = BufferHeight; + VirtualWidth = BufferWidth; + croppedBuffer = new int[BufferWidth * BufferHeight]; + break; + + case ZXSpectrum.BorderType.None: + BufferWidth = ScreenWidth; + BufferHeight = ScreenHeight; + VirtualHeight = BufferHeight; + VirtualWidth = BufferWidth; + croppedBuffer = new int[BufferWidth * BufferHeight]; + break; + } + } + + protected int[] croppedBuffer; + + private ZXSpectrum.BorderType _borderType; + + public ZXSpectrum.BorderType borderType + { + get { return _borderType; } + set { _borderType = value; } + } + + #endregion + + #region Serialization + + public void SyncState(Serializer ser) + { + ser.BeginSection("ULA"); + ser.Sync("ScreenBuffer", ref ScreenBuffer, false); + ser.Sync("FrameLength", ref FrameCycleLength); + ser.Sync("ClockSpeed", ref ClockSpeed); + ser.Sync("BorderColor", ref BorderColor); + ser.Sync("LastTState", ref LastTState); + ser.Sync("flashOn", ref flashOn); + ser.Sync("fetchB1", ref fetchB1); + ser.Sync("fetchA1", ref fetchA1); + ser.Sync("fetchB2", ref fetchB2); + ser.Sync("fetchA2", ref fetchA2); + ser.Sync("ink", ref ink); + ser.Sync("paper", ref paper); + ser.Sync("fetchBorder", ref fetchBorder); + ser.Sync("bright", ref bright); + ser.Sync("flash", ref flash); + ser.Sync("palPaper", ref palPaper); + ser.Sync("palInk", ref palInk); + ser.EndSection(); + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULABase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULABase.cs index 7f479eb635..c7361f27cb 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULABase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULABase.cs @@ -4,6 +4,7 @@ using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { + /* /// /// ULA (Uncommitted Logic Array) implementation /// @@ -78,6 +79,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public byte[] contentionTable; + /// + /// Contention offset (used for testing) + /// + public int contentionOffset = 0; // -5; + #endregion #region Screen Rendering @@ -86,6 +92,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// Video output buffer /// public int[] ScreenBuffer; + + /// + /// Screen rendering T-State info + /// + public RenderCycle[] RenderTable; + /// /// Display memory /// @@ -246,14 +258,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #region Interrupt /// - /// The number of T-States that the INT pin is simulated to be held low + /// The t-state within the frame that an interrupt is raised /// - public int InterruptPeriod; + public int InterruptStart; /// - /// The longest instruction cycle count + /// The number of T-States that the INT pin is simulated to be held low /// - protected int LongestOperationCycles = 23; + public int InterruptDuration = 32; /// /// Signs that an interrupt has been raised in this frame. @@ -287,13 +299,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return; } - if (currentCycle < LongestOperationCycles)// InterruptPeriod) + if (currentCycle < InterruptStart) { // interrupt does not need to be raised yet return; } - if (currentCycle >= InterruptPeriod + LongestOperationCycles) + if (currentCycle > InterruptStart + InterruptDuration) { // interrupt should have already been raised and the cpu may or // may not have caught it. The time has passed so revoke the signal @@ -350,31 +362,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// public abstract bool IsContended(int addr); - - /// - /// Contends the machine for a given address - /// - /// - public virtual void Contend(ushort addr) - { - if (IsContended(addr) && !(_machine is ZX128Plus3)) - { - _machine.CPU.TotalExecutedCycles += contentionTable[CurrentTStateInFrame]; - } - } - - public virtual void Contend(int addr, int time, int count) - { - if (IsContended(addr) && !(_machine is ZX128Plus3)) - { - for (int f = 0; f < count; f++) - { - _machine.CPU.TotalExecutedCycles += contentionTable[CurrentTStateInFrame] + time; - } - } - else - _machine.CPU.TotalExecutedCycles += count * time; - } + /// /// Resets render state once interrupt is generated @@ -401,6 +389,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } } + /// /// Builds the T-State to attribute map used with the floating bus /// @@ -426,6 +415,32 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } } + /// + /// Returns the floating bus value + /// + public virtual void ReadFloatingBus(ref int result) + { + // Floating bus is read on the previous cycle + long _tStates = _machine.CurrentFrameCycle - 1; + + // if we are on the top or bottom border return 0xff + if ((_tStates < contentionStartPeriod) || (_tStates > contentionEndPeriod)) + { + result = 0xff; + } + else + { + if (floatingBusTable[_tStates] < 0) + { + result = 0xff; + } + else + { + result = _machine.ReadBus((ushort)floatingBusTable[_tStates]); + } + } + } + /// /// Updates the screen buffer based on the number of T-States supplied /// @@ -444,7 +459,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } //the additional 1 tstate is required to get correct number of bytes to output in ircontention.sna - elapsedTStates = (_tstates + 1 - lastTState) - 1; + elapsedTStates = (_tstates + 1 - lastTState); //It takes 4 tstates to write 1 byte. Or, 2 pixels per t-state. @@ -755,6 +770,27 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + /* #endregion } + + /// + /// T-State display mapping + /// + public class RenderCycle + { + public RenderType Type { get; set; } + public short DisplayAddress { get; set; } + public short AttributeAddress { get; set; } + public int ContentionValue { get; set; } + public short FloatingBusAddress { get; set; } + } + + public enum RenderType + { + None, + Border, + Display + } + */ } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs index e769fc46ef..3ab198737e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs @@ -175,10 +175,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum default: break; } - - // update ULA screen buffer if necessary - if ((addr & 49152) == 16384 && _render) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); } /// @@ -189,9 +185,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + ContendMemory(addr); + var data = ReadBus(addr); return data; } @@ -204,13 +199,56 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { - // apply contention if necessary - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; + // update ULA screen buffer if necessary BEFORE T1 write + if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render) + ULADevice.RenderScreen((int)CurrentFrameCycle); + ContendMemory(addr); WriteBus(addr, value); } - + + /// + /// Contends memory if necessary + /// + public override void ContendMemory(ushort addr) + { + if (IsContended(addr)) + { + var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); + CPU.TotalExecutedCycles += delay; + } + } + + /// + /// Checks whether supplied address is in a potentially contended bank + /// + /// + public override bool IsContended(ushort addr) + { + var a = addr & 0xc000; + + if (a == 0x4000) + { + // low port contention + return true; + } + + if (a == 0xc000) + { + // high port contention - check for contended bank paged in + switch (RAMPaged) + { + case 1: + case 3: + case 5: + case 7: + return true; + } + } + + return false; + } + /// /// ULA reads the memory at the specified address /// (No memory contention) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index f88922132c..68639979e9 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum bool deviceAddressed = true; // process IO contention - ContendPortAddress(port); + ContendPort(port); int result = 0xFF; @@ -56,6 +56,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // Floating bus is read on the previous cycle long _tStates = CurrentFrameCycle - 1; + ULADevice.ReadFloatingBus((int)_tStates, ref result); + + /* // if we are on the top or bottom border return 0xff if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) { @@ -72,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); } } + */ } return (byte)result; @@ -85,7 +89,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WritePort(ushort port, byte value) { // process IO contention - ContendPortAddress(port); + ContendPort(port); // get a BitArray of the port BitArray portBits = new BitArray(BitConverter.GetBytes(port)); @@ -142,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { // store the last OUT byte LastULAOutByte = value; - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; + CPU.TotalExecutedCycles += ULADevice.GetContentionValue(); /* Bit 7 6 5 4 3 2 1 0 @@ -152,10 +156,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.borderColour != (value & BORDER_BIT)) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); + if (ULADevice.BorderColor != (value & BORDER_BIT)) + ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.borderColour = value & BORDER_BIT; + ULADevice.BorderColor = value & BORDER_BIT; // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); @@ -165,5 +169,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum //TapeDevice.ProcessMicBit((value & MIC_BIT) != 0); } } + + /// + /// Contend port if necessary + /// + /// + public override void ContendPort(ushort addr) + { + throw new NotImplementedException(); + } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs index 59d9108290..2228ed82c1 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs @@ -1,6 +1,7 @@  namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { + /* class ULA128 : ULABase { #region Construction @@ -8,8 +9,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ULA128(SpectrumBase machine) : base(machine) { - InterruptPeriod = 36; - LongestOperationCycles = 64 + 2; + InterruptStart = 0; + //LongestOperationCycles = 64 + 2; FrameLength = 70908; ClockSpeed = 3546900; @@ -189,4 +190,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } + */ } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs index 74b6744893..fc2369a3a1 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs @@ -21,12 +21,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum Spectrum = spectrum; CPU = cpu; + CPUMon = new CPUMonitor(this); + CPUMon.machineType = MachineType.ZXSpectrum128; + ROMPaged = 0; SHADOWPaged = false; RAMPaged = 0; PagingDisabled = false; - ULADevice = new ULA128(this); + //ULADevice = new ULA128(this); + ULADevice = new Screen48(this); // still todo BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs index 265a413002..26ae8ef939 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs @@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // update ULA screen buffer if necessary if ((addr & 49152) == 16384 && _render) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); + ULADevice.RenderScreen((int)CurrentFrameCycle); } /// @@ -355,9 +355,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + ContendMemory(addr); + var data = ReadBus(addr); return data; } @@ -370,13 +369,74 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { - // apply contention if necessary - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + // update ULA screen buffer if necessary BEFORE T1 write + if (!SpecialPagingMode) + { + if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render) + ULADevice.RenderScreen((int)CurrentFrameCycle); + } + else + { + switch (PagingConfiguration) + { + case 2: + case 3: + if ((addr & 49152) == 16384) + ULADevice.RenderScreen((int)CurrentFrameCycle); + break; + case 1: + if ((addr & 49152) == 16384 || addr >= 0xc000) + ULADevice.RenderScreen((int)CurrentFrameCycle); + break; + } + } + + ContendMemory(addr); WriteBus(addr, value); } - + + /// + /// Contends memory if necessary + /// + public override void ContendMemory(ushort addr) + { + if (IsContended(addr)) + { + var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); + CPU.TotalExecutedCycles += delay; + } + } + + /// + /// Checks whether supplied address is in a potentially contended bank + /// + /// + public override bool IsContended(ushort addr) + { + var a = addr & 0xc000; + + if (a == 0x4000) + { + // low port contention + return true; + } + + if (a == 0xc000) + { + // high port contention - check for contended bank paged in + switch (RAMPaged) + { + case 4: + case 5: + case 6: + case 7: + return true; + } + } + + return false; + } + /// /// ULA reads the memory at the specified address /// (No memory contention) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index 64ec430ef0..3eb942d51f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum bool deviceAddressed = true; // process IO contention - ContendPortAddress(port); + ContendPort(port); int result = 0xFF; @@ -56,6 +56,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // Floating bus is read on the previous cycle long _tStates = CurrentFrameCycle - 1; + ULADevice.ReadFloatingBus((int)_tStates, ref result); + /* // if we are on the top or bottom border return 0xff if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) { @@ -72,6 +74,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); } } + */ } /* // Check whether the low bit is reset @@ -158,7 +161,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WritePort(ushort port, byte value) { // process IO contention - ContendPortAddress(port); + ContendPort(port); // get a BitArray of the port BitArray portBits = new BitArray(BitConverter.GetBytes(port)); @@ -241,10 +244,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.borderColour != (value & BORDER_BIT)) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); + if (ULADevice.BorderColor != (value & BORDER_BIT)) + ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.borderColour = value & BORDER_BIT; + ULADevice.BorderColor = value & BORDER_BIT; // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); @@ -281,13 +284,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } /// - /// Override port contention - /// +3/2a does not have the same ULA IO contention + /// Contend port if necessary /// /// - public override void ContendPortAddress(ushort addr) + public override void ContendPort(ushort addr) { - //CPU.TotalExecutedCycles += 4; + throw new NotImplementedException(); } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs index c6547833ad..e164f8b53a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs @@ -1,6 +1,7 @@  namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { + /* class ULAPlus2a : ULABase { #region Construction @@ -8,8 +9,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ULAPlus2a(SpectrumBase machine) : base(machine) { - InterruptPeriod = 36; - LongestOperationCycles = 64 + 2; + InterruptStart = 0; + //LongestOperationCycles = 64 + 2; FrameLength = 70908; ClockSpeed = 3546900; @@ -193,4 +194,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } + */ } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs index a6eec74beb..487cc386b4 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs @@ -21,12 +21,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum Spectrum = spectrum; CPU = cpu; + CPUMon = new CPUMonitor(this); + CPUMon.machineType = MachineType.ZXSpectrum128Plus2a; + ROMPaged = 0; SHADOWPaged = false; RAMPaged = 0; PagingDisabled = false; - ULADevice = new ULAPlus2a(this); + //ULADevice = new ULAPlus2a(this); + ULADevice = new Screen48(this); // still todo BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index bead71f975..68a3841244 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // update ULA screen buffer if necessary if ((addr & 49152) == 16384 && _render) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); + ULADevice.RenderScreen((int)CurrentFrameCycle); } /// @@ -355,9 +355,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + ContendMemory(addr); + var data = ReadBus(addr); return data; } @@ -370,13 +369,74 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { - // apply contention if necessary - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + // update ULA screen buffer if necessary BEFORE T1 write + if (!SpecialPagingMode) + { + if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render) + ULADevice.RenderScreen((int)CurrentFrameCycle); + } + else + { + switch (PagingConfiguration) + { + case 2: + case 3: + if ((addr & 49152) == 16384) + ULADevice.RenderScreen((int)CurrentFrameCycle); + break; + case 1: + if ((addr & 49152) == 16384 || addr >= 0xc000) + ULADevice.RenderScreen((int)CurrentFrameCycle); + break; + } + } + + ContendMemory(addr); WriteBus(addr, value); } - + + /// + /// Contends memory if necessary + /// + public override void ContendMemory(ushort addr) + { + if (IsContended(addr)) + { + var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); + CPU.TotalExecutedCycles += delay; + } + } + + /// + /// Checks whether supplied address is in a potentially contended bank + /// + /// + public override bool IsContended(ushort addr) + { + var a = addr & 0xc000; + + if (a == 0x4000) + { + // low port contention + return true; + } + + if (a == 0xc000) + { + // high port contention - check for contended bank paged in + switch (RAMPaged) + { + case 4: + case 5: + case 6: + case 7: + return true; + } + } + + return false; + } + /// /// ULA reads the memory at the specified address /// (No memory contention) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index 5aed81dd52..c3b53fff79 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum bool deviceAddressed = true; // process IO contention - ContendPortAddress(port); + ContendPort(port); int result = 0xFF; @@ -60,6 +60,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // Floating bus is read on the previous cycle long _tStates = CurrentFrameCycle - 1; + ULADevice.ReadFloatingBus((int)_tStates, ref result); + + /* + // if we are on the top or bottom border return 0xff if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) { @@ -76,6 +80,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); } } + */ } return (byte)result; @@ -89,7 +94,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WritePort(ushort port, byte value) { // process IO contention - ContendPortAddress(port); + ContendPort(port); // get a BitArray of the port BitArray portBits = new BitArray(BitConverter.GetBytes(port)); @@ -174,10 +179,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.borderColour != (value & BORDER_BIT)) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); + if (ULADevice.BorderColor != (value & BORDER_BIT)) + ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.borderColour = value & BORDER_BIT; + ULADevice.BorderColor = value & BORDER_BIT; // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); @@ -214,13 +219,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } /// - /// Override port contention - /// +3/2a does not have the same ULA IO contention + /// Contend port if necessary /// /// - public override void ContendPortAddress(ushort addr) + public override void ContendPort(ushort addr) { - //CPU.TotalExecutedCycles += 4; + throw new NotImplementedException(); } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs index 3b2291a082..9e0289d53e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs @@ -1,6 +1,7 @@  namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { + /* class ULAPlus3 : ULABase { #region Construction @@ -8,8 +9,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ULAPlus3(SpectrumBase machine) : base(machine) { - InterruptPeriod = 36; - LongestOperationCycles = 64 + 2; + InterruptStart = 0; + //LongestOperationCycles = 64 + 2; FrameLength = 70908; ClockSpeed = 3546900; @@ -193,4 +194,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } + */ } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs index 5b000e543e..decfb7466e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs @@ -20,13 +20,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { Spectrum = spectrum; CPU = cpu; + CPUMon.machineType = MachineType.ZXSpectrum128Plus3; + + CPUMon = new CPUMonitor(this); ROMPaged = 0; SHADOWPaged = false; RAMPaged = 0; PagingDisabled = false; - ULADevice = new ULAPlus3(this); + // ULADevice = new ULAPlus3(this); + ULADevice = new Screen48(this); // still todo BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs index 3f6499e916..1d9c7edc0b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs @@ -24,7 +24,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #endregion - #region Memory /* 48K Spectrum has NO memory paging @@ -88,11 +87,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case 1: RAM0[index] = value; break; - } - - // update ULA screen buffer if necessary - if ((addr & 49152) == 16384 && _render) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); + } } /// @@ -103,8 +98,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; + if (IsContended(addr)) + CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle); var data = ReadBus(addr); return data; @@ -119,8 +114,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WriteMemory(ushort addr, byte value) { // apply contention if necessary - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; + if (IsContended(addr)) + { + ULADevice.RenderScreen((int)CurrentFrameCycle); + CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle); + } WriteBus(addr, value); } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index 5f7958f4d9..624df29d2c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -86,10 +86,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum RAM2[index] = value; break; } - - // update ULA screen buffer if necessary - if ((addr & 49152) == 16384 && _render) - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); } /// @@ -100,9 +96,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + ContendMemory(addr); var data = ReadBus(addr); return data; } @@ -115,13 +109,41 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { - // apply contention if necessary - if (ULADevice.IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle]; - + // update ULA screen buffer if necessary BEFORE T1 write + if ((addr & 49152) == 16384 && _render) + ULADevice.RenderScreen((int)CurrentFrameCycle); + + ContendMemory(addr); WriteBus(addr, value); } + /// + /// Contends memory if necessary + /// + public override void ContendMemory(ushort addr) + { + if (IsContended(addr)) + { + var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); + if (delay > 0) + { + + } + CPU.TotalExecutedCycles += delay; + } + } + + /// + /// Checks whether supplied address is in a potentially contended bank + /// + /// + public override bool IsContended(ushort addr) + { + if ((addr & 49152) == 16384) + return true; + return false; + } + /// /// Sets up the ROM /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index 12f8850957..127feb84ae 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override byte ReadPort(ushort port) { // process IO contention - ContendPortAddress(port); + ContendPort(port); int result = 0xFF; @@ -56,6 +56,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // If this is an unused port the floating memory bus should be returned + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + + /* // Floating bus is read on the previous cycle long _tStates = CurrentFrameCycle - 1; @@ -75,6 +78,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); } } + */ } return (byte)result; @@ -88,7 +92,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WritePort(ushort port, byte value) { // process IO contention - ContendPortAddress(port); + ContendPort(port); // Check whether the low bit is reset // Technically the ULA should respond to every even I/O address @@ -106,13 +110,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.borderColour != (value & BORDER_BIT)) - { - // border value has changed - update the screen buffer - ULADevice.UpdateScreenBuffer(CurrentFrameCycle); - } - - ULADevice.borderColour = value & BORDER_BIT; + ULADevice.RenderScreen((int)CurrentFrameCycle); + ULADevice.BorderColor = value & BORDER_BIT; // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); @@ -124,6 +123,40 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum //TapeDevice.ProcessMicBit((value & MIC_BIT) != 0); } - + + /// + /// Simulates IO port contention based on the supplied address + /// This method is for 48k and 128k/+2 machines only and should be overridden for other models + /// + /// + public override void ContendPort(ushort addr) + { + /* + It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port. As is the case with memory access, + this can be lengthened by the ULA. There are two effects which occur here: + + If the port address being accessed has its low bit reset, the ULA is required to supply the result, which leads to a delay if it is + currently busy handling the screen. + The address of the port being accessed is placed on the data bus. If this is in the range 0x4000 to 0x7fff, the ULA treats this as an + attempted access to contended memory and therefore introduces a delay. If the port being accessed is between 0xc000 and 0xffff, + this effect does not apply, even on a 128K machine if a contended memory bank is paged into the range 0xc000 to 0xffff. + + These two effects combine to lead to the following contention patterns: + + High byte | | + in 40 - 7F? | Low bit | Contention pattern + ------------+---------+------------------- + No | Reset | N:1, C:3 + No | Set | N:4 + Yes | Reset | C:1, C:3 + Yes | Set | C:1, C:1, C:1, C:1 + + The 'Contention pattern' column should be interpreted from left to right. An "N:n" entry means that no delay is applied at this cycle, and the Z80 continues uninterrupted for 'n' T states. A "C:n" entry means that the ULA halts the Z80; the delay is exactly the same as would occur for a contended memory access at this cycle (eg 6 T states at cycle 14335, 5 at 14336, etc on the 48K machine). After this delay, the Z80 then continues for 'n' cycles. + */ + + CPUMon.ContendPort(addr); + return; + } + } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs new file mode 100644 index 0000000000..f1bc6f89ec --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + class Screen48 : ULA + { + #region Construction + + public Screen48(SpectrumBase machine) + : base(machine) + { + // timing + ClockSpeed = 3500000; + FrameCycleLength = 69888; + InterruptStartTime = 32; + InterruptLength = 32; + ScanlineTime = 224; + + BorderLeftTime = 24; + BorderRightTime = 24; + + FirstPaperLine = 64; + FirstPaperTState = 64; + + Border4T = true; + Border4TStage = 0; + + // screen layout + ScreenWidth = 256; + ScreenHeight = 192; + BorderTopHeight = 48; + BorderBottomHeight = 56; + BorderLeftWidth = 48; + BorderRightWidth = 48; + ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth; + + RenderingTable = new RenderTable(this, + MachineType.ZXSpectrum48); + + SetupScreenSize(); + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs index 3b4eca3dc3..03e10d9685 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs @@ -1,6 +1,9 @@  +using System.Linq; + namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { + /* class ULA48 : ULABase { #region Construction @@ -8,8 +11,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public ULA48(SpectrumBase machine) : base(machine) { - InterruptPeriod = 32; - LongestOperationCycles = 64; + InterruptStart = 0;// 5; // 0; // 3; // 0;// 32; + //LongestOperationCycles = 32; FrameLength = 69888; ClockSpeed = 3500000; @@ -55,7 +58,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void Reset() { - contentionStartPeriod = 14335; // + LateTiming; + contentionOffset = 0; + InterruptStart = 0; + + contentionStartPeriod = 14335;// + contentionOffset; // + LateTiming; contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline); screen = _machine.RAM0; screenByteCtr = DisplayStart; @@ -160,6 +166,30 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum h += TstatesPerScanline - 128; } + // offset floating bus table + var offset = 0; + + if (offset != 0) + { + var fbt = floatingBusTable.ToArray(); + for (int i = 0; i < FrameLength; i++) + { + var off = i + offset; + if (off < 0) + { + off = FrameLength - 1 + off; + } + else if (off >= FrameLength) + { + off = off - FrameLength; + } + + fbt[off] = floatingBusTable[i]; + } + + floatingBusTable = fbt.ToArray(); + } + //build bottom border while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom)) { @@ -177,4 +207,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } + */ } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs index db8105555d..a8d33eb03a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.cs @@ -21,7 +21,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum Spectrum = spectrum; CPU = cpu; - ULADevice = new ULA48(this); + CPUMon = new CPUMonitor(this); + + //ULADevice = new ULA48(this); + ULADevice = new Screen48(this); BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs index 14ed0a439b..b182a80270 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs @@ -91,6 +91,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum _cpu.ReadHardware = _machine.ReadPort; _cpu.WriteHardware = _machine.WritePort; _cpu.FetchDB = _machine.PushBus; + _cpu.OnExecFetch = _machine.CPUMon.OnExecFetch; ser.Register(_tracer); ser.Register(_cpu); From c0d6c02b2ed49cca459a4449c34e6dd44422e3cd Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 31 May 2018 21:05:41 -0400 Subject: [PATCH 02/51] Z80: Recast core to cycle accurate memory accesses and wait state timing --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 8 +- .../CPUs/Z80A/Interrupts.cs | 42 +-- .../CPUs/Z80A/Operations.cs | 14 + .../CPUs/Z80A/Tables_Direct.cs | 330 +++++++++--------- .../CPUs/Z80A/Tables_Indirect.cs | 319 ++++++++--------- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 198 +++++------ 6 files changed, 438 insertions(+), 473 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index 5f4ccb2437..57f262bd7a 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -20,13 +20,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public int instr_pntr = 0; public ushort instr_swap; public ushort[] cur_instr; - public int opcode; + public byte opcode; public bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix; public bool IXCB_prefetch, IYCB_prefetch; // value is fetched before opcode public bool halted; public ushort PF; - public void FetchInstruction(byte opcode) + public void FetchInstruction() { if (NO_prefix) { @@ -1186,6 +1186,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IXCB_prefetch = false; PF = opcode; Regs[ALU] = PF; + Regs[W] = Regs[Ixh]; + Regs[Z] = Regs[Ixl]; PREFETCH_(Ixl, Ixh); return; } @@ -1195,6 +1197,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IYCB_prefetch = false; PF = opcode; Regs[ALU] = PF; + Regs[W] = Regs[Iyh]; + Regs[Z] = Regs[Iyl]; PREFETCH_(Iyl, Iyh); return; } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs index 2c4f5c5204..648590c92b 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -33,16 +33,16 @@ namespace BizHawk.Emulation.Cores.Components.Z80A private void NMI_() { cur_instr = new ushort[] - {IDLE, - DEC16, SPl, SPh, + {DEC16, SPl, SPh, + WAIT, WR, SPl, SPh, PCh, - IDLE, DEC16, SPl, SPh, + WAIT, WR, SPl, SPh, PCl, - IDLE, ASGN, PCl, 0x66, ASGN, PCh, 0, - IDLE, + WAIT, + OP_F, OP }; } @@ -55,11 +55,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, + WAIT, RD, ALU, PCl, PCh, - IDLE, INC16, PCl, PCh, - IDLE, + WAIT, + OP_F, OP }; } @@ -68,17 +68,17 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {DEC16, SPl, SPh, - IDLE, + WAIT, WR, SPl, SPh, PCh, - IDLE, DEC16, SPl, SPh, - IDLE, + WAIT, WR, SPl, SPh, PCl, - IDLE, ASGN, PCl, 0x38, IDLE, ASGN, PCh, 0, IDLE, + WAIT, + OP_F, OP }; } @@ -87,23 +87,23 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, + WAIT, FTCH_DB, - TR, Z, DB, - TR, W, I, - IDLE, + TR16, Z, W, DB, I, DEC16, SPl, SPh, + WAIT, WR, SPl, SPh, PCh, - IDLE, DEC16, SPl, SPh, - WR, SPl, SPh, PCl, + WAIT, + WR, SPl, SPh, PCl, IDLE, - RD, PCl, Z, W, - INC16, Z, W, + WAIT, + RD_INC, PCl, Z, W, IDLE, RD, PCh, Z, W, IDLE, - IDLE, + WAIT, + OP_F, OP }; } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs index c26a7a6aff..f9fe6f797f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs @@ -11,6 +11,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Regs[DB] = Regs[dest]; } + public void Read_INC_Func(ushort dest, ushort src_l, ushort src_h) + { + Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8)); + Regs[DB] = Regs[dest]; + INC16_Func(src_l, src_h); + } + public void I_Read_Func(ushort dest, ushort src_l, ushort src_h, ushort inc) { Regs[dest] = ReadMemory((ushort)((Regs[src_l] | (Regs[src_h] << 8)) + inc)); @@ -23,6 +30,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]); } + public void Write_INC_Func(ushort dest_l, ushort dest_h, ushort src) + { + Regs[DB] = Regs[src]; + WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]); + INC16_Func(dest_l, dest_h); + } + public void I_Write_Func(ushort dest_l, ushort dest_h, ushort inc, ushort src) { Regs[DB] = Regs[src]; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index e708b02bac..0bc5e7cc19 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -10,10 +10,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A private void NOP_() { cur_instr = new ushort[] - {IDLE, - IDLE, - IDLE, - OP }; + { IDLE, + WAIT, + OP_F, + OP }; } // NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers @@ -22,8 +22,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {EXCH, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -31,8 +31,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {EXX, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -41,19 +41,19 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {EXCH_16, dest_l, dest_h, src_l, src_h, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } private void INC_16(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {IDLE, + {INC16, src_l, src_h, IDLE, IDLE, - INC16, src_l, src_h, - IDLE, + WAIT, + OP_F, OP }; } @@ -61,11 +61,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A private void DEC_16(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {IDLE, - IDLE, - DEC16, src_l, src_h, + {DEC16, src_l, src_h, IDLE, IDLE, + WAIT, + OP_F, OP }; } @@ -74,16 +74,16 @@ namespace BizHawk.Emulation.Cores.Components.Z80A private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) { cur_instr = new ushort[] - {IDLE, + {TR16, Z, W, dest_l, dest_h, IDLE, - IDLE, - TR16, Z, W, dest_l, dest_h, INC16, Z, W, IDLE, - IDLE, ADD16, dest_l, dest_h, src_l, src_h, IDLE, IDLE, + IDLE, + WAIT, + OP_F, OP }; } @@ -91,8 +91,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {operation, dest, src, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -101,9 +101,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {operation, dest, src, - IDLE, - IDLE, SET_FL_IR, dest, + WAIT, + OP_F, OP }; } @@ -114,17 +114,17 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, + ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), - IDLE, - RD, Z, PCl, PCh, - IDLE, - INC16, PCl, PCh, IDLE, ASGN, W, 0, - IDLE, ADDS, PCl, PCh, Z, W, TR16, Z, W, PCl, PCh, + IDLE, + WAIT, + OP_F, OP }; } else @@ -132,11 +132,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A cur_instr = new ushort[] {IDLE, ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, - RD, ALU, PCl, PCh, - IDLE, - INC16, PCl, PCh, - IDLE, + WAIT, + OP_F, OP }; } } @@ -156,27 +156,27 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, - RD, Z, PCl, PCh, - INC16, PCl, PCh, - IDLE, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, ASGN, W, 0, - IDLE, ADDS, PCl, PCh, Z, W, - TR16, Z, W, PCl, PCh, + TR16, Z, W, PCl, PCh, IDLE, + IDLE, + WAIT, + OP_F, OP }; } else { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, - IDLE, - RD, ALU, PCl, PCh, - IDLE, - INC16, PCl, PCh, + WAIT, + OP_F, OP }; } } @@ -187,28 +187,28 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - RD, Z, PCl, PCh, - INC16, PCl, PCh, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, + WAIT, + RD_INC, W, PCl, PCh, TR16, PCl, PCh, Z, W, - IDLE, + WAIT, + OP_F, OP }; } else { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - RD, Z, PCl, PCh, - INC16, PCl, PCh, - IDLE, - RD, W, PCl, PCh, - INC16, PCl, PCh, - IDLE, + WAIT, + RD_INC, W, PCl, PCh, IDLE, + WAIT, + OP_F, OP }; } } @@ -217,14 +217,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, Z, SPl, SPh, IDLE, - RD, Z, SPl, SPh, - INC16, SPl, SPh, - IDLE, - IDLE, - RD, W, SPl, SPh, - INC16, SPl, SPh, - TR16, PCl, PCh, Z, W, + WAIT, + RD_INC, W, SPl, SPh, + TR16, PCl, PCh, Z, W, + WAIT, + OP_F, OP }; } @@ -232,14 +232,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, Z, SPl, SPh, IDLE, - RD, Z, SPl, SPh, - INC16, SPl, SPh, - IDLE, - IDLE, - RD, W, SPl, SPh, - INC16, SPl, SPh, + WAIT, + RD_INC, W, SPl, SPh, TR16, PCl, PCh, Z, W, + WAIT, + OP_F, OP }; } @@ -247,14 +247,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, - RD, Z, SPl, SPh, - INC16, SPl, SPh, - IDLE, - RD, W, SPl, SPh, - INC16, SPl, SPh, + WAIT, + RD_INC, Z, SPl, SPh, EI_RETN, + WAIT, + RD_INC, W, SPl, SPh, TR16, PCl, PCh, Z, W, + WAIT, + OP_F, OP }; } @@ -266,14 +266,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A cur_instr = new ushort[] {IDLE, IDLE, - RD, Z, SPl, SPh, - INC16, SPl, SPh, + WAIT, + RD_INC, Z, SPl, SPh, IDLE, - IDLE, - RD, W, SPl, SPh, - INC16, SPl, SPh, - IDLE, + WAIT, + RD_INC, W, SPl, SPh, TR16, PCl, PCh, Z, W, + WAIT, + OP_F, OP }; } else @@ -281,8 +281,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A cur_instr = new ushort[] {IDLE, IDLE, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } } @@ -293,35 +293,35 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - RD, Z, PCl, PCh, - INC16, PCl, PCh, - IDLE, - RD, W, PCl, PCh, - INC16, PCl, PCh, IDLE, + WAIT, + RD_INC, W, PCl, PCh, DEC16, SPl, SPh, - IDLE, - WR, SPl, SPh, PCh, + WAIT, + WR, SPl, SPh, PCh, DEC16, SPl, SPh, + WAIT, WR, SPl, SPh, PCl, - IDLE, - TR, PCl, Z, - TR, PCh, W, + TR16, PCl, PCh, Z, W, + WAIT, + OP_F, OP }; } else { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, W, PCl, PCh, IDLE, - INC16, PCl, PCh, - IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, + WAIT, + OP_F, OP }; } } @@ -330,8 +330,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {operation, src, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -339,8 +339,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {operation, bit, src, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -348,15 +348,15 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, DEC16, SPl, SPh, - IDLE, + WAIT, WR, SPl, SPh, src_h, - IDLE, DEC16, SPl, SPh, - IDLE, + WAIT, WR, SPl, SPh, src_l, IDLE, + WAIT, + OP_F, OP }; } @@ -365,14 +365,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - RD, src_l, SPl, SPh, + WAIT, + RD_INC, src_l, SPl, SPh, IDLE, - INC16, SPl, SPh, - IDLE, - RD, src_h, SPl, SPh, - IDLE, - INC16, SPl, SPh, + WAIT, + RD_INC, src_h, SPl, SPh, IDLE, + WAIT, + OP_F, OP }; } @@ -380,15 +380,15 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, DEC16, SPl, SPh, + WAIT, WR, SPl, SPh, PCh, DEC16, SPl, SPh, + WAIT, WR, SPl, SPh, PCl, - IDLE, - ASGN, Z, n, - ASGN, W, 0, - TR16, PCl, PCh, Z, W, + RST, n, + WAIT, + OP_F, OP }; } @@ -396,17 +396,17 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, - IDLE, + WAIT, + OP_F, PREFIX, src}; } private void PREFETCH_(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {TR16, Z, W, src_l, src_h, - ADDS, Z, W, ALU, ZERO, - IDLE, + {ADDS, Z, W, ALU, ZERO, + WAIT, + OP_F, PREFIX, IXYprefetch }; } @@ -414,8 +414,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {DI, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -423,17 +423,17 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {EI, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } private void JP_16(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {TR, PCl, src_l, - IDLE, - TR, PCh, src_h, + {TR16, PCl, PCh, src_l, src_h, + WAIT, + OP_F, OP }; } @@ -442,9 +442,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A cur_instr = new ushort[] {IDLE, IDLE, - TR, SPl, src_l, - TR, SPh, src_h, - IDLE, + TR16, SPl, SPh, src_l, src_h, + WAIT, + OP_F, OP }; } @@ -452,15 +452,15 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - INC16, PCl, PCh, TR, W, A, OUT, Z, W, A, - IDLE, INC16, Z, W, IDLE, - IDLE, + WAIT, + OP_F, OP}; } @@ -468,12 +468,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, TR16, Z, W, C, B, OUT, Z, W, src, - IDLE, INC16, Z, W, - IDLE, + IDLE, + WAIT, + OP_F, OP}; } @@ -481,15 +481,15 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - INC16, PCl, PCh, TR, W, A, IN, A, Z, W, - IDLE, INC16, Z, W, IDLE, - IDLE, + WAIT, + OP_F, OP}; } @@ -497,12 +497,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IDLE, IN, dest, src, B, - IDLE, TR16, Z, W, C, B, INC16, Z, W, IDLE, + WAIT, + OP_F, OP}; } @@ -511,61 +511,61 @@ namespace BizHawk.Emulation.Cores.Components.Z80A cur_instr = new ushort[] {IDLE, IDLE, - IDLE, TR16, Z, W, dest_l, dest_h, INC16, Z, W, IDLE, IDLE, op, dest_l, dest_h, src_l, src_h, IDLE, - IDLE, + WAIT, + OP_F, OP}; } private void INT_MODE_(ushort src) { cur_instr = new ushort[] - {IDLE, - IDLE, - INT_MODE, src, + {INT_MODE, src, + WAIT, + OP_F, OP }; } private void RRD_() { cur_instr = new ushort[] - {IDLE, - IDLE, - TR16, Z, W, L, H, - IDLE, + {TR16, Z, W, L, H, + WAIT, RD, ALU, Z, W, IDLE, RRD, ALU, A, IDLE, + IDLE, + IDLE, + WAIT, WR, Z, W, ALU, - IDLE, INC16, Z, W, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } private void RLD_() { cur_instr = new ushort[] - {IDLE, - IDLE, - TR16, Z, W, L, H, - IDLE, + {TR16, Z, W, L, H, + WAIT, RD, ALU, Z, W, IDLE, RLD, ALU, A, IDLE, + IDLE, + IDLE, + WAIT, WR, Z, W, ALU, - IDLE, INC16, Z, W, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index c53b013a86..0ed80b9067 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -6,15 +6,15 @@ { cur_instr = new ushort[] {IDLE, - IDLE, - IDLE, + WAIT, RD, ALU, src_l, src_h, IDLE, operation, ALU, - IDLE, + WAIT, WR, src_l, src_h, ALU, - IDLE, - IDLE, + IDLE, + WAIT, + OP_F, OP }; } @@ -23,14 +23,14 @@ cur_instr = new ushort[] {IDLE, IDLE, - IDLE, + WAIT, RD, ALU, src_l, src_h, - IDLE, operation, bit, ALU, - IDLE, + WAIT, WR, src_l, src_h, ALU, IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -43,11 +43,11 @@ cur_instr = new ushort[] {IDLE, IDLE, - IDLE, + WAIT, RD, ALU, src_l, src_h, - IDLE, I_BIT, bit, ALU, - IDLE, + WAIT, + OP_F, OP }; } @@ -55,23 +55,23 @@ { cur_instr = new ushort[] {IDLE, - IDLE, - RD, ALU, src_l, src_h, - IDLE, + WAIT, + RD_INC, ALU, src_l, src_h, operation, dest, ALU, - INC16, src_l, src_h, + WAIT, + OP_F, OP }; } private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h) { cur_instr = new ushort[] - {IDLE, - IDLE, - TR16, Z, W, src_l, src_h, - RD, ALU, Z, W, - INC16, Z, W, - operation, dest, ALU, + {TR16, Z, W, src_l, src_h, + WAIT, + RD_INC, ALU, Z, W, + operation, dest, ALU, + WAIT, + OP_F, OP }; } @@ -79,20 +79,20 @@ { cur_instr = new ushort[] {IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - INC16, PCl, PCh, - IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, + WAIT, + RD_INC, W, PCl, PCh, IDLE, + WAIT, WR, Z, W, src_l, - IDLE, INC16, Z, W, - IDLE, + WAIT, WR, Z, W, src_h, IDLE, + WAIT, + OP_F, OP }; } @@ -100,20 +100,20 @@ { cur_instr = new ushort[] {IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - INC16, PCl, PCh, + WAIT, + RD_INC, W, PCl, PCh, IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, - IDLE, - RD, dest_l, Z, W, - IDLE, - INC16, Z, W, + WAIT, + RD_INC, dest_l, Z, W, IDLE, + WAIT, RD, dest_h, Z, W, IDLE, + WAIT, + OP_F, OP }; } @@ -121,17 +121,17 @@ { cur_instr = new ushort[] {IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - INC16, PCl, PCh, + WAIT, + RD_INC, W, PCl, PCh, IDLE, - RD, W, PCl, PCh, - IDLE, - INC16, PCl, PCh, - IDLE, - WR, Z, W, src, - INC16, Z, W, + WAIT, + WR_INC, Z, W, src, TR, W, A, + WAIT, + OP_F, OP }; } @@ -139,29 +139,29 @@ { cur_instr = new ushort[] {IDLE, - RD, Z, PCl, PCh, + WAIT, + RD_INC, Z, PCl, PCh, IDLE, - INC16, PCl, PCh, + WAIT, + RD_INC, W, PCl, PCh, IDLE, - RD, W, PCl, PCh, + WAIT, + RD_INC, dest, Z, W, IDLE, - INC16, PCl, PCh, - IDLE, - RD, dest, Z, W, - IDLE, - INC16, Z, W, + WAIT, + OP_F, OP }; } private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src) { cur_instr = new ushort[] - {IDLE, - IDLE, - TR16, Z, W, dest_l, dest_h, - WR, Z, W, src, - INC16, Z, W, - TR, W, A, + {TR16, Z, W, dest_l, dest_h, + WAIT, + WR_INC, Z, W, src, + TR, W, A, + WAIT, + OP_F, OP }; } @@ -169,14 +169,14 @@ { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, ALU, src_l, src_h, IDLE, - IDLE, - RD, ALU, src_l, src_h, - IDLE, - INC16, src_l, src_h, - IDLE, + WAIT, WR, dest_l, dest_h, ALU, IDLE, + WAIT, + OP_F, OP }; } @@ -184,24 +184,11 @@ { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, dest, src_l, src_h, IDLE, - IDLE, - RD, dest, src_l, src_h, - IDLE, - INC16, src_l, src_h, - OP }; - } - - private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h) - { - cur_instr = new ushort[] - {IDLE, - IDLE, - IDLE, - RD, dest, src_l, src_h, - IDLE, - DEC16, src_l, src_h, - IDLE, + WAIT, + OP_F, OP }; } @@ -209,14 +196,14 @@ { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, dest_l, src_l, src_h, IDLE, + WAIT, + RD_INC, dest_h, src_l, src_h, IDLE, - RD, dest_l, src_l, src_h, - IDLE, - INC16, src_l, src_h, - RD, dest_h, src_l, src_h, - IDLE, - INC16, src_l, src_h, + WAIT, + OP_F, OP }; } @@ -225,14 +212,14 @@ cur_instr = new ushort[] {IDLE, IDLE, - IDLE, + WAIT, RD, ALU, src_l, src_h, - IDLE, INC8, ALU, - IDLE, + WAIT, WR, src_l, src_h, ALU, IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -241,14 +228,14 @@ cur_instr = new ushort[] {IDLE, IDLE, - IDLE, + WAIT, RD, ALU, src_l, src_h, - IDLE, DEC8, ALU, - IDLE, + WAIT, WR, src_l, src_h, ALU, IDLE, - IDLE, + WAIT, + OP_F, OP }; } @@ -258,14 +245,14 @@ cur_instr = new ushort[] {IDLE, IDLE, + WAIT, RD, ALU, Z, W, - IDLE, operation, ALU, - IDLE, + WAIT, WR, Z, W, ALU, - IDLE, TR, dest, ALU, - IDLE, + WAIT, + OP_F, OP }; } @@ -274,14 +261,14 @@ cur_instr = new ushort[] {IDLE, IDLE, + WAIT, RD, ALU, Z, W, - IDLE, operation, bit, ALU, - IDLE, + WAIT, WR, Z, W, ALU, - IDLE, TR, dest, ALU, - IDLE, + WAIT, + OP_F, OP }; } @@ -290,11 +277,11 @@ cur_instr = new ushort[] {IDLE, IDLE, - IDLE, + WAIT, RD, ALU, Z, W, - IDLE, I_BIT, bit, ALU, - IDLE, + WAIT, + OP_F, OP }; } @@ -302,23 +289,23 @@ { cur_instr = new ushort[] {IDLE, + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, - RD, ALU, PCl, PCh, - INC16, PCl, PCh, IDLE, TR16, Z, W, src_l, src_h, + ADDS, Z, W, ALU, ZERO, IDLE, - ADDS, Z, W, ALU, ZERO, IDLE, + IDLE, + WAIT, RD, ALU, Z, W, - IDLE, - IDLE, operation, ALU, - IDLE, - IDLE, - IDLE, + WAIT, WR, Z, W, ALU, IDLE, + WAIT, + OP_F, OP }; } @@ -326,19 +313,19 @@ { cur_instr = new ushort[] {IDLE, - IDLE, - RD, ALU, PCl, PCh, - INC16, PCl, PCh, + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, TR16, Z, W, src_l, src_h, - IDLE, ADDS, Z, W, ALU, ZERO, + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, - RD, ALU, PCl, PCh, - INC16, PCl, PCh, - IDLE, + WAIT, WR, Z, W, ALU, IDLE, + WAIT, + OP_F, OP }; } @@ -346,19 +333,19 @@ { cur_instr = new ushort[] {IDLE, - IDLE, - RD, ALU, PCl, PCh, - IDLE, - INC16, PCl, PCh, + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, TR16, Z, W, src_l, src_h, IDLE, ADDS, Z, W, ALU, ZERO, IDLE, + WAIT, RD, ALU, Z, W, - IDLE, operation, dest, ALU, IDLE, + WAIT, + OP_F, OP }; } @@ -366,36 +353,36 @@ { cur_instr = new ushort[] {IDLE, - RD, ALU, PCl, PCh, + WAIT, + RD_INC, ALU, PCl, PCh, IDLE, - INC16, PCl, PCh, IDLE, TR16, Z, W, dest_l, dest_h, - IDLE, ADDS, Z, W, ALU, ZERO, IDLE, - WR, Z, W, src, - IDLE, - IDLE, IDLE, + WAIT, + WR, Z, W, src, IDLE, + WAIT, + OP_F, OP }; } private void LD_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] - {RD, ALU, L, H, + {IDLE, + WAIT, + RD, ALU, L, H, IDLE, + WAIT, WR, E, D, ALU, - IDLE, operation, L, H, - IDLE, operation, E, D, - IDLE, - DEC16, C, B, - SET_FL_LD, - IDLE, + SET_FL_LD, // BC gets decremented in here + WAIT, + OP_F, OP_R, 0, operation, repeat_instr }; } @@ -403,16 +390,16 @@ { cur_instr = new ushort[] {IDLE, - IDLE, + WAIT, RD, ALU, L, H, operation, L, H, - IDLE, - IDLE, DEC16, C, B, SET_FL_CP, - IDLE, operation, Z, W, IDLE, + IDLE, + WAIT, + OP_F, OP_R, 1, operation, repeat_instr }; } @@ -421,32 +408,32 @@ cur_instr = new ushort[] {IN, ALU, C, B, IDLE, + IDLE, + IDLE, + IDLE, + WAIT, WR, L, H, ALU, + REP_OP_I, operation, IDLE, - operation, L, H, - IDLE, - TR16, Z, W, C, B, - operation, Z, W, - IDLE, - DEC8, B, - IDLE, + WAIT, + OP_F, OP_R, 2, operation, repeat_instr }; } private void OUT_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] - {RD, ALU, L, H, + {IDLE, + WAIT, + RD, ALU, L, H, IDLE, OUT, C, B, ALU, IDLE, IDLE, - operation, L, H, - DEC8, B, - IDLE, - TR16, Z, W, C, B, - operation, Z, W, + REP_OP_O, operation, IDLE, + WAIT, + OP_F, OP_R, 3, operation, repeat_instr }; } @@ -455,23 +442,23 @@ { cur_instr = new ushort[] {IDLE, - IDLE, + WAIT, RD, Z, dest_l, dest_h, IDLE, IDLE, + WAIT, I_RD, W, dest_l, dest_h, 1, IDLE, - IDLE, - WR, dest_l, dest_h, src_l, + WAIT, + WR, dest_l, dest_h, src_l, IDLE, IDLE, + IDLE, + WAIT, I_WR, dest_l, dest_h, 1, src_h, - IDLE, - IDLE, TR16, src_l, src_h, Z, W, - IDLE, - IDLE, - IDLE, + WAIT, + OP_F, OP }; } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index c3786015a3..867b83a1e0 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -76,6 +76,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort HL_BIT = 61; public const ushort FTCH_DB = 62; public const ushort WAIT = 63; // enterred when readin or writing and FlagW is true + public const ushort OP_F = 64; // fetch the opcode, happens on cycle 3 of fetch cycle + public const ushort RD_INC = 65; // read and increment + public const ushort RST = 66; + public const ushort WR_INC = 67; // write and increment + public const ushort REP_OP_I = 68; + public const ushort REP_OP_O = 69; public byte temp_R; @@ -90,7 +96,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A ResetRegisters(); ResetInterrupts(); TotalExecutedCycles = 0; - cur_instr = new ushort[] { OP }; + cur_instr = new ushort[] + { IDLE, + WAIT, + OP_F, + OP }; instr_pntr = 0; NO_prefix = true; } @@ -205,19 +215,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A } else { - if(!FlagW) - { - if (OnExecFetch != null) OnExecFetch(RegPC); - if (TraceCallback != null) TraceCallback(State()); - FetchInstruction(FetchMemory(RegPC++)); - instr_pntr = 0; - } - else - { - instr_pntr--; - instr_swap = OP; - cur_instr[instr_pntr] = WAIT; - } + if (OnExecFetch != null) OnExecFetch(RegPC); + if (TraceCallback != null) TraceCallback(State()); + RegPC++; + FetchInstruction(); + instr_pntr = 0; } temp_R = (byte)(Regs[R] & 0x7F); @@ -255,10 +257,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (repeat && temp3 > 0) { cur_instr = new ushort[] - {IDLE, - DEC16, PCl, PCh, - IDLE, + {DEC16, PCl, PCh, DEC16, PCl, PCh, + WAIT, + OP_F, OP }; instr_pntr = 0; @@ -340,19 +342,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A } else { - if (!FlagW) - { - if (OnExecFetch != null) OnExecFetch(RegPC); - if (TraceCallback != null) TraceCallback(State()); - FetchInstruction(FetchMemory(RegPC++)); - instr_pntr = 0; - } - else - { - instr_pntr--; - instr_swap = OP; - cur_instr[instr_pntr] = WAIT; - } + if (OnExecFetch != null) OnExecFetch(RegPC); + if (TraceCallback != null) TraceCallback(State()); + RegPC++; + FetchInstruction(); + instr_pntr = 0; } temp_R = (byte)(Regs[R] & 0x7F); @@ -432,53 +426,16 @@ namespace BizHawk.Emulation.Cores.Components.Z80A instr_pntr = 0; break; case RD: - if (!FlagW) - { - Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - } - else - { - instr_pntr--; - instr_swap = RD; - cur_instr[instr_pntr] = WAIT; - } - + Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case WR: - if (!FlagW) - { - Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - } - else - { - instr_pntr--; - instr_swap = WR; - cur_instr[instr_pntr] = WAIT; - } + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case I_RD: - if (!FlagW) - { - I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - } - else - { - instr_pntr--; - instr_swap = I_RD; - cur_instr[instr_pntr] = WAIT; - } + I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case I_WR: - if (!FlagW) - { - I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - } - else - { - instr_pntr--; - instr_swap =I_WR; - cur_instr[instr_pntr] = WAIT; - } + I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case TR: TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); @@ -606,7 +563,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (prefix_src == IXCBpre) { IXCB_prefix = true; IXCB_prefetch = true; } if (prefix_src == IYCBpre) { IYCB_prefix = true; IYCB_prefetch = true; } - FetchInstruction(FetchMemory(RegPC++)); + RegPC++; + FetchInstruction(); instr_pntr = 0; // only the first prefix in a double prefix increases R, although I don't know how / why if (prefix_src < 4) @@ -632,28 +590,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A iff1 = iff2; break; case OUT: - if (!FlagW) - { - OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - } - else - { - instr_pntr--; - instr_swap = OUT; - cur_instr[instr_pntr] = WAIT; - } + OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case IN: - if (!FlagW) - { - IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - } - else - { - instr_pntr--; - instr_swap = IN; - cur_instr[instr_pntr] = WAIT; - } + IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case NEG: NEG_8_Func(cur_instr[instr_pntr++]); @@ -668,6 +608,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A RLD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case SET_FL_LD: + DEC16_Func(C, B); SET_FL_LD_Func(); break; case SET_FL_CP: @@ -684,35 +625,54 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { instr_pntr--; } + break; + case OP_F: + opcode = FetchMemory(RegPC); + break; + case RD_INC: + Read_INC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR_INC: + Write_INC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RST: + Regs[Z] = cur_instr[instr_pntr++]; + Regs[W] = 0; + Regs[PCl] = Regs[Z]; + Regs[PCh] = Regs[W]; + break; + case REP_OP_I: + ushort temp4 = cur_instr[instr_pntr++]; + if (temp4 == DEC16) + { + DEC16_Func(L, H); + TR16_Func(Z, W, C, B); + DEC16_Func(Z, W); + DEC8_Func(B); + } else { - switch (instr_swap) - { - case OP: - if (OnExecFetch != null) OnExecFetch(RegPC); - if (TraceCallback != null) TraceCallback(State()); - FetchInstruction(FetchMemory(RegPC++)); - instr_pntr = 0; - break; - case RD: - Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - case WR: - Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - case I_RD: - I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - case I_WR: - I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - case IN: - IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - case OUT: - OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - } + INC16_Func(L, H); + TR16_Func(Z, W, C, B); + INC16_Func(Z, W); + DEC8_Func(B); + } + break; + case REP_OP_O: + ushort temp5 = cur_instr[instr_pntr++]; + if (temp5 == DEC16) + { + DEC16_Func(L, H); + DEC8_Func(B); + TR16_Func(Z, W, C, B); + DEC16_Func(Z, W); + } + else + { + INC16_Func(L, H); + DEC8_Func(B); + TR16_Func(Z, W, C, B); + INC16_Func(Z, W); } break; } From b9dd43545536d15432ded4c28e56a3ad794c1b1d Mon Sep 17 00:00:00 2001 From: Matt Burgess Date: Fri, 1 Jun 2018 17:38:42 +0100 Subject: [PATCH 03/51] ZXHawk: Started 128 and +2a/3 new ULA implementation --- .../BizHawk.Emulation.Cores.csproj | 2 + .../SinclairSpectrum/Machine/CPUMonitor.cs | 108 +++++++++++++++++- .../SinclairSpectrum/Machine/SpectrumBase.cs | 3 +- .../Machine/ZXSpectrum128K/ZX128.Port.cs | 3 +- .../Machine/ZXSpectrum128K/ZX128.Screen.cs | 49 ++++++++ .../Machine/ZXSpectrum128K/ZX128.cs | 2 +- .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 3 +- .../ZX128Plus2a.Screen.cs | 49 ++++++++ .../ZXSpectrum128KPlus2a/ZX128Plus2a.cs | 2 +- .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 3 +- .../Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs | 5 +- .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 9 +- 12 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 36b6f5462a..6ac5775daf 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -263,6 +263,7 @@ + @@ -1437,6 +1438,7 @@ + diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 25a03161fc..d2cff11e0e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -39,12 +39,112 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void Cycle() { + if (portContending) { - RunPortContention(); + RunPortContention(); + } + /* + else + { + // check for wait state on cycle that has just happened + // next cycle should be a read/write operation + if (cur_instr[instr_pntr] == Z80A.WAIT) + { + ushort addr = 0; + bool abort = false; + + // identify the type of operation and get the targetted address + switch (cur_instr[instr_pntr + 1]) + { + // op fetch + case Z80A.OP_F: + addr = RegPC; + break; + // read/writes + case Z80A.RD: + case Z80A.RD_INC: + case Z80A.WR: + case Z80A.WR_INC: + addr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 3]] | _cpu.Regs[cur_instr[instr_pntr + 4]] << 8); + break; + default: + abort = true; + break; + } + + if (!abort) + { + // is the address in a potentially contended bank? + if (_machine.IsContended(addr)) + { + // will the ULA be contending this address on the next cycle? + var delay = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle + 1); + _cpu.TotalExecutedCycles += delay; + } + } + } + + } + */ + return; + // check for wait state on next cycle + // the cycle after that should be a read/write operation or op fetch + if (instr_pntr >= cur_instr.Length - 1) + { + // will overflow + return; + } + + if (cur_instr[instr_pntr + 1] == Z80A.WAIT) + { + // return; + ushort addr = 0; + + // identify the type of operation and get the targetted address + var op = cur_instr[instr_pntr + 2]; + switch (op) + { + // op fetch + case Z80A.OP_F: + addr = (ushort)(RegPC); + if (_machine.IsContended(addr)) + { + var delay = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (delay > 0) + { + _cpu.TotalExecutedCycles += delay; + _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); + } + } + break; + // read/writes + case Z80A.RD: + case Z80A.RD_INC: + case Z80A.WR: + case Z80A.WR_INC: + case Z80A.I_RD: + case Z80A.I_WR: + addr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 4]] | _cpu.Regs[cur_instr[instr_pntr + 5]] << 8); + if (_machine.IsContended(addr)) + { + var delay = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (delay > 0) + { + _cpu.TotalExecutedCycles += delay; + _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); + } + } + break; + case Z80A.FTCH_DB: + break; + default: + break; + } } } + #region Port Contention public int portContCounter = 0; @@ -78,6 +178,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { case MachineType.ZXSpectrum16: case MachineType.ZXSpectrum48: + case MachineType.ZXSpectrum128: + case MachineType.ZXSpectrum128Plus2: if ((lastPortAddr & 0xc000) == 0x4000) highByte407f = true; @@ -160,10 +262,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } break; - case MachineType.ZXSpectrum128: - case MachineType.ZXSpectrum128Plus2: - break; - case MachineType.ZXSpectrum128Plus2a: case MachineType.ZXSpectrum128Plus3: break; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index 1a8ff0a328..d6bea89b67 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -169,7 +169,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // check for interrupt ULADevice.CheckForInterrupt(CurrentFrameCycle); - // run a single CPU instruction + // run a single CPU instruction + CPU.ExecuteOne(); CPUMon.Cycle(); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index 68639979e9..bff1ec4334 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -176,7 +176,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendPort(ushort addr) { - throw new NotImplementedException(); + CPUMon.ContendPort(addr); + return; } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs new file mode 100644 index 0000000000..cbd98f1128 --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + class Screen128 : ULA + { + #region Construction + + public Screen128(SpectrumBase machine) + : base(machine) + { + // timing + ClockSpeed = 3546900; + FrameCycleLength = 70908; + InterruptStartTime = 33; + InterruptLength = 36; + ScanlineTime = 228; + + BorderLeftTime = 24; + BorderRightTime = 24; + + FirstPaperLine = 63; + FirstPaperTState = 64; + + Border4T = true; + Border4TStage = 2; + + // screen layout + ScreenWidth = 256; + ScreenHeight = 192; + BorderTopHeight = 48; + BorderBottomHeight = 56; + BorderLeftWidth = 48; + BorderRightWidth = 48; + ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth; + + RenderingTable = new RenderTable(this, + MachineType.ZXSpectrum128); + + SetupScreenSize(); + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs index fc2369a3a1..ed556a3025 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.cs @@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum PagingDisabled = false; //ULADevice = new ULA128(this); - ULADevice = new Screen48(this); // still todo + ULADevice = new Screen128(this); // still todo BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index 3eb942d51f..2423078a83 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -289,7 +289,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendPort(ushort addr) { - throw new NotImplementedException(); + CPUMon.ContendPort(addr); + return; } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs new file mode 100644 index 0000000000..e9026ce5d7 --- /dev/null +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum +{ + class Screen128Plus2a : ULA + { + #region Construction + + public Screen128Plus2a(SpectrumBase machine) + : base(machine) + { + // timing + ClockSpeed = 3546900; + FrameCycleLength = 70908; + InterruptStartTime = 33; + InterruptLength = 32; + ScanlineTime = 228; + + BorderLeftTime = 24; + BorderRightTime = 24; + + FirstPaperLine = 63; + FirstPaperTState = 64; + + Border4T = true; + Border4TStage = 2; + + // screen layout + ScreenWidth = 256; + ScreenHeight = 192; + BorderTopHeight = 48; + BorderBottomHeight = 56; + BorderLeftWidth = 48; + BorderRightWidth = 48; + ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth; + + RenderingTable = new RenderTable(this, + MachineType.ZXSpectrum128Plus2a); + + SetupScreenSize(); + } + + #endregion + } +} diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs index 487cc386b4..363f1a52ac 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs @@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum PagingDisabled = false; //ULADevice = new ULAPlus2a(this); - ULADevice = new Screen48(this); // still todo + ULADevice = new Screen128Plus2a(this); // still todo BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index c3b53fff79..d1c30ee3a8 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -224,7 +224,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendPort(ushort addr) { - throw new NotImplementedException(); + CPUMon.ContendPort(addr); + return; } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs index decfb7466e..4e6d889d55 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs @@ -20,9 +20,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { Spectrum = spectrum; CPU = cpu; - CPUMon.machineType = MachineType.ZXSpectrum128Plus3; + CPUMon = new CPUMonitor(this); + CPUMon.machineType = MachineType.ZXSpectrum128Plus3; ROMPaged = 0; SHADOWPaged = false; @@ -30,7 +31,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum PagingDisabled = false; // ULADevice = new ULAPlus3(this); - ULADevice = new Screen48(this); // still todo + ULADevice = new Screen128Plus2a(this); // still todo BuzzerDevice = new Beeper(this); BuzzerDevice.Init(44100, ULADevice.FrameLength); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index 624df29d2c..7dd6f3cd21 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -124,7 +124,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { if (IsContended(addr)) { - var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); + var off = 1; + var offset = CurrentFrameCycle + off; + if (offset < 0) + offset += ULADevice.FrameCycleLength; + if (offset >= ULADevice.FrameCycleLength) + offset -= ULADevice.FrameCycleLength; + + var delay = ULADevice.GetContentionValue((int)offset); if (delay > 0) { From 7220e9d3944241386216cb6c434601086939820f Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 1 Jun 2018 15:21:05 -0400 Subject: [PATCH 04/51] z80: fix some instruction timings for IN/OUT --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs | 6 +++--- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 0bc5e7cc19..4ad6252352 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -385,7 +385,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WR, SPl, SPh, PCh, DEC16, SPl, SPh, WAIT, - WR, SPl, SPh, PCl, + WR, SPl, SPh, PCl, RST, n, WAIT, OP_F, @@ -497,10 +497,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - IN, dest, src, B, TR16, Z, W, C, B, + WAIT, + IN, dest, src, B, INC16, Z, W, - IDLE, WAIT, OP_F, OP}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 0ed80b9067..0e0b69801e 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -406,10 +406,10 @@ private void IN_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] - {IN, ALU, C, B, - IDLE, - IDLE, + {IDLE, IDLE, + WAIT, + IN, ALU, C, B, IDLE, WAIT, WR, L, H, ALU, @@ -427,9 +427,9 @@ WAIT, RD, ALU, L, H, IDLE, + IDLE, + WAIT, OUT, C, B, ALU, - IDLE, - IDLE, REP_OP_O, operation, IDLE, WAIT, From 32ae549c70d570972d6bb6b6fd5f3005a2c880ca Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 3 Jun 2018 19:14:30 -0400 Subject: [PATCH 05/51] z80: Add bus request timing array to work with zx spectrum Also some clean up --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 2 + .../CPUs/Z80A/Operations.cs | 11 +- .../CPUs/Z80A/Tables_Direct.cs | 120 ++++++++++-- .../CPUs/Z80A/Tables_Indirect.cs | 66 ++++++- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 182 +++++++++--------- .../SinclairSpectrum/Machine/CPUMonitor.cs | 2 - 6 files changed, 256 insertions(+), 127 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index 57f262bd7a..8feed65cbe 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -18,8 +18,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // variables for executing instructions public int instr_pntr = 0; + public int bus_pntr = 0; public ushort instr_swap; public ushort[] cur_instr; + public ushort[] BUSRQ; public byte opcode; public bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix; public bool IXCB_prefetch, IYCB_prefetch; // value is fetched before opcode diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs index f9fe6f797f..4ec81fe298 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs @@ -18,12 +18,6 @@ namespace BizHawk.Emulation.Cores.Components.Z80A INC16_Func(src_l, src_h); } - public void I_Read_Func(ushort dest, ushort src_l, ushort src_h, ushort inc) - { - Regs[dest] = ReadMemory((ushort)((Regs[src_l] | (Regs[src_h] << 8)) + inc)); - Regs[DB] = Regs[dest]; - } - public void Write_Func(ushort dest_l, ushort dest_h, ushort src) { Regs[DB] = Regs[src]; @@ -37,10 +31,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A INC16_Func(dest_l, dest_h); } - public void I_Write_Func(ushort dest_l, ushort dest_h, ushort inc, ushort src) + public void Write_DEC_Func(ushort dest_l, ushort dest_h, ushort src) { Regs[DB] = Regs[src]; - WriteMemory((ushort)((Regs[dest_l] | (Regs[dest_h] << 8)) + inc), (byte)Regs[src]); + WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]); + DEC16_Func(dest_l, dest_h); } public void OUT_Func(ushort dest_l, ushort dest_h, ushort src) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 4ad6252352..c4ab95abf7 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -14,6 +14,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, 0 }; } // NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers @@ -25,6 +27,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void EXX_() @@ -34,6 +38,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } // this exchanges 2 16 bit registers @@ -44,17 +50,21 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void INC_16(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {INC16, src_l, src_h, + {INC16, src_l, src_h, IDLE, IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, 0, PCl, 0, 0, 0}; } @@ -67,6 +77,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, 0, PCl, 0, 0, 0}; } // this is done in two steps technically, but the flags don't work out using existing funcitons @@ -85,6 +97,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void REG_OP(ushort operation, ushort dest, ushort src) @@ -94,6 +108,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, 0 }; } // Operations using the I and R registers take one T-cycle longer @@ -105,6 +121,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, PCl, 0, 0, 0 }; } // note: do not use DEC here since no flags are affected by this operation @@ -126,6 +144,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, PCl, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0}; } else { @@ -138,6 +158,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, PCl, 0, 0, PCl, 0, 0, 0}; } } @@ -148,6 +170,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IDLE, IDLE, HALT }; + + BUSRQ = new ushort[] {PCl, 0, 0, 0 }; } private void JR_COND(bool cond) @@ -167,6 +191,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0}; } else { @@ -178,6 +204,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, 0}; } } @@ -196,6 +224,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, Z, 0, 0, 0}; } else { @@ -210,6 +240,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, PCl, 0, 0, 0}; } } @@ -226,6 +258,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; } private void RETI_() @@ -241,6 +275,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; } private void RETN_() @@ -256,6 +292,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; } @@ -275,6 +313,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; } else { @@ -284,6 +324,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {0, PCl, 0, 0, 0}; } } @@ -296,19 +338,21 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, RD_INC, Z, PCl, PCh, IDLE, - IDLE, + DEC16, SPl, SPh, WAIT, RD_INC, W, PCl, PCh, - DEC16, SPl, SPh, + IDLE, WAIT, - WR, SPl, SPh, PCh, - DEC16, SPl, SPh, + WR_DEC, SPl, SPh, PCh, + IDLE, WAIT, WR, SPl, SPh, PCl, TR16, PCl, PCh, Z, W, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, 0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; } else { @@ -323,6 +367,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, PCl, 0, 0, 0 }; } } @@ -333,6 +379,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void BIT_OP(ushort operation, ushort bit, ushort src) @@ -342,22 +390,26 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void PUSH_(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {IDLE, - DEC16, SPl, SPh, + {DEC16, SPl, SPh, + IDLE, WAIT, - WR, SPl, SPh, src_h, - DEC16, SPl, SPh, + WR_DEC, SPl, SPh, src_h, + IDLE, WAIT, WR, SPl, SPh, src_l, IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; } @@ -374,22 +426,26 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; } private void RST_(ushort n) { cur_instr = new ushort[] - {IDLE, - DEC16, SPl, SPh, + {DEC16, SPl, SPh, + IDLE, WAIT, - WR, SPl, SPh, PCh, - DEC16, SPl, SPh, + WR_DEC, SPl, SPh, PCh, + RST, n, WAIT, WR, SPl, SPh, PCl, - RST, n, + TR16, PCl, PCh, Z, W, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0 }; } private void PREFIX_(ushort src) @@ -399,6 +455,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, PREFIX, src}; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void PREFETCH_(ushort src_l, ushort src_h) @@ -408,6 +466,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, PREFIX, IXYprefetch }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void DI_() @@ -417,6 +477,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void EI_() @@ -426,6 +488,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void JP_16(ushort src_l, ushort src_h) @@ -435,6 +499,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, 0 }; } private void LD_SP_16(ushort src_l, ushort src_h) @@ -446,6 +512,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, 0, src_l, 0, 0, 0 }; } private void OUT_() @@ -462,6 +530,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP}; + + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0 ,0, PCl, 0, 0, 0}; } private void OUT_REG_(ushort dest, ushort src) @@ -475,6 +545,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP}; + + BUSRQ = new ushort[] { 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void IN_() @@ -491,6 +563,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP}; + + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void IN_REG_(ushort dest, ushort src) @@ -504,6 +578,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP}; + + BUSRQ = new ushort[] { 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -520,6 +596,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP}; + + BUSRQ = new ushort[] { 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void INT_MODE_(ushort src) @@ -529,6 +607,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; } private void RRD_() @@ -543,11 +623,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IDLE, IDLE, WAIT, - WR, Z, W, ALU, - INC16, Z, W, + WR_INC, Z, W, ALU, + IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, Z, 0, 0, 0, PCl, 0, 0, 0 }; } private void RLD_() @@ -562,11 +644,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IDLE, IDLE, WAIT, - WR, Z, W, ALU, - INC16, Z, W, + WR_INC, Z, W, ALU, + IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, Z, 0, 0, 0, PCl, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 0e0b69801e..25e2f06528 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -16,6 +16,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, src_l, 0, 0, 0, PCl, 0, 0, 0 }; } private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) @@ -32,6 +34,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; } // Note that this operation uses I_BIT, same as indexed BIT. @@ -49,6 +53,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, src_l, 0, 0, PCl, 0, 0, 0 }; } private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -61,6 +67,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, PCl, 0, 0, 0 }; } private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -73,6 +81,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, PCl, 0, 0, 0 }; } private void LD_16_IND_nn(ushort src_l, ushort src_h) @@ -86,14 +96,16 @@ RD_INC, W, PCl, PCh, IDLE, WAIT, - WR, Z, W, src_l, - INC16, Z, W, + WR_INC, Z, W, src_l, + IDLE, WAIT, WR, Z, W, src_h, IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void LD_IND_16_nn(ushort dest_l, ushort dest_h) @@ -115,6 +127,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void LD_8_IND_nn(ushort src) @@ -133,6 +147,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void LD_IND_8_nn(ushort dest) @@ -151,6 +167,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src) @@ -163,6 +181,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { dest_l, 0, 0, PCl, 0, 0, 0 }; } private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -178,6 +198,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, dest_l, 0, 0, PCl, 0, 0, 0 }; } private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h) @@ -190,6 +212,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, PCl, 0, 0, 0 }; } private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -205,6 +229,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; } private void INC_8_IND(ushort src_l, ushort src_h) @@ -221,6 +247,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; } private void DEC_8_IND(ushort src_l, ushort src_h) @@ -237,6 +265,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; } // NOTE: WZ implied for the wollowing 3 functions @@ -254,6 +284,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_BIT_OP(ushort operation, ushort bit, ushort dest) @@ -270,6 +302,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_BIT_TE(ushort bit) @@ -283,6 +317,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_OP_n(ushort operation, ushort src_l, ushort src_h) @@ -307,6 +343,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_OP_n_n(ushort src_l, ushort src_h) @@ -327,6 +365,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, PCl, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -347,6 +387,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) @@ -367,6 +409,8 @@ WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, Z, 0, 0, 0, PCl, 0, 0, 0 }; } private void LD_OP_R(ushort operation, ushort repeat_instr) @@ -384,6 +428,8 @@ WAIT, OP_F, OP_R, 0, operation, repeat_instr }; + + BUSRQ = new ushort[] { L, 0, 0, E, 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void CP_OP_R(ushort operation, ushort repeat_instr) @@ -401,6 +447,8 @@ WAIT, OP_F, OP_R, 1, operation, repeat_instr }; + + BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; } private void IN_OP_R(ushort operation, ushort repeat_instr) @@ -418,6 +466,8 @@ WAIT, OP_F, OP_R, 2, operation, repeat_instr }; + + BUSRQ = new ushort[] { 0, 0, 0, 0, L, 0, 0, 0, PCl, 0, 0, 0 }; } private void OUT_OP_R(ushort operation, ushort repeat_instr) @@ -435,6 +485,8 @@ WAIT, OP_F, OP_R, 3, operation, repeat_instr }; + + BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; } // this is an indirect change of a a 16 bit register with memory @@ -444,22 +496,24 @@ {IDLE, WAIT, RD, Z, dest_l, dest_h, - IDLE, + INC16, dest_l, dest_h, IDLE, WAIT, - I_RD, W, dest_l, dest_h, 1, + RD, W, dest_l, dest_h, IDLE, WAIT, - WR, dest_l, dest_h, src_l, + WR_DEC, dest_l, dest_h, src_h, IDLE, IDLE, IDLE, WAIT, - I_WR, dest_l, dest_h, 1, src_h, + WR, dest_l, dest_h, 1, src_l, TR16, src_l, src_h, Z, W, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { dest_l, 0, 0, 0, dest_l, 0, 0, dest_l, 0, 0, 0, 0, dest_l, 0, 0, PCl, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 867b83a1e0..5291fb597a 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -18,70 +18,70 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort HALT = 3; public const ushort RD = 4; public const ushort WR = 5; - public const ushort I_RD = 6; - public const ushort I_WR = 7; - public const ushort TR = 8; - public const ushort TR16 = 9; - public const ushort ADD16 = 10; - public const ushort ADD8 = 11; - public const ushort SUB8 = 12; - public const ushort ADC8 = 13; - public const ushort SBC8 = 14; - public const ushort SBC16 = 15; - public const ushort ADC16 = 16; - public const ushort INC16 = 17; - public const ushort INC8 = 18; - public const ushort DEC16 = 19; - public const ushort DEC8 = 20; - public const ushort RLC = 21; - public const ushort RL = 22; - public const ushort RRC = 23; - public const ushort RR = 24; - public const ushort CPL = 25; - public const ushort DA = 26; - public const ushort SCF = 27; - public const ushort CCF = 28; - public const ushort AND8 = 29; - public const ushort XOR8 = 30; - public const ushort OR8 = 31; - public const ushort CP8 = 32; - public const ushort SLA = 33; - public const ushort SRA = 34; - public const ushort SRL = 35; - public const ushort SLL = 36; - public const ushort BIT = 37; - public const ushort RES = 38; - public const ushort SET = 39; - public const ushort EI = 40; - public const ushort DI = 41; - public const ushort EXCH = 42; - public const ushort EXX = 43; - public const ushort EXCH_16 = 44; - public const ushort PREFIX = 45; - public const ushort PREFETCH = 46; - public const ushort ASGN = 47; - public const ushort ADDS = 48; // signed 16 bit operation used in 2 instructions - public const ushort INT_MODE = 49; - public const ushort EI_RETN = 50; - public const ushort EI_RETI = 51; // reti has no delay in interrupt enable - public const ushort OUT = 52; - public const ushort IN = 53; - public const ushort NEG = 54; - public const ushort RRD = 55; - public const ushort RLD = 56; - public const ushort SET_FL_LD = 57; - public const ushort SET_FL_CP = 58; - public const ushort SET_FL_IR = 59; - public const ushort I_BIT = 60; - public const ushort HL_BIT = 61; - public const ushort FTCH_DB = 62; - public const ushort WAIT = 63; // enterred when readin or writing and FlagW is true - public const ushort OP_F = 64; // fetch the opcode, happens on cycle 3 of fetch cycle - public const ushort RD_INC = 65; // read and increment + public const ushort RD_INC = 6; // read and increment + public const ushort WR_INC = 7; // write and increment + public const ushort WR_DEC = 8; // write and increment (for stack pointer) + public const ushort TR = 9; + public const ushort TR16 = 10; + public const ushort ADD16 = 11; + public const ushort ADD8 = 12; + public const ushort SUB8 = 13; + public const ushort ADC8 = 14; + public const ushort SBC8 = 15; + public const ushort SBC16 = 16; + public const ushort ADC16 = 17; + public const ushort INC16 = 18; + public const ushort INC8 = 19; + public const ushort DEC16 = 20; + public const ushort DEC8 = 21; + public const ushort RLC = 22; + public const ushort RL = 23; + public const ushort RRC = 24; + public const ushort RR = 25; + public const ushort CPL = 26; + public const ushort DA = 27; + public const ushort SCF = 28; + public const ushort CCF = 29; + public const ushort AND8 = 30; + public const ushort XOR8 = 31; + public const ushort OR8 = 32; + public const ushort CP8 = 33; + public const ushort SLA = 34; + public const ushort SRA = 35; + public const ushort SRL = 36; + public const ushort SLL = 37; + public const ushort BIT = 38; + public const ushort RES = 39; + public const ushort SET = 40; + public const ushort EI = 41; + public const ushort DI = 42; + public const ushort EXCH = 43; + public const ushort EXX = 44; + public const ushort EXCH_16 = 45; + public const ushort PREFIX = 46; + public const ushort PREFETCH = 47; + public const ushort ASGN = 48; + public const ushort ADDS = 49; // signed 16 bit operation used in 2 instructions + public const ushort INT_MODE = 50; + public const ushort EI_RETN = 51; + public const ushort EI_RETI = 52; // reti has no delay in interrupt enable + public const ushort OUT = 53; + public const ushort IN = 54; + public const ushort NEG = 55; + public const ushort RRD = 56; + public const ushort RLD = 57; + public const ushort SET_FL_LD = 58; + public const ushort SET_FL_CP = 59; + public const ushort SET_FL_IR = 60; + public const ushort I_BIT = 61; + public const ushort HL_BIT = 62; + public const ushort FTCH_DB = 63; + public const ushort WAIT = 64; // enterred when readin or writing and FlagW is true + public const ushort OP_F = 65; // fetch the opcode, happens on cycle 3 of fetch cycle public const ushort RST = 66; - public const ushort WR_INC = 67; // write and increment - public const ushort REP_OP_I = 68; - public const ushort REP_OP_O = 69; + public const ushort REP_OP_I = 67; + public const ushort REP_OP_O = 68; + public byte temp_R; @@ -101,7 +101,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, OP_F, OP }; - instr_pntr = 0; + + BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + instr_pntr = 0; bus_pntr = 0; NO_prefix = true; } @@ -157,6 +159,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // Execute instructions public void ExecuteOne() { + bus_pntr++; switch (cur_instr[instr_pntr++]) { case IDLE: @@ -184,7 +187,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A iff1 = false; NMI_(); NMICallback(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; } else if (iff1 && FlagI) { @@ -211,7 +214,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A break; } IRQCallback(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; } else { @@ -219,7 +222,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (TraceCallback != null) TraceCallback(State()); RegPC++; FetchInstruction(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; } temp_R = (byte)(Regs[R] & 0x7F); @@ -263,7 +266,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - instr_pntr = 0; + BUSRQ = new ushort[] { 0, PCl, 0, 0, 0 }; + + instr_pntr = 0; bus_pntr = 0; // adjust WZ register accordingly switch (temp1) { @@ -311,7 +316,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A iff1 = false; NMI_(); NMICallback(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; } else if (iff1 && FlagI) { @@ -338,7 +343,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A break; } IRQCallback(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; } else { @@ -346,7 +351,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (TraceCallback != null) TraceCallback(State()); RegPC++; FetchInstruction(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; } temp_R = (byte)(Regs[R] & 0x7F); @@ -410,20 +415,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IRQCallback(); halted = false; } - else - { - cur_instr = new ushort[] - {IDLE, - IDLE, - IDLE, - HALT }; - } + temp_R = (byte)(Regs[R] & 0x7F); temp_R++; temp_R &= 0x7F; Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; break; case RD: Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); @@ -431,11 +429,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case WR: Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; - case I_RD: - I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + case RD_INC: + Read_INC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; - case I_WR: - I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + case WR_INC: + Write_INC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR_DEC: + Write_DEC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; case TR: TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); @@ -565,7 +566,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A RegPC++; FetchInstruction(); - instr_pntr = 0; + instr_pntr = 0; bus_pntr = 0; // only the first prefix in a double prefix increases R, although I don't know how / why if (prefix_src < 4) { @@ -624,22 +625,15 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (FlagW) { instr_pntr--; + bus_pntr--; } break; case OP_F: opcode = FetchMemory(RegPC); break; - case RD_INC: - Read_INC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; - case WR_INC: - Write_INC_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - break; case RST: Regs[Z] = cur_instr[instr_pntr++]; Regs[W] = 0; - Regs[PCl] = Regs[Z]; - Regs[PCh] = Regs[W]; break; case REP_OP_I: ushort temp4 = cur_instr[instr_pntr++]; @@ -747,7 +741,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A ser.Sync("EI_pending", ref EI_pending); ser.Sync("instr_pntr", ref instr_pntr); + ser.Sync("bus_pntr", ref bus_pntr); ser.Sync("cur_instr", ref cur_instr, false); + ser.Sync("BUSRQ", ref BUSRQ, false); ser.Sync("instr_swap", ref instr_swap); ser.Sync("opcode", ref opcode); ser.Sync("FlagI", ref FlagI); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index d2cff11e0e..d098cc94a4 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -123,8 +123,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case Z80A.RD_INC: case Z80A.WR: case Z80A.WR_INC: - case Z80A.I_RD: - case Z80A.I_WR: addr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 4]] | _cpu.Regs[cur_instr[instr_pntr + 5]] << 8); if (_machine.IsContended(addr)) { From 7677b75de3c0f31733b541415f848255d23d5d2a Mon Sep 17 00:00:00 2001 From: Asnivor Date: Mon, 4 Jun 2018 10:35:12 +0100 Subject: [PATCH 06/51] ZXHawk: Start building on new BUSRQ implementation --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 139 +++++++----------- .../SinclairSpectrum/Machine/SpectrumBase.cs | 5 +- .../Machine/ZXSpectrum128K/ZX128.Memory.cs | 2 + .../ZX128Plus2a.Memory.cs | 2 + .../ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 2 + .../Machine/ZXSpectrum16K/ZX16.cs | 4 + .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 3 + 7 files changed, 70 insertions(+), 87 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index d098cc94a4..e345c44c4f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -23,6 +23,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public int instr_pntr => _cpu.instr_pntr; public ushort RegPC => _cpu.RegPC; public long TotalExecutedCycles => _cpu.TotalExecutedCycles; + public ushort BUSRQ + { + get + { + if (_cpu.bus_pntr < _cpu.BUSRQ.Length - 1) + return _cpu.BUSRQ[_cpu.bus_pntr]; + + return 0; + } + } /// /// Called when the first byte of an instruction is fetched @@ -39,106 +49,67 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void Cycle() { - if (portContending) { RunPortContention(); } - /* else { - // check for wait state on cycle that has just happened - // next cycle should be a read/write operation - if (cur_instr[instr_pntr] == Z80A.WAIT) - { - ushort addr = 0; - bool abort = false; + // check for upcoming BUSRQ + if (BUSRQ == 0) + return; - // identify the type of operation and get the targetted address - switch (cur_instr[instr_pntr + 1]) - { - // op fetch - case Z80A.OP_F: - addr = RegPC; - break; - // read/writes - case Z80A.RD: - case Z80A.RD_INC: - case Z80A.WR: - case Z80A.WR_INC: - addr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 3]] | _cpu.Regs[cur_instr[instr_pntr + 4]] << 8); - break; - default: - abort = true; - break; - } - - if (!abort) - { - // is the address in a potentially contended bank? - if (_machine.IsContended(addr)) - { - // will the ULA be contending this address on the next cycle? - var delay = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle + 1); - _cpu.TotalExecutedCycles += delay; - } - } - } - - } - */ - return; - // check for wait state on next cycle - // the cycle after that should be a read/write operation or op fetch - if (instr_pntr >= cur_instr.Length - 1) - { - // will overflow - return; - } - - if (cur_instr[instr_pntr + 1] == Z80A.WAIT) - { - // return; ushort addr = 0; - // identify the type of operation and get the targetted address - var op = cur_instr[instr_pntr + 2]; - switch (op) + switch (BUSRQ) { - // op fetch - case Z80A.OP_F: - addr = (ushort)(RegPC); - if (_machine.IsContended(addr)) - { - var delay = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (delay > 0) - { - _cpu.TotalExecutedCycles += delay; - _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); - } - } + // PCl + case 0: + addr = (ushort)(_cpu.Regs[_cpu.PCl] | _cpu.Regs[_cpu.PCh] << 8); break; - // read/writes - case Z80A.RD: - case Z80A.RD_INC: - case Z80A.WR: - case Z80A.WR_INC: - addr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 4]] | _cpu.Regs[cur_instr[instr_pntr + 5]] << 8); - if (_machine.IsContended(addr)) - { - var delay = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (delay > 0) - { - _cpu.TotalExecutedCycles += delay; - _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); - } - } + // Z + case 13: + addr = (ushort)(_cpu.Regs[_cpu.Z] | _cpu.Regs[_cpu.W] << 8); break; - case Z80A.FTCH_DB: + // SPl + case 2: + addr = (ushort)(_cpu.Regs[_cpu.SPl] | _cpu.Regs[_cpu.SPh] << 8); break; + // L + case 11: + addr = (ushort)(_cpu.Regs[_cpu.L] | _cpu.Regs[_cpu.H] << 8); + break; + // I + case 21: + addr = (ushort)(_cpu.Regs[_cpu.R] | _cpu.Regs[_cpu.I] << 8); + break; + // Ixl + case 15: + addr = (ushort)(_cpu.Regs[_cpu.Ixl] | _cpu.Regs[_cpu.Ixh] << 8); + break; + // Iyl + case 17: + addr = (ushort)(_cpu.Regs[_cpu.Iyl] | _cpu.Regs[_cpu.Iyh] << 8); + break; + // A + case 4: + addr = (ushort)(_cpu.Regs[_cpu.F] | _cpu.Regs[_cpu.A] << 8); + break; + // B + case 6: + addr = (ushort)(_cpu.Regs[_cpu.C] | _cpu.Regs[_cpu.B] << 8); + break; + // D + case 8: + addr = (ushort)(_cpu.Regs[_cpu.E] | _cpu.Regs[_cpu.D] << 8); + break; + default: break; } + + if (_machine.IsContended(addr)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(); } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index d6bea89b67..a87c006336 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -169,10 +169,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // check for interrupt ULADevice.CheckForInterrupt(CurrentFrameCycle); - // run a single CPU instruction - + // run a single CPU instruction CPU.ExecuteOne(); - + // check contention for next cycle CPUMon.Cycle(); // cycle the tape device diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs index 3ab198737e..df1d5587da 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs @@ -212,11 +212,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendMemory(ushort addr) { + /* if (IsContended(addr)) { var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); CPU.TotalExecutedCycles += delay; } + */ } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs index 26ae8ef939..d4c46af37f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs @@ -400,11 +400,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendMemory(ushort addr) { + /* if (IsContended(addr)) { var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); CPU.TotalExecutedCycles += delay; } + */ } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index 68a3841244..e288b67c86 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -400,11 +400,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendMemory(ushort addr) { + /* if (IsContended(addr)) { var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); CPU.TotalExecutedCycles += delay; } + */ } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs index 1d9c7edc0b..c17d90fe26 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs @@ -98,8 +98,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { + /* if (IsContended(addr)) CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle); + */ var data = ReadBus(addr); return data; @@ -113,12 +115,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { + /* // apply contention if necessary if (IsContended(addr)) { ULADevice.RenderScreen((int)CurrentFrameCycle); CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle); } + */ WriteBus(addr, value); } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index 7dd6f3cd21..2006f35c02 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -122,6 +122,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendMemory(ushort addr) { + return; + /* if (IsContended(addr)) { var off = 1; @@ -138,6 +140,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } CPU.TotalExecutedCycles += delay; } + */ } /// From 1125ccedc3792d8f0ede6502e6340997508b0f86 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 4 Jun 2018 07:52:48 -0400 Subject: [PATCH 07/51] z80: fix a bug --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 25e2f06528..1a37a84f9d 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -507,7 +507,7 @@ IDLE, IDLE, WAIT, - WR, dest_l, dest_h, 1, src_l, + WR, dest_l, dest_h, src_l, TR16, src_l, src_h, Z, W, WAIT, OP_F, From 9f4b6f1ecf19f2a74d84fb83fd09eeace38eddd5 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 4 Jun 2018 08:57:12 -0400 Subject: [PATCH 08/51] z80: Bus timing on interrupts --- .../CPUs/Z80A/Interrupts.cs | 48 +++++++++++-------- .../CPUs/Z80A/Registers.cs | 7 +++ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs index 648590c92b..442fe109f6 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -34,16 +34,18 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {DEC16, SPl, SPh, + TR, ALU, PCl, WAIT, - WR, SPl, SPh, PCh, - DEC16, SPl, SPh, + WR_DEC, SPl, SPh, PCh, + TR16, PCl, PCh, NMI_V, ZERO, WAIT, - WR, SPl, SPh, PCl, - ASGN, PCl, 0x66, - ASGN, PCh, 0, + WR, SPl, SPh, ALU, + IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; } // Mode 0 interrupts only take effect if a CALL or RST is on the data bus @@ -56,55 +58,61 @@ namespace BizHawk.Emulation.Cores.Components.Z80A cur_instr = new ushort[] {IDLE, WAIT, - RD, ALU, PCl, PCh, - INC16, PCl, PCh, + RD_INC, ALU, PCl, PCh, + IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, 0 }; } // Just jump to $0038 private void INTERRUPT_1() { cur_instr = new ushort[] - {DEC16, SPl, SPh, - WAIT, - WR, SPl, SPh, PCh, + {IDLE, + ASGN, ALU, PCl, DEC16, SPl, SPh, - WAIT, - WR, SPl, SPh, PCl, - ASGN, PCl, 0x38, IDLE, - ASGN, PCh, 0, + WAIT, + WR_DEC, SPl, SPh, PCh, + TR16, PCl, PCh, IRQ_V, ZERO, + WAIT, + WR, SPl, SPh, ALU, IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, 0, 0, SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; } // Interrupt mode 2 uses the I vector combined with a byte on the data bus private void INTERRUPT_2() { cur_instr = new ushort[] - {IDLE, - WAIT, - FTCH_DB, - TR16, Z, W, DB, I, + {FTCH_DB, + IDLE, DEC16, SPl, SPh, + TR16, Z, W, DB, I, WAIT, - WR, SPl, SPh, PCh, - DEC16, SPl, SPh, + WR_DEC, SPl, SPh, PCh, + IDLE, WAIT, WR, SPl, SPh, PCl, IDLE, WAIT, RD_INC, PCl, Z, W, IDLE, + WAIT, RD, PCh, Z, W, IDLE, WAIT, OP_F, OP }; + + BUSRQ = new ushort[] { 0, 0, 0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, Z, 0 ,0 ,PCl, 0, 0, 0 }; } private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index 0e8dde3435..b1fd71d5b9 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -40,6 +40,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public ushort H_s = 30; public ushort L_s = 31; public ushort DB = 32; + public ushort IRQ_V = 34; // IRQ mode 1 vector + public ushort NMI_V = 35; // NMI vector public ushort[] Regs = new ushort[36]; @@ -112,6 +114,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Regs[i] = 0; } + // the IRQ1 vector is 0x38 + Regs[IRQ_V] = 0x38; + // The NMI vector is constant 0x66 + Regs[NMI_V] = 0x66; + FlagI = false; FlagW = false; } From 2661b0804cfd8f5d0ac67af66e9c7b4cb74a998a Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 4 Jun 2018 11:15:26 -0400 Subject: [PATCH 09/51] z80: fix a typo --- BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs index 442fe109f6..a84fc640c0 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -72,7 +72,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, - ASGN, ALU, PCl, + TR, ALU, PCl, DEC16, SPl, SPh, IDLE, WAIT, From bff3f41c9af3114b48d165d4dd316661f0435493 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 4 Jun 2018 11:42:59 -0400 Subject: [PATCH 10/51] z80: IN/OUT access fixes --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs | 10 +++++----- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index c4ab95abf7..4307f34705 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -523,10 +523,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, RD_INC, Z, PCl, PCh, IDLE, + IDLE, TR, W, A, OUT, Z, W, A, - INC16, Z, W, - IDLE, + INC16, Z, W, WAIT, OP_F, OP}; @@ -538,10 +538,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A { cur_instr = new ushort[] {IDLE, + IDLE, TR16, Z, W, C, B, OUT, Z, W, src, - INC16, Z, W, - IDLE, + INC16, Z, W, WAIT, OP_F, OP}; @@ -556,10 +556,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, RD_INC, Z, PCl, PCh, IDLE, + IDLE, TR, W, A, IN, A, Z, W, INC16, Z, W, - IDLE, WAIT, OP_F, OP}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 1a37a84f9d..0189229958 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -380,15 +380,15 @@ IDLE, ADDS, Z, W, ALU, ZERO, IDLE, + IDLE, WAIT, RD, ALU, Z, W, - operation, dest, ALU, - IDLE, + operation, dest, ALU, WAIT, OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) @@ -410,7 +410,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, Z, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; } private void LD_OP_R(ushort operation, ushort repeat_instr) From 7dfd19de2b6b1e50ebe770aa907895f7c3c46672 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Mon, 4 Jun 2018 17:11:12 +0100 Subject: [PATCH 11/51] ZXHawk: Fix memory contention lookup overflow --- .../Computers/SinclairSpectrum/Machine/CPUMonitor.cs | 2 +- .../Computers/SinclairSpectrum/Machine/ULA.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index e345c44c4f..8cfd43c657 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -109,7 +109,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } if (_machine.IsContended(addr)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(); + _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue((int)(_machine.CurrentFrameCycle + 1)); } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 72bd3bc3ba..59abd58290 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -752,7 +752,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetContentionValue() { - return RenderingTable.Renderer[_machine.CurrentFrameCycle].ContentionValue; + var f = _machine.CurrentFrameCycle; + if (f >= FrameCycleLength) + f -= FrameCycleLength; + + return RenderingTable.Renderer[f].ContentionValue; } /// From beae64d563beaff5a1d981c9d24eead29275fc82 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 4 Jun 2018 14:27:57 -0400 Subject: [PATCH 12/51] z80: use high byte BUSRQ vector since PCl = 0 so the look up fails (oops) --- .../CPUs/Z80A/Interrupts.cs | 8 +- .../CPUs/Z80A/Tables_Direct.cs | 84 +++++++++---------- .../CPUs/Z80A/Tables_Indirect.cs | 54 ++++++------ BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 2 +- .../SinclairSpectrum/Machine/CPUMonitor.cs | 69 ++++++++------- 5 files changed, 108 insertions(+), 109 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs index a84fc640c0..9b1426505c 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -45,7 +45,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } // Mode 0 interrupts only take effect if a CALL or RST is on the data bus @@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0 }; } // Just jump to $0038 @@ -85,7 +85,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, 0, 0, SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } // Interrupt mode 2 uses the I vector combined with a byte on the data bus @@ -112,7 +112,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, 0, 0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, Z, 0 ,0 ,PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, W, 0 ,0 ,PCh, 0, 0, 0 }; } private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 4307f34705..a41949ee0c 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, 0 }; + BUSRQ = new ushort[] {PCh, 0, 0, 0 }; } // NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers @@ -28,7 +28,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void EXX_() @@ -39,7 +39,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } // this exchanges 2 16 bit registers @@ -51,7 +51,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void INC_16(ushort src_l, ushort src_h) @@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {0, 0, PCh, 0, 0, 0}; } @@ -78,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {0, 0, PCh, 0, 0, 0}; } // this is done in two steps technically, but the flags don't work out using existing funcitons @@ -98,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] {0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP(ushort operation, ushort dest, ushort src) @@ -109,7 +109,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, 0 }; + BUSRQ = new ushort[] {PCh, 0, 0, 0 }; } // Operations using the I and R registers take one T-cycle longer @@ -122,7 +122,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] {0, PCh, 0, 0, 0 }; } // note: do not use DEC here since no flags are affected by this operation @@ -145,7 +145,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCl, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {0, PCh, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0}; } else { @@ -159,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCl, 0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {0, PCh, 0, 0, PCh, 0, 0, 0}; } } @@ -171,7 +171,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IDLE, HALT }; - BUSRQ = new ushort[] {PCl, 0, 0, 0 }; + BUSRQ = new ushort[] {PCh, 0, 0, 0 }; } private void JR_COND(bool cond) @@ -192,7 +192,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0}; } else { @@ -205,7 +205,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, 0}; } } @@ -225,7 +225,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, Z, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, W, 0, 0, 0}; } else { @@ -241,7 +241,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0}; } } @@ -259,7 +259,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; + BUSRQ = new ushort[] {SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } private void RETI_() @@ -276,7 +276,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; + BUSRQ = new ushort[] {SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } private void RETN_() @@ -293,7 +293,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; + BUSRQ = new ushort[] {SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } @@ -314,7 +314,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; + BUSRQ = new ushort[] {0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } else { @@ -325,7 +325,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] {0, PCh, 0, 0, 0}; } } @@ -352,7 +352,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCl, 0, 0, PCl, 0, 0, 0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } else { @@ -368,7 +368,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0 }; } } @@ -380,7 +380,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void BIT_OP(ushort operation, ushort bit, ushort src) @@ -391,7 +391,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void PUSH_(ushort src_l, ushort src_h) @@ -409,7 +409,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } @@ -427,7 +427,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { SPl, 0, 0, SPl, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } private void RST_(ushort n) @@ -445,7 +445,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, SPl, 0, 0, SPl, 0, 0, Z, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } private void PREFIX_(ushort src) @@ -456,7 +456,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, PREFIX, src}; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void PREFETCH_(ushort src_l, ushort src_h) @@ -467,7 +467,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, PREFIX, IXYprefetch }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void DI_() @@ -478,7 +478,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void EI_() @@ -489,7 +489,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void JP_16(ushort src_l, ushort src_h) @@ -500,7 +500,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, 0 }; } private void LD_SP_16(ushort src_l, ushort src_h) @@ -513,7 +513,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, 0, src_l, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, src_h, 0, 0, 0 }; } private void OUT_() @@ -531,7 +531,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0 ,0, PCl, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0 ,0, PCh, 0, 0, 0}; } private void OUT_REG_(ushort dest, ushort src) @@ -546,7 +546,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void IN_() @@ -564,7 +564,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void IN_REG_(ushort dest, ushort src) @@ -579,7 +579,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -597,7 +597,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void INT_MODE_(ushort src) @@ -608,7 +608,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } private void RRD_() @@ -629,7 +629,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, Z, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, W, 0, 0, 0, PCh, 0, 0, 0 }; } private void RLD_() @@ -650,7 +650,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, Z, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, W, 0, 0, 0, PCh, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 0189229958..b26802d32e 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -17,7 +17,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, src_l, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, 0, 0, 0, PCh, 0, 0, 0 }; } private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) @@ -35,7 +35,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } // Note that this operation uses I_BIT, same as indexed BIT. @@ -54,7 +54,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, src_h, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -68,7 +68,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -82,7 +82,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } private void LD_16_IND_nn(ushort src_l, ushort src_h) @@ -105,7 +105,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_16_nn(ushort dest_l, ushort dest_h) @@ -128,7 +128,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_8_IND_nn(ushort src) @@ -148,7 +148,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_8_nn(ushort dest) @@ -168,7 +168,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, PCl, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src) @@ -182,7 +182,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { dest_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { dest_h, 0, 0, PCh, 0, 0, 0 }; } private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -199,7 +199,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, dest_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, dest_h, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h) @@ -213,7 +213,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -230,7 +230,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } private void INC_8_IND(ushort src_l, ushort src_h) @@ -248,7 +248,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } private void DEC_8_IND(ushort src_l, ushort src_h) @@ -266,7 +266,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_l, 0, 0, src_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } // NOTE: WZ implied for the wollowing 3 functions @@ -285,7 +285,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_BIT_OP(ushort operation, ushort bit, ushort dest) @@ -303,7 +303,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_BIT_TE(ushort bit) @@ -318,7 +318,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_OP_n(ushort operation, ushort src_l, ushort src_h) @@ -344,7 +344,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_OP_n_n(ushort src_l, ushort src_h) @@ -366,7 +366,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, PCl, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -388,7 +388,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) @@ -410,7 +410,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCh, 0, 0, 0 }; } private void LD_OP_R(ushort operation, ushort repeat_instr) @@ -429,7 +429,7 @@ OP_F, OP_R, 0, operation, repeat_instr }; - BUSRQ = new ushort[] { L, 0, 0, E, 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, D, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void CP_OP_R(ushort operation, ushort repeat_instr) @@ -448,7 +448,7 @@ OP_F, OP_R, 1, operation, repeat_instr }; - BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void IN_OP_R(ushort operation, ushort repeat_instr) @@ -467,7 +467,7 @@ OP_F, OP_R, 2, operation, repeat_instr }; - BUSRQ = new ushort[] { 0, 0, 0, 0, L, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, 0, 0, 0, H, 0, 0, 0, PCh, 0, 0, 0 }; } private void OUT_OP_R(ushort operation, ushort repeat_instr) @@ -486,7 +486,7 @@ OP_F, OP_R, 3, operation, repeat_instr }; - BUSRQ = new ushort[] { L, 0, 0, 0, 0, 0, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } // this is an indirect change of a a 16 bit register with memory @@ -513,7 +513,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { dest_l, 0, 0, 0, dest_l, 0, 0, dest_l, 0, 0, 0, 0, dest_l, 0, 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { dest_h, 0, 0, 0, dest_h, 0, 0, dest_h, 0, 0, 0, 0, dest_h, 0, 0, PCh, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 5291fb597a..051b727a0d 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -266,7 +266,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { 0, PCh, 0, 0, 0 }; instr_pntr = 0; bus_pntr = 0; // adjust WZ register accordingly diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 8cfd43c657..00f581c7aa 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -27,10 +27,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { get { - if (_cpu.bus_pntr < _cpu.BUSRQ.Length - 1) - return _cpu.BUSRQ[_cpu.bus_pntr]; + //if (_cpu.bus_pntr < _cpu.BUSRQ.Length - 1) + return _cpu.BUSRQ[_cpu.bus_pntr]; - return 0; + //return 0; } } @@ -63,48 +63,47 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum switch (BUSRQ) { - // PCl - case 0: + // PCh + case 1: addr = (ushort)(_cpu.Regs[_cpu.PCl] | _cpu.Regs[_cpu.PCh] << 8); break; - // Z - case 13: - addr = (ushort)(_cpu.Regs[_cpu.Z] | _cpu.Regs[_cpu.W] << 8); - break; - // SPl - case 2: + // SPh + case 3: addr = (ushort)(_cpu.Regs[_cpu.SPl] | _cpu.Regs[_cpu.SPh] << 8); break; - // L - case 11: + // A + case 4: + addr = (ushort)(_cpu.Regs[_cpu.F] | _cpu.Regs[_cpu.A] << 8); + break; + // B + case 6: + addr = (ushort)(_cpu.Regs[_cpu.C] | _cpu.Regs[_cpu.B] << 8); + break; + // D + case 8: + addr = (ushort)(_cpu.Regs[_cpu.E] | _cpu.Regs[_cpu.D] << 8); + break; + // H + case 10: addr = (ushort)(_cpu.Regs[_cpu.L] | _cpu.Regs[_cpu.H] << 8); break; - // I - case 21: - addr = (ushort)(_cpu.Regs[_cpu.R] | _cpu.Regs[_cpu.I] << 8); - break; - // Ixl - case 15: + // W + case 12: + addr = (ushort)(_cpu.Regs[_cpu.Z] | _cpu.Regs[_cpu.W] << 8); + break; + // Ixh + case 16: addr = (ushort)(_cpu.Regs[_cpu.Ixl] | _cpu.Regs[_cpu.Ixh] << 8); break; - // Iyl - case 17: + // Iyh + case 18: addr = (ushort)(_cpu.Regs[_cpu.Iyl] | _cpu.Regs[_cpu.Iyh] << 8); break; - // A - case 4: - addr = (ushort)(_cpu.Regs[_cpu.F] | _cpu.Regs[_cpu.A] << 8); - break; - // B - case 6: - addr = (ushort)(_cpu.Regs[_cpu.C] | _cpu.Regs[_cpu.B] << 8); - break; - // D - case 8: - addr = (ushort)(_cpu.Regs[_cpu.E] | _cpu.Regs[_cpu.D] << 8); - break; - - default: + // I + case 21: + addr = (ushort)(_cpu.Regs[_cpu.R] | _cpu.Regs[_cpu.I] << 8); + break; + default: break; } From f764c137ee924690de9142681bcc0d407776f773 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 5 Jun 2018 17:14:37 +0100 Subject: [PATCH 13/51] ZXHawk: 48k timing work --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 334 +++++++++++++----- .../SinclairSpectrum/Machine/SpectrumBase.cs | 8 +- .../Computers/SinclairSpectrum/Machine/ULA.cs | 59 +++- .../Machine/ZXSpectrum128K/ZX128.Port.cs | 2 +- .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 2 +- .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 2 +- .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 4 +- .../Machine/ZXSpectrum48K/ZX48.Port.cs | 2 +- .../Machine/ZXSpectrum48K/ZX48.Screen.cs | 2 +- 9 files changed, 311 insertions(+), 104 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 00f581c7aa..1623679213 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -9,15 +9,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { public class CPUMonitor { + #region Devices + private SpectrumBase _machine; private Z80A _cpu; public MachineType machineType = MachineType.ZXSpectrum48; - public CPUMonitor(SpectrumBase machine) - { - _machine = machine; - _cpu = _machine.CPU; - } + #endregion + + #region Lookups public ushort[] cur_instr => _cpu.cur_instr; public int instr_pntr => _cpu.instr_pntr; @@ -34,91 +34,240 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } } - /// - /// Called when the first byte of an instruction is fetched - /// - /// - public void OnExecFetch(ushort firstByte) + #endregion + + #region Construction + + public CPUMonitor(SpectrumBase machine) { - // fetch instruction without incrementing pc - //_cpu.FetchInstruction(_cpu.FetchMemory(firstByte)); + _machine = machine; + _cpu = _machine.CPU; } + #endregion + + #region State + + public bool IsContending = false; + public int ContCounter = -1; + public int portContCounter = 0; + public int portContTotalLen = 0; + public bool portContending = false; + public ushort lastPortAddr; + public int[] portContArr = new int[4]; + + #endregion + + #region Methods + /// - /// A CPU monitor cycle + /// Handles the ULA and CPU cycle clocks, along with any memory and port contention /// - public void Cycle() + public void ExecuteCycle() { + _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); + if (portContending) { RunPortContention(); } else { - // check for upcoming BUSRQ - if (BUSRQ == 0) - return; - - ushort addr = 0; - - switch (BUSRQ) + // is the next CPU cycle causing a BUSRQ? + if (BUSRQ > 0) { - // PCh - case 1: - addr = (ushort)(_cpu.Regs[_cpu.PCl] | _cpu.Regs[_cpu.PCh] << 8); - break; - // SPh - case 3: - addr = (ushort)(_cpu.Regs[_cpu.SPl] | _cpu.Regs[_cpu.SPh] << 8); - break; - // A - case 4: - addr = (ushort)(_cpu.Regs[_cpu.F] | _cpu.Regs[_cpu.A] << 8); - break; - // B - case 6: - addr = (ushort)(_cpu.Regs[_cpu.C] | _cpu.Regs[_cpu.B] << 8); - break; - // D - case 8: - addr = (ushort)(_cpu.Regs[_cpu.E] | _cpu.Regs[_cpu.D] << 8); - break; - // H - case 10: - addr = (ushort)(_cpu.Regs[_cpu.L] | _cpu.Regs[_cpu.H] << 8); - break; - // W - case 12: - addr = (ushort)(_cpu.Regs[_cpu.Z] | _cpu.Regs[_cpu.W] << 8); - break; - // Ixh - case 16: - addr = (ushort)(_cpu.Regs[_cpu.Ixl] | _cpu.Regs[_cpu.Ixh] << 8); - break; - // Iyh - case 18: - addr = (ushort)(_cpu.Regs[_cpu.Iyl] | _cpu.Regs[_cpu.Iyh] << 8); - break; - // I - case 21: - addr = (ushort)(_cpu.Regs[_cpu.R] | _cpu.Regs[_cpu.I] << 8); - break; - default: - break; + // is the memory address of the BUSRQ potentially contended? + if (_machine.IsContended(AscertainBUSRQAddress())) + { + var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (cont > 0) + { + _cpu.TotalExecutedCycles += cont; + } + } + } + } + + _cpu.ExecuteOne(); + + /* + else if (ContCounter > 0) + { + // still contention cycles to process + IsContending = true; + } + else + { + // is the next CPU cycle causing a BUSRQ? + if (BUSRQ > 0) + { + // is the memory address of the BUSRQ potentially contended? + if (_machine.IsContended(AscertainBUSRQAddress())) + { + var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (cont > 0) + { + ContCounter = cont + 1; + IsContending = true; + } + } + } + } + /* + else + { + // no contention cycles to process (so far) on this cycle + IsContending = false; + ContCounter = 0; + + if (portContending) + { + // a port operation is still in progress + portContCounter++; + if (portContCounter > 3) + { + // we are now out of the IN/OUT operation + portContCounter = 0; + portContending = false; + } + else + { + // still IN/OUT cycles to process + if (IsPortContended(portContCounter)) + { + var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (cont > 0) + { + ContCounter = cont + 1; + IsContending = true; + // dont let this fall through + // just manually do the first contention cycle + ContCounter--; + _cpu.TotalExecutedCycles++; + return; + } + } + } } - if (_machine.IsContended(addr)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue((int)(_machine.CurrentFrameCycle + 1)); + // is the next CPU cycle causing a BUSRQ? + if (BUSRQ > 0) + { + // is the memory address of the BUSRQ potentially contended? + if (_machine.IsContended(AscertainBUSRQAddress())) + { + var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (cont > 0) + { + ContCounter = cont + 1; + IsContending = true; + } + } + } + /* + // is the next CPU cycle an OUT operation? + else if (cur_instr[instr_pntr] == Z80A.OUT) + { + portContending = true; + lastPortAddr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 1]] | _cpu.Regs[cur_instr[instr_pntr + 2]] << 8); + portContCounter = 0; + if (IsPortContended(portContCounter)) + { + var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (cont > 0) + { + ContCounter = cont; + IsContending = true; + } + } + } + // is the next cpu cycle an IN operation? + else if (cur_instr[instr_pntr] == Z80A.IN) + { + portContending = true; + lastPortAddr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 2]] | _cpu.Regs[cur_instr[instr_pntr + 3]] << 8); + portContCounter = 0; + if (IsPortContended(portContCounter)) + { + var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); + if (cont > 0) + { + ContCounter = cont; + IsContending = true; + } + } + } + */ + /* }*/ + + /* + // run a CPU cycle if no contention is applicable + if (!IsContending) + { + _cpu.ExecuteOne(); } + else + { + _cpu.TotalExecutedCycles++; + ContCounter--; + } + */ } + /// + /// Looks up the BUSRQ address that is about to be signalled + /// + /// + private ushort AscertainBUSRQAddress() + { + ushort addr = 0; + switch (BUSRQ) + { + // PCh + case 1: + addr = (ushort)(_cpu.Regs[_cpu.PCl] | _cpu.Regs[_cpu.PCh] << 8); + break; + // SPh + case 3: + addr = (ushort)(_cpu.Regs[_cpu.SPl] | _cpu.Regs[_cpu.SPh] << 8); + break; + // A + case 4: + addr = (ushort)(_cpu.Regs[_cpu.F] | _cpu.Regs[_cpu.A] << 8); + break; + // B + case 6: + addr = (ushort)(_cpu.Regs[_cpu.C] | _cpu.Regs[_cpu.B] << 8); + break; + // D + case 8: + addr = (ushort)(_cpu.Regs[_cpu.E] | _cpu.Regs[_cpu.D] << 8); + break; + // H + case 10: + addr = (ushort)(_cpu.Regs[_cpu.L] | _cpu.Regs[_cpu.H] << 8); + break; + // W + case 12: + addr = (ushort)(_cpu.Regs[_cpu.Z] | _cpu.Regs[_cpu.W] << 8); + break; + // Ixh + case 16: + addr = (ushort)(_cpu.Regs[_cpu.Ixl] | _cpu.Regs[_cpu.Ixh] << 8); + break; + // Iyh + case 18: + addr = (ushort)(_cpu.Regs[_cpu.Iyl] | _cpu.Regs[_cpu.Iyh] << 8); + break; + // I + case 21: + addr = (ushort)(_cpu.Regs[_cpu.R] | _cpu.Regs[_cpu.I] << 8); + break; + } - #region Port Contention - - public int portContCounter = 0; - public bool portContending = false; - public ushort lastPortAddr; - + return addr; + } + /// /// Perfors the actual port contention (if necessary) /// @@ -162,10 +311,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // C:1, C:1, C:1, C:1 switch (portContCounter) { - case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; - case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; - case 1: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; - case 0: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; + case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; + case 1: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; + case 0: + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); + portContCounter = 0; + portContending = false; + break; default: portContCounter = 0; portContending = false; @@ -179,10 +332,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // C:1, C:3 switch (portContCounter) { - case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; - case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; + case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; case 1: break; - case 0: break; + case 0: + portContCounter = 0; + portContending = false; + break; default: portContCounter = 0; portContending = false; @@ -203,7 +359,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case 3: break; case 2: break; case 1: break; - case 0: break; + case 0: + portContCounter = 0; + portContending = false; + break; default: portContCounter = 0; portContending = false; @@ -218,9 +377,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum switch (portContCounter) { case 3: break; - case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break; + case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; case 1: break; - case 0: break; + case 0: + portContCounter = 0; + portContending = false; + break; default: portContCounter = 0; portContending = false; @@ -247,6 +409,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum lastPortAddr = port; } + /// + /// Called when the first byte of an instruction is fetched + /// + /// + public void OnExecFetch(ushort firstByte) + { + // fetch instruction without incrementing pc + //_cpu.FetchInstruction(_cpu.FetchMemory(firstByte)); + } + #endregion } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index a87c006336..35161bf3a3 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -166,14 +166,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum while (CurrentFrameCycle < ULADevice.FrameLength) { - // check for interrupt ULADevice.CheckForInterrupt(CurrentFrameCycle); - - // run a single CPU instruction - CPU.ExecuteOne(); - // check contention for next cycle - CPUMon.Cycle(); - + CPUMon.ExecuteCycle(); // cycle the tape device if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) TapeDevice.TapeCycle(); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 59abd58290..6a3e7ca04d 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -287,6 +287,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public MachineType _machineType; + public int Offset; + /// /// Constructor /// @@ -305,6 +307,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// private void InitRenderer(MachineType machineType) { + switch (machineType) + { + case MachineType.ZXSpectrum16: + case MachineType.ZXSpectrum48: + Offset = 0; + break; + } + for (var t = 0; t < _ula.FrameCycleLength; t++) { var tStateScreen = t + _ula.InterruptStartTime; @@ -438,7 +448,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // calculate contention values for (int t = 0; t < _ula.FrameCycleLength; t++) { - int shifted = (t + 1) + _ula.InterruptStartTime; + int shifted = (t + 1) + _ula.InterruptStartTime + Offset; if (shifted < 0) shifted += _ula.FrameCycleLength; shifted %= _ula.FrameCycleLength; @@ -466,7 +476,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // calculate floating bus values for (int t = 0; t < _ula.FrameCycleLength; t++) { - int shifted = (t + 1) + _ula.InterruptStartTime; + int shifted = (t + 10) + _ula.InterruptStartTime; if (shifted < 0) shifted += _ula.FrameCycleLength; shifted %= _ula.FrameCycleLength; @@ -580,7 +590,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (toCycle > FrameCycleLength) toCycle = FrameCycleLength; if (LastTState > toCycle) - LastTState = 0; + LastTState = toCycle - 2; + if (toCycle < 0) + toCycle = 0; // render the required number of cycles for (int t = LastTState; t < toCycle; t++) @@ -701,6 +713,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void ReadFloatingBus(int tstate, ref int result) { + int off = 1; + tstate += off; + if (tstate >= RenderingTable.Renderer.Length) + tstate -= RenderingTable.Renderer.Length; + if (tstate < 0) + tstate += RenderingTable.Renderer.Length; + var item = RenderingTable.Renderer[tstate]; switch (RenderingTable._machineType) @@ -752,11 +771,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetContentionValue() { - var f = _machine.CurrentFrameCycle; - if (f >= FrameCycleLength) - f -= FrameCycleLength; - - return RenderingTable.Renderer[f].ContentionValue; + return GetContentionValue((int)_machine.CurrentFrameCycle); } /// @@ -765,6 +780,25 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetContentionValue(int tstate) { + int off = 5; + tstate += off; + if (tstate >= FrameCycleLength) + tstate -= FrameCycleLength; + + if (tstate < 0) + tstate += FrameCycleLength; + + return RenderingTable.Renderer[tstate].ContentionValue; + } + + /// + /// Returns the contention value for the supplied t-state + /// + /// + public int GetPortContentionValue(int tstate) + { + int off = 1; + tstate += off; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; @@ -926,6 +960,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum protected void SetupScreenSize() { + BufferWidth = ScreenWidth + BorderLeftWidth + BorderRightWidth; + BufferHeight = ScreenHeight + BorderTopHeight + BorderBottomHeight; + VirtualHeight = BufferHeight; + VirtualWidth = BufferWidth; + ScreenBuffer = new int[BufferWidth * BufferHeight]; + switch (borderType) { case ZXSpectrum.BorderType.Full: @@ -987,7 +1027,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public void SyncState(Serializer ser) { ser.BeginSection("ULA"); - ser.Sync("ScreenBuffer", ref ScreenBuffer, false); + if (ScreenBuffer != null) + ser.Sync("ScreenBuffer", ref ScreenBuffer, false); ser.Sync("FrameLength", ref FrameCycleLength); ser.Sync("ClockSpeed", ref ClockSpeed); ser.Sync("BorderColor", ref BorderColor); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index bff1ec4334..32a42cea0c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -176,7 +176,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendPort(ushort addr) { - CPUMon.ContendPort(addr); + //CPUMon.ContendPort(addr); return; } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index 2423078a83..478fab56c3 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -289,7 +289,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendPort(ushort addr) { - CPUMon.ContendPort(addr); + //CPUMon.ContendPort(addr); return; } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index d1c30ee3a8..ef2fad7331 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -224,7 +224,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void ContendPort(ushort addr) { - CPUMon.ContendPort(addr); + //CPUMon.ContendPort(addr); return; } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index 2006f35c02..45745dcd26 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -110,8 +110,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WriteMemory(ushort addr, byte value) { // update ULA screen buffer if necessary BEFORE T1 write - if ((addr & 49152) == 16384 && _render) - ULADevice.RenderScreen((int)CurrentFrameCycle); + //if ((addr & 49152) == 16384 && _render) + //ULADevice.RenderScreen((int)CurrentFrameCycle); ContendMemory(addr); WriteBus(addr, value); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index 127feb84ae..d4170ffd9e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -110,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - ULADevice.RenderScreen((int)CurrentFrameCycle); + //ULADevice.RenderScreen((int)CurrentFrameCycle); ULADevice.BorderColor = value & BORDER_BIT; // Buzzer diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs index f1bc6f89ec..96219e04db 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3500000; FrameCycleLength = 69888; - InterruptStartTime = 32; + InterruptStartTime = 31; InterruptLength = 32; ScanlineTime = 224; From 6752a173215815e84145068150f2c3967841b152 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 5 Jun 2018 12:52:10 -0400 Subject: [PATCH 14/51] z80: clean up prefetch implementation --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 26 ++--------------- .../CPUs/Z80A/Tables_Direct.cs | 29 ++++++++++++++----- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 4 +-- 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index 8feed65cbe..987c876bc5 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -858,7 +858,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0xC8: RET_COND(FlagZ); break; // RET Z case 0xC9: RET_(); break; // RET case 0xCA: JP_COND(FlagZ); break; // JP Z - case 0xCB: PREFIX_(IXCBpre); break; // PREFIX IXCB + case 0xCB: PREFETCH_(IXCBpre); break; // PREFIX IXCB case 0xCC: CALL_COND(FlagZ); break; // CALL Z case 0xCD: CALL_COND(true); break; // CALL case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n @@ -1123,7 +1123,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0xC8: RET_COND(FlagZ); break; // RET Z case 0xC9: RET_(); break; // RET case 0xCA: JP_COND(FlagZ); break; // JP Z - case 0xCB: PREFIX_(IYCBpre); break; // PREFIy IyCB + case 0xCB: PREFETCH_(IYCBpre); break; // PREFIX IyCB case 0xCC: CALL_COND(FlagZ); break; // CALL Z case 0xCD: CALL_COND(true); break; // CALL case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n @@ -1183,28 +1183,6 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // the first byte fetched is the prefetch value to use with the instruction // we pick Ix or Iy here, the indexed value is stored in WZ // In this way, we don't need to pass them as an argument to the I_Funcs. - if (IXCB_prefetch) - { - IXCB_prefetch = false; - PF = opcode; - Regs[ALU] = PF; - Regs[W] = Regs[Ixh]; - Regs[Z] = Regs[Ixl]; - PREFETCH_(Ixl, Ixh); - return; - } - - if (IYCB_prefetch) - { - IYCB_prefetch = false; - PF = opcode; - Regs[ALU] = PF; - Regs[W] = Regs[Iyh]; - Regs[Z] = Regs[Iyl]; - PREFETCH_(Iyl, Iyh); - return; - } - IXCB_prefix = false; IYCB_prefix = false; NO_prefix = true; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index a41949ee0c..240d2ce06f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -184,15 +184,15 @@ namespace BizHawk.Emulation.Cores.Components.Z80A RD_INC, Z, PCl, PCh, IDLE, ASGN, W, 0, + IDLE, + IDLE, ADDS, PCl, PCh, Z, W, TR16, Z, W, PCl, PCh, - IDLE, - IDLE, WAIT, OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, PCh, 0, 0, 0}; } else { @@ -459,15 +459,30 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { PCh, 0, 0, 0 }; } - private void PREFETCH_(ushort src_l, ushort src_h) + private void PREFETCH_(ushort src) { + if (src == IXCBpre) + { + Regs[W] = Regs[Ixh]; + Regs[Z] = Regs[Ixl]; + } + else + { + Regs[W] = Regs[Iyh]; + Regs[Z] = Regs[Iyl]; + } + cur_instr = new ushort[] - {ADDS, Z, W, ALU, ZERO, + {IDLE, + WAIT, + RD_INC, ALU, PCl, PCh, + ADDS, Z, W, ALU, ZERO, WAIT, OP_F, - PREFIX, IXYprefetch }; + IDLE, + PREFIX, src,}; - BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0, 0 }; } private void DI_() diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 051b727a0d..5617d14940 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -561,8 +561,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (prefix_src == EXTDpre) { EXTD_prefix = true; } if (prefix_src == IXpre) { IX_prefix = true; } if (prefix_src == IYpre) { IY_prefix = true; } - if (prefix_src == IXCBpre) { IXCB_prefix = true; IXCB_prefetch = true; } - if (prefix_src == IYCBpre) { IYCB_prefix = true; IYCB_prefetch = true; } + if (prefix_src == IXCBpre) { IXCB_prefix = true; } + if (prefix_src == IYCBpre) { IYCB_prefix = true; } RegPC++; FetchInstruction(); From 978a93b6811cb1302a6a038a6bc742c80618e05d Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 5 Jun 2018 15:05:48 -0400 Subject: [PATCH 15/51] z80: more memory contention timing work (up to test 23) --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs | 14 +++++++------- .../CPUs/Z80A/Tables_Indirect.cs | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 240d2ce06f..55f08e4905 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -352,7 +352,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, PCh, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } else { @@ -409,7 +409,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } @@ -445,7 +445,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + BUSRQ = new ushort[] { I, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } private void PREFIX_(ushort src) @@ -528,7 +528,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, 0, src_h, 0, 0, 0 }; + BUSRQ = new ushort[] { I, I, PCh, 0, 0, 0 }; } private void OUT_() @@ -612,7 +612,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, I, I, I, I, I, I, PCh, 0, 0, 0 }; } private void INT_MODE_(ushort src) @@ -644,7 +644,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, W, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, H, H, H, H, W, 0, 0, PCh, 0, 0, 0 }; } private void RLD_() @@ -665,7 +665,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, W, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, H, H, H, H, W, 0, 0, PCh, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index b26802d32e..4e6ce7adb2 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -350,15 +350,15 @@ private void I_OP_n_n(ushort src_l, ushort src_h) { cur_instr = new ushort[] - {IDLE, + {TR16, Z, W, src_l, src_h, WAIT, RD_INC, ALU, PCl, PCh, - IDLE, - TR16, Z, W, src_l, src_h, ADDS, Z, W, ALU, ZERO, WAIT, RD_INC, ALU, PCl, PCh, IDLE, + IDLE, + IDLE, WAIT, WR, Z, W, ALU, IDLE, @@ -366,7 +366,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, PCh, W, 0, 0, PCh, 0, 0, 0 }; } private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -388,7 +388,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, W, 0, 0, PCh, 0, 0, 0 }; } private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) @@ -410,7 +410,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, Z, 0, 0, PCh, 0, 0, 0 }; } private void LD_OP_R(ushort operation, ushort repeat_instr) From 620c4b3c2e50d0aaa478aeba0ba6d498f6fd3dc0 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 5 Jun 2018 18:04:19 -0400 Subject: [PATCH 16/51] z80:more contention work, only IN/OUT to go --- .../CPUs/Z80A/Tables_Direct.cs | 6 +- .../CPUs/Z80A/Tables_Indirect.cs | 54 ++-- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 238 ++++++++---------- 3 files changed, 127 insertions(+), 171 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 55f08e4905..09342f9922 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -145,7 +145,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCh, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] {I, PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, PCh, 0, 0, 0}; } else { @@ -159,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCh, 0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] {I, PCh, 0, 0, PCh, 0, 0, 0}; } } @@ -482,7 +482,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IDLE, PREFIX, src,}; - BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, PCh }; } private void DI_() diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 4e6ce7adb2..5ac492c6f1 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -292,9 +292,9 @@ { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, Z, W, + IDLE, operation, bit, ALU, WAIT, WR, Z, W, ALU, @@ -303,22 +303,22 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { W, 0, 0, W, W, 0, 0, PCh, 0, 0, 0 }; } private void I_BIT_TE(ushort bit) { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, Z, W, + IDLE, I_BIT, bit, ALU, WAIT, OP_F, OP }; - BUSRQ = new ushort[] { 0, W, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { W, 0, 0, W, PCh, 0, 0, 0 }; } private void I_OP_n(ushort operation, ushort src_l, ushort src_h) @@ -333,10 +333,10 @@ ADDS, Z, W, ALU, ZERO, IDLE, IDLE, - IDLE, WAIT, RD, ALU, Z, W, operation, ALU, + IDLE, WAIT, WR, Z, W, ALU, IDLE, @@ -344,7 +344,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, W, 0, 0, W, W, 0, 0, PCh, 0, 0, 0 }; } private void I_OP_n_n(ushort src_l, ushort src_h) @@ -419,74 +419,58 @@ {IDLE, WAIT, RD, ALU, L, H, - IDLE, + operation, L, H, WAIT, WR, E, D, ALU, - operation, L, H, operation, E, D, - SET_FL_LD, // BC gets decremented in here - WAIT, - OP_F, - OP_R, 0, operation, repeat_instr }; + SET_FL_LD_R, 0, operation, repeat_instr}; - BUSRQ = new ushort[] { H, 0, 0, D, 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, D, 0, 0, D, D}; } private void CP_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] - {IDLE, + {IDLE, WAIT, RD, ALU, L, H, operation, L, H, DEC16, C, B, - SET_FL_CP, operation, Z, W, IDLE, - IDLE, - WAIT, - OP_F, - OP_R, 1, operation, repeat_instr }; + SET_FL_CP_R, 1, operation, repeat_instr}; - BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { H, 0, 0, H, H, H, H, H }; } private void IN_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] {IDLE, - IDLE, + WAIT, WAIT, IN, ALU, C, B, IDLE, WAIT, WR, L, H, ALU, - REP_OP_I, operation, - IDLE, - WAIT, - OP_F, - OP_R, 2, operation, repeat_instr }; + REP_OP_I, operation, 2, operation, repeat_instr }; - BUSRQ = new ushort[] { 0, 0, 0, 0, H, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, 0, 0, 0, H, 0, 0, 0}; } private void OUT_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] - {IDLE, + {IDLE, + IDLE, WAIT, RD, ALU, L, H, IDLE, - IDLE, WAIT, OUT, C, B, ALU, - REP_OP_O, operation, - IDLE, - WAIT, - OP_F, - OP_R, 3, operation, repeat_instr }; + REP_OP_O, operation, 3, operation, repeat_instr }; - BUSRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, H, 0, 0, 0, 0, 0, 0}; } // this is an indirect change of a a 16 bit register with memory diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 5617d14940..ea5bcebfe8 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -70,8 +70,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort NEG = 55; public const ushort RRD = 56; public const ushort RLD = 57; - public const ushort SET_FL_LD = 58; - public const ushort SET_FL_CP = 59; + public const ushort SET_FL_LD_R = 58; + public const ushort SET_FL_CP_R = 59; public const ushort SET_FL_IR = 60; public const ushort I_BIT = 61; public const ushort HL_BIT = 62; @@ -102,7 +102,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCl, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; instr_pntr = 0; bus_pntr = 0; NO_prefix = true; } @@ -231,134 +231,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); break; case OP_R: - // determine if we repeat based on what operation we are doing - // single execution versions also come here, but never repeat - ushort temp1 = cur_instr[instr_pntr++]; - ushort temp2 = cur_instr[instr_pntr++]; - ushort temp3 = cur_instr[instr_pntr++]; - - bool repeat = false; - int Reg16_d = Regs[C] | (Regs[B] << 8); - switch (temp1) - { - case 0: - repeat = Reg16_d != 0; - break; - case 1: - repeat = (Reg16_d != 0) && !FlagZ; - break; - case 2: - repeat = Regs[B] != 0; - break; - case 3: - repeat = Regs[B] != 0; - break; - } - - // if we repeat, we do a 5 cycle refresh which decrements PC by 2 - // if we don't repeat, continue on as a normal opcode fetch - if (repeat && temp3 > 0) - { - cur_instr = new ushort[] - {DEC16, PCl, PCh, - DEC16, PCl, PCh, - WAIT, - OP_F, - OP }; - - BUSRQ = new ushort[] { 0, PCh, 0, 0, 0 }; - - instr_pntr = 0; bus_pntr = 0; - // adjust WZ register accordingly - switch (temp1) - { - case 0: - // TEST: PC before or after the instruction? - Regs[Z] = Regs[PCl]; - Regs[W] = Regs[PCh]; - INC16_Func(Z, W); - break; - case 1: - // TEST: PC before or after the instruction? - Regs[Z] = Regs[PCl]; - Regs[W] = Regs[PCh]; - INC16_Func(Z, W); - break; - case 2: - // Nothing - break; - case 3: - // Nothing - break; - } - } - else - { - // Interrupts can occur at this point, so process them accordingly - // Read the opcode of the next instruction - if (EI_pending > 0) - { - EI_pending--; - if (EI_pending == 0) { IFF1 = IFF2 = true; } - } - - // Process interrupt requests. - if (nonMaskableInterruptPending) - { - nonMaskableInterruptPending = false; - - if (TraceCallback != null) - { - TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); - } - - iff2 = iff1; - iff1 = false; - NMI_(); - NMICallback(); - instr_pntr = 0; bus_pntr = 0; - } - else if (iff1 && FlagI) - { - iff1 = iff2 = false; - EI_pending = 0; - - if (TraceCallback != null) - { - TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); - } - - switch (interruptMode) - { - case 0: - // Requires something to be pushed onto the data bus - // we'll assume it's a zero for now - INTERRUPT_0(0); - break; - case 1: - INTERRUPT_1(); - break; - case 2: - INTERRUPT_2(); - break; - } - IRQCallback(); - instr_pntr = 0; bus_pntr = 0; - } - else - { - if (OnExecFetch != null) OnExecFetch(RegPC); - if (TraceCallback != null) TraceCallback(State()); - RegPC++; - FetchInstruction(); - instr_pntr = 0; bus_pntr = 0; - } - - temp_R = (byte)(Regs[R] & 0x7F); - temp_R++; - temp_R &= 0x7F; - Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); - } + break; case HALT: @@ -608,12 +481,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case RLD: RLD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); break; - case SET_FL_LD: + case SET_FL_LD_R: DEC16_Func(C, B); SET_FL_LD_Func(); + Repeat_Op(); break; - case SET_FL_CP: + case SET_FL_CP_R: SET_FL_CP_Func(); + Repeat_Op(); break; case SET_FL_IR: SET_FL_IR_Func(cur_instr[instr_pntr++]); @@ -651,6 +526,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A INC16_Func(Z, W); DEC8_Func(B); } + Repeat_Op(); break; case REP_OP_O: ushort temp5 = cur_instr[instr_pntr++]; @@ -668,11 +544,107 @@ namespace BizHawk.Emulation.Cores.Components.Z80A TR16_Func(Z, W, C, B); INC16_Func(Z, W); } + Repeat_Op(); break; } TotalExecutedCycles++; } + public void Repeat_Op() + { + // determine if we repeat based on what operation we are doing + // single execution versions also come here, but never repeat + ushort temp1 = cur_instr[instr_pntr++]; + ushort temp2 = cur_instr[instr_pntr++]; + ushort temp3 = cur_instr[instr_pntr++]; + + bool repeat = false; + int Reg16_d = Regs[C] | (Regs[B] << 8); + switch (temp1) + { + case 0: + repeat = Reg16_d != 0; + break; + case 1: + repeat = (Reg16_d != 0) && !FlagZ; + break; + case 2: + repeat = Regs[B] != 0; + break; + case 3: + repeat = Regs[B] != 0; + break; + } + + // if we repeat, we do a 5 cycle refresh which decrements PC by 2 + // if we don't repeat, continue on as a normal opcode fetch + if (repeat && temp3 > 0) + { + cur_instr = new ushort[] + {DEC16, PCl, PCh, + DEC16, PCl, PCh, + IDLE, + IDLE, + IDLE, + IDLE, + WAIT, + OP_F, + OP}; + + if (temp1 == 0) + { + BUSRQ = new ushort[] { D, D, D, D, D, PCh, 0, 0, 0 }; + } + else if (temp1 == 1) + { + BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; + } + else if (temp1 == 2) + { + BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; + } + else if (temp1 == 3) + { + BUSRQ = new ushort[] { B, B, B, B, B, PCh, 0, 0, 0 }; + } + + instr_pntr = 0; bus_pntr = 0; + // adjust WZ register accordingly + switch (temp1) + { + case 0: + // TEST: PC before or after the instruction? + Regs[Z] = Regs[PCl]; + Regs[W] = Regs[PCh]; + INC16_Func(Z, W); + break; + case 1: + // TEST: PC before or after the instruction? + Regs[Z] = Regs[PCl]; + Regs[W] = Regs[PCh]; + INC16_Func(Z, W); + break; + case 2: + // Nothing + break; + case 3: + // Nothing + break; + } + } + else + { + cur_instr = new ushort[] + { IDLE, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + instr_pntr = 0; bus_pntr = 0; + } + } + // tracer stuff public Action TraceCallback; From 74e6f630c3322b67037c3611906752ded53bbdda Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 6 Jun 2018 07:33:49 -0400 Subject: [PATCH 17/51] z80: IO port re-work and contention --- .../CPUs/Z80A/Registers.cs | 12 +++++++++ .../CPUs/Z80A/Tables_Direct.cs | 26 +++++++++---------- .../CPUs/Z80A/Tables_Indirect.cs | 12 ++++----- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 21 +++++++-------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index b1fd71d5b9..d7c7cbe90f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -45,6 +45,18 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public ushort[] Regs = new ushort[36]; + // IO Contention Constants. Need to distinguish port access and normal memory accesses for zx spectrum + public const ushort BIO1 = 100; + public const ushort BIO2 = 101; + public const ushort BIO3 = 102; + public const ushort BIO4 = 103; + + public const ushort WIO1 = 105; + public const ushort WIO2 = 106; + public const ushort WIO3 = 107; + public const ushort WIO4 = 108; + + public bool FlagI; public bool FlagW; // wait flag, when set to true reads / writes will be delayed diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 09342f9922..4b4b5e50d6 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -534,19 +534,19 @@ namespace BizHawk.Emulation.Cores.Components.Z80A private void OUT_() { cur_instr = new ushort[] - {IDLE, + {TR, W, A, WAIT, RD_INC, Z, PCl, PCh, IDLE, - IDLE, - TR, W, A, + WAIT, + WAIT, OUT, Z, W, A, INC16, Z, W, WAIT, OP_F, OP}; - BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0 ,0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0}; } private void OUT_REG_(ushort dest, ushort src) @@ -561,40 +561,40 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; } private void IN_() { cur_instr = new ushort[] - {IDLE, + {TR, W, A, WAIT, RD_INC, Z, PCl, PCh, IDLE, - IDLE, - TR, W, A, + WAIT, + WAIT, IN, A, Z, W, INC16, Z, W, WAIT, OP_F, OP}; - BUSRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; } private void IN_REG_(ushort dest, ushort src) { cur_instr = new ushort[] - {IDLE, - TR16, Z, W, C, B, + {TR16, Z, W, C, B, WAIT, - IN, dest, src, B, + WAIT, + IN, dest, Z, W, INC16, Z, W, WAIT, OP_F, OP}; - BUSRQ = new ushort[] { 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; } private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 5ac492c6f1..b8f3505fa4 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -447,15 +447,15 @@ { cur_instr = new ushort[] {IDLE, + IDLE, WAIT, WAIT, IN, ALU, C, B, IDLE, WAIT, - WR, L, H, ALU, - REP_OP_I, operation, 2, operation, repeat_instr }; + REP_OP_I, L, H, ALU, operation, 2, operation, repeat_instr }; - BUSRQ = new ushort[] { I, 0, 0, 0, H, 0, 0, 0}; + BUSRQ = new ushort[] { I, BIO1, BIO2, BIO3, BIO4, H, 0, 0}; } private void OUT_OP_R(ushort operation, ushort repeat_instr) @@ -467,10 +467,10 @@ RD, ALU, L, H, IDLE, WAIT, - OUT, C, B, ALU, - REP_OP_O, operation, 3, operation, repeat_instr }; + WAIT, + REP_OP_O, C, B, ALU, operation, 3, operation, repeat_instr }; - BUSRQ = new ushort[] { I, H, 0, 0, 0, 0, 0, 0}; + BUSRQ = new ushort[] { I, H, 0, 0, BIO1, BIO2, BIO3, BIO4 }; } // this is an indirect change of a a 16 bit register with memory diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index ea5bcebfe8..34ec1bb5ff 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // operations that can take place in an instruction public const ushort IDLE = 0; public const ushort OP = 1; - public const ushort OP_R = 2; // used for repeating operations + public const ushort OP_F = 2; // used for repeating operations public const ushort HALT = 3; public const ushort RD = 4; public const ushort WR = 5; @@ -77,10 +77,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort HL_BIT = 62; public const ushort FTCH_DB = 63; public const ushort WAIT = 64; // enterred when readin or writing and FlagW is true - public const ushort OP_F = 65; // fetch the opcode, happens on cycle 3 of fetch cycle - public const ushort RST = 66; - public const ushort REP_OP_I = 67; - public const ushort REP_OP_O = 68; + public const ushort RST = 65; + public const ushort REP_OP_I = 66; + public const ushort REP_OP_O = 67; public byte temp_R; @@ -230,10 +229,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A temp_R &= 0x7F; Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); break; - case OP_R: - + case OP_F: + opcode = FetchMemory(RegPC); break; - case HALT: halted = true; // NOTE: Check how halt state effects the DB @@ -503,14 +501,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A bus_pntr--; } break; - case OP_F: - opcode = FetchMemory(RegPC); - break; case RST: Regs[Z] = cur_instr[instr_pntr++]; Regs[W] = 0; break; case REP_OP_I: + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + ushort temp4 = cur_instr[instr_pntr++]; if (temp4 == DEC16) { @@ -529,6 +526,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Repeat_Op(); break; case REP_OP_O: + OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + ushort temp5 = cur_instr[instr_pntr++]; if (temp5 == DEC16) { From 7f8084d4104015b749affd189ec15f64fe6a6217 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 6 Jun 2018 14:39:41 +0100 Subject: [PATCH 18/51] ZXHawk: IORQ check now happens pre T-Cycle --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 316 ++++++------------ .../Computers/SinclairSpectrum/Machine/ULA.cs | 2 +- .../Machine/ZXSpectrum48K/ZX48.Port.cs | 2 +- 3 files changed, 111 insertions(+), 209 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 1623679213..8ac36b391a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -67,14 +67,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); - if (portContending) + // is the next CPU cycle causing a BUSRQ or IORQ? + if (BUSRQ > 0) { - RunPortContention(); - } - else - { - // is the next CPU cycle causing a BUSRQ? - if (BUSRQ > 0) + // check for IORQ + if (!CheckIO()) { // is the memory address of the BUSRQ potentially contended? if (_machine.IsContended(AscertainBUSRQAddress())) @@ -89,129 +86,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } _cpu.ExecuteOne(); - - /* - else if (ContCounter > 0) - { - // still contention cycles to process - IsContending = true; - } - else - { - // is the next CPU cycle causing a BUSRQ? - if (BUSRQ > 0) - { - // is the memory address of the BUSRQ potentially contended? - if (_machine.IsContended(AscertainBUSRQAddress())) - { - var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (cont > 0) - { - ContCounter = cont + 1; - IsContending = true; - } - } - } - } - /* - else - { - // no contention cycles to process (so far) on this cycle - IsContending = false; - ContCounter = 0; - - if (portContending) - { - // a port operation is still in progress - portContCounter++; - if (portContCounter > 3) - { - // we are now out of the IN/OUT operation - portContCounter = 0; - portContending = false; - } - else - { - // still IN/OUT cycles to process - if (IsPortContended(portContCounter)) - { - var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (cont > 0) - { - ContCounter = cont + 1; - IsContending = true; - // dont let this fall through - // just manually do the first contention cycle - ContCounter--; - _cpu.TotalExecutedCycles++; - return; - } - } - } - } - - // is the next CPU cycle causing a BUSRQ? - if (BUSRQ > 0) - { - // is the memory address of the BUSRQ potentially contended? - if (_machine.IsContended(AscertainBUSRQAddress())) - { - var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (cont > 0) - { - ContCounter = cont + 1; - IsContending = true; - } - } - } - /* - // is the next CPU cycle an OUT operation? - else if (cur_instr[instr_pntr] == Z80A.OUT) - { - portContending = true; - lastPortAddr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 1]] | _cpu.Regs[cur_instr[instr_pntr + 2]] << 8); - portContCounter = 0; - if (IsPortContended(portContCounter)) - { - var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (cont > 0) - { - ContCounter = cont; - IsContending = true; - } - } - } - // is the next cpu cycle an IN operation? - else if (cur_instr[instr_pntr] == Z80A.IN) - { - portContending = true; - lastPortAddr = (ushort)(_cpu.Regs[cur_instr[instr_pntr + 2]] | _cpu.Regs[cur_instr[instr_pntr + 3]] << 8); - portContCounter = 0; - if (IsPortContended(portContCounter)) - { - var cont = _machine.ULADevice.GetContentionValue((int)_machine.CurrentFrameCycle); - if (cont > 0) - { - ContCounter = cont; - IsContending = true; - } - } - } - */ - /* }*/ - - /* - // run a CPU cycle if no contention is applicable - if (!IsContending) - { - _cpu.ExecuteOne(); - } - else - { - _cpu.TotalExecutedCycles++; - ContCounter--; - } - */ } /// @@ -263,34 +137,36 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case 21: addr = (ushort)(_cpu.Regs[_cpu.R] | _cpu.Regs[_cpu.I] << 8); break; + // BC + case Z80A.BIO1: + case Z80A.BIO2: + case Z80A.BIO3: + case Z80A.BIO4: + addr = (ushort)(_cpu.Regs[_cpu.C] | _cpu.Regs[_cpu.B] << 8); + break; + // WZ + case Z80A.WIO1: + case Z80A.WIO2: + case Z80A.WIO3: + case Z80A.WIO4: + addr = (ushort)(_cpu.Regs[_cpu.Z] | _cpu.Regs[_cpu.W] << 8); + break; } return addr; } - + /// - /// Perfors the actual port contention (if necessary) + /// Returns TRUE if the supplied T-cycle within an IO operation has the possibility of being contended + /// This can be different based on the emulated ZX Spectrum model /// - private void RunPortContention() + /// + /// + private bool IsIOCycleContended(int T) { - //return; - bool lowBitSet = false; + bool lowBitSet = (lastPortAddr & 0x0001) != 0; bool highByte407f = false; - int offset = 0; // _machine.ULADevice.contentionOffset; // -5;// 57;// - 10; - var c = _machine.CurrentFrameCycle; - var t = _machine.ULADevice.FrameLength; - int f = (int)c + offset; - if (f >= t) - f = f - t; - else if (f < 0) - f = t + f; - - if ((lastPortAddr & 0x0001) != 0) - lowBitSet = true; - - portContCounter--; - switch (machineType) { case MachineType.ZXSpectrum16: @@ -309,20 +185,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // high byte 40-7f // low bit set // C:1, C:1, C:1, C:1 - switch (portContCounter) + switch (T) { - case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; - case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; - case 1: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; - case 0: - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); - portContCounter = 0; - portContending = false; - break; - default: - portContCounter = 0; - portContending = false; - break; + case 1: + case 2: + case 3: + case 4: + return true; } } else @@ -330,19 +199,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // high byte 40-7f // low bit reset // C:1, C:3 - switch (portContCounter) + switch (T) { - case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; - case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; - case 1: break; - case 0: - portContCounter = 0; - portContending = false; - break; - default: - portContCounter = 0; - portContending = false; - break; + case 1: + case 2: + return true; } } } @@ -353,40 +214,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { // high byte not 40-7f // low bit set - // N:4 - switch (portContCounter) - { - case 3: break; - case 2: break; - case 1: break; - case 0: - portContCounter = 0; - portContending = false; - break; - default: - portContCounter = 0; - portContending = false; - break; - } + // N:4 } else { // high byte not 40-7f // low bit reset // N:1, C:3 - switch (portContCounter) + switch (T) { - case 3: break; - case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue(f); break; - case 1: break; - case 0: - portContCounter = 0; - portContending = false; - break; - default: - portContCounter = 0; - portContending = false; - break; + case 2: + return true; } } } @@ -396,17 +234,81 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case MachineType.ZXSpectrum128Plus3: break; } + + return false; } /// - /// Starts the port contention process + /// Running every cycle, this determines whether the upcoming BUSRQ is for an IO operation + /// Also processes any contention /// - /// - public void ContendPort(ushort port) + /// + private bool CheckIO() { - portContending = true; - portContCounter = 4; - lastPortAddr = port; + bool isIO = false; + + switch (BUSRQ) + { + // BC: T1 + case Z80A.BIO1: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(1)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // BC: T2 + case Z80A.BIO2: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(2)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // BC: T3 + case Z80A.BIO3: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(3)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // BC: T4 + case Z80A.BIO4: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(4)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + + // WZ: T1 + case Z80A.WIO1: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(1)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // WZ: T2 + case Z80A.WIO2: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(2)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // WZ: T3 + case Z80A.WIO3: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(3)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // WZ: T4 + case Z80A.WIO4: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(4)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + } + + return isIO; } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 6a3e7ca04d..345b468cb7 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -797,7 +797,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetPortContentionValue(int tstate) { - int off = 1; + int off = 5; tstate += off; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index d4170ffd9e..f6b01cc3be 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -154,7 +154,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum The 'Contention pattern' column should be interpreted from left to right. An "N:n" entry means that no delay is applied at this cycle, and the Z80 continues uninterrupted for 'n' T states. A "C:n" entry means that the ULA halts the Z80; the delay is exactly the same as would occur for a contended memory access at this cycle (eg 6 T states at cycle 14335, 5 at 14336, etc on the 48K machine). After this delay, the Z80 then continues for 'n' cycles. */ - CPUMon.ContendPort(addr); + //CPUMon.ContendPort(addr); return; } From c80f873adf9830f45f7b5522e133795566787ee7 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 6 Jun 2018 15:37:29 +0100 Subject: [PATCH 19/51] ZXHawk: added CPUMonitor syncstate --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 192 +++++++++--------- 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 8ac36b391a..fbdc5d2134 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -1,4 +1,5 @@ -using BizHawk.Emulation.Cores.Components.Z80A; +using BizHawk.Common; +using BizHawk.Emulation.Cores.Components.Z80A; using System; using System.Collections.Generic; using System.Linq; @@ -19,19 +20,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #region Lookups - public ushort[] cur_instr => _cpu.cur_instr; - public int instr_pntr => _cpu.instr_pntr; - public ushort RegPC => _cpu.RegPC; + /// + /// CPU total executes t-states + /// public long TotalExecutedCycles => _cpu.TotalExecutedCycles; + + /// + /// Current BUSRQ line array + /// public ushort BUSRQ { - get - { - //if (_cpu.bus_pntr < _cpu.BUSRQ.Length - 1) - return _cpu.BUSRQ[_cpu.bus_pntr]; - - //return 0; - } + get { return _cpu.BUSRQ[_cpu.bus_pntr]; } } #endregion @@ -48,18 +47,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #region State - public bool IsContending = false; - public int ContCounter = -1; - public int portContCounter = 0; - public int portContTotalLen = 0; - public bool portContending = false; + /// + /// The last 16-bit port address that was detected + /// public ushort lastPortAddr; - public int[] portContArr = new int[4]; #endregion #region Methods - + /// /// Handles the ULA and CPU cycle clocks, along with any memory and port contention /// @@ -89,7 +85,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } /// - /// Looks up the BUSRQ address that is about to be signalled + /// Looks up the current BUSRQ address that is about to be signalled on the upcoming cycle /// /// private ushort AscertainBUSRQAddress() @@ -156,6 +152,79 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return addr; } + /// + /// Running every cycle, this determines whether the upcoming BUSRQ is for an IO operation + /// Also processes any contention + /// + /// + private bool CheckIO() + { + bool isIO = false; + + switch (BUSRQ) + { + // BC: T1 + case Z80A.BIO1: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(1)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // BC: T2 + case Z80A.BIO2: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(2)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // BC: T3 + case Z80A.BIO3: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(3)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // BC: T4 + case Z80A.BIO4: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(4)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + + // WZ: T1 + case Z80A.WIO1: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(1)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // WZ: T2 + case Z80A.WIO2: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(2)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // WZ: T3 + case Z80A.WIO3: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(3)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + // WZ: T4 + case Z80A.WIO4: + lastPortAddr = AscertainBUSRQAddress(); + isIO = true; + if (IsIOCycleContended(4)) + _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); + break; + } + + return isIO; + } + /// /// Returns TRUE if the supplied T-cycle within an IO operation has the possibility of being contended /// This can be different based on the emulated ZX Spectrum model @@ -236,80 +305,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } return false; - } - - /// - /// Running every cycle, this determines whether the upcoming BUSRQ is for an IO operation - /// Also processes any contention - /// - /// - private bool CheckIO() - { - bool isIO = false; - - switch (BUSRQ) - { - // BC: T1 - case Z80A.BIO1: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(1)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - // BC: T2 - case Z80A.BIO2: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(2)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - // BC: T3 - case Z80A.BIO3: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(3)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - // BC: T4 - case Z80A.BIO4: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(4)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - - // WZ: T1 - case Z80A.WIO1: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(1)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - // WZ: T2 - case Z80A.WIO2: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(2)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - // WZ: T3 - case Z80A.WIO3: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(3)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - // WZ: T4 - case Z80A.WIO4: - lastPortAddr = AscertainBUSRQAddress(); - isIO = true; - if (IsIOCycleContended(4)) - _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); - break; - } - - return isIO; - } + } /// /// Called when the first byte of an instruction is fetched @@ -323,5 +319,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #endregion + #region Serialization + + public void SyncState(Serializer ser) + { + ser.BeginSection("CPUMonitor"); + ser.Sync("", ref lastPortAddr); + ser.EndSection(); + } + + #endregion } } From 535534a94a9a8af3a3801d7e4044371518b6615c Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 6 Jun 2018 15:56:27 +0100 Subject: [PATCH 20/51] ZXHawk: start preparing 128k and +2a/+3 for updating timings --- .../Machine/SpectrumBase.Memory.cs | 5 - .../Machine/SpectrumBase.Port.cs | 2 +- .../Machine/ZXSpectrum128K/ZX128.Memory.cs | 21 ---- .../Machine/ZXSpectrum128K/ZX128.Port.cs | 44 +------ .../ZX128Plus2a.Memory.cs | 24 +--- .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 115 +----------------- .../ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 25 +--- .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 44 +------ .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 34 +----- .../Machine/ZXSpectrum48K/ZX48.Port.cs | 64 +--------- 10 files changed, 11 insertions(+), 367 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs index 5a8455bc34..283f12cdb6 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs @@ -155,11 +155,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return value; } - /// - /// Contends memory if necessary - /// - public abstract void ContendMemory(ushort addr); - /// /// Checks whether supplied address is in a potentially contended bank /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs index f71aee74a8..3eba9a46f2 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs @@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// This method is for 48k and 128k/+2 machines only and should be overridden for other models /// /// - public abstract void ContendPort(ushort addr); + //public abstract void ContendPort(ushort addr); } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs index df1d5587da..99065d6b45 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs @@ -185,8 +185,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - ContendMemory(addr); - var data = ReadBus(addr); return data; } @@ -199,28 +197,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { - // update ULA screen buffer if necessary BEFORE T1 write - if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render) - ULADevice.RenderScreen((int)CurrentFrameCycle); - - ContendMemory(addr); WriteBus(addr, value); } - /// - /// Contends memory if necessary - /// - public override void ContendMemory(ushort addr) - { - /* - if (IsContended(addr)) - { - var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); - CPU.TotalExecutedCycles += delay; - } - */ - } - /// /// Checks whether supplied address is in a potentially contended bank /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index 32a42cea0c..ec358785d5 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -18,9 +18,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { bool deviceAddressed = true; - // process IO contention - ContendPort(port); - int result = 0xFF; // check AY @@ -53,29 +50,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (!deviceAddressed) { // If this is an unused port the floating memory bus should be returned - // Floating bus is read on the previous cycle - long _tStates = CurrentFrameCycle - 1; - - ULADevice.ReadFloatingBus((int)_tStates, ref result); - - /* - // if we are on the top or bottom border return 0xff - if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) - { - result = 0xff; - } - else - { - if (ULADevice.floatingBusTable[_tStates] < 0) - { - result = 0xff; - } - else - { - result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); - } - } - */ + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); } return (byte)result; @@ -88,9 +63,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WritePort(ushort port, byte value) { - // process IO contention - ContendPort(port); - // get a BitArray of the port BitArray portBits = new BitArray(BitConverter.GetBytes(port)); // get a BitArray of the value byte @@ -146,7 +118,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { // store the last OUT byte LastULAOutByte = value; - CPU.TotalExecutedCycles += ULADevice.GetContentionValue(); /* Bit 7 6 5 4 3 2 1 0 @@ -156,9 +127,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.BorderColor != (value & BORDER_BIT)) - ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.BorderColor = value & BORDER_BIT; // Buzzer @@ -169,15 +137,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum //TapeDevice.ProcessMicBit((value & MIC_BIT) != 0); } } - - /// - /// Contend port if necessary - /// - /// - public override void ContendPort(ushort addr) - { - //CPUMon.ContendPort(addr); - return; - } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs index d4c46af37f..aec8326d86 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs @@ -341,10 +341,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; } } - - // update ULA screen buffer if necessary - if ((addr & 49152) == 16384 && _render) - ULADevice.RenderScreen((int)CurrentFrameCycle); } /// @@ -355,8 +351,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - ContendMemory(addr); - var data = ReadBus(addr); return data; } @@ -370,6 +364,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override void WriteMemory(ushort addr, byte value) { // update ULA screen buffer if necessary BEFORE T1 write + /* if (!SpecialPagingMode) { if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render) @@ -390,23 +385,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; } } - - ContendMemory(addr); - WriteBus(addr, value); - } - - /// - /// Contends memory if necessary - /// - public override void ContendMemory(ushort addr) - { - /* - if (IsContended(addr)) - { - var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); - CPU.TotalExecutedCycles += delay; - } */ + WriteBus(addr, value); } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index 478fab56c3..431444b67d 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -18,9 +18,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { bool deviceAddressed = true; - // process IO contention - ContendPort(port); - int result = 0xFF; // check AY @@ -53,102 +50,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (!deviceAddressed) { // If this is an unused port the floating memory bus should be returned - // Floating bus is read on the previous cycle - long _tStates = CurrentFrameCycle - 1; - - ULADevice.ReadFloatingBus((int)_tStates, ref result); - /* - // if we are on the top or bottom border return 0xff - if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) - { - result = 0xff; - } - else - { - if (ULADevice.floatingBusTable[_tStates] < 0) - { - result = 0xff; - } - else - { - result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); - } - } - */ + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); } - /* - // Check whether the low bit is reset - // Technically the ULA should respond to every even I/O address - bool lowBitReset = (port & 0x0001) == 0; - - // Kempston joystick input takes priority over all other input - // if this is detected just return the kempston byte - if ((port & 0xe0) == 0 || (port & 0x20) == 0) - { - if (LocateUniqueJoystick(JoystickType.Kempston) != null) - return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine; - - InputRead = true; - } - else if (lowBitReset) - { - // Even I/O address so get input from keyboard - KeyboardDevice.ReadPort(port, ref result); - - TapeDevice.MonitorRead(); - - // not a lagframe - InputRead = true; - - // tape loading monitor cycle - //TapeDevice.MonitorRead(); - - // process tape INs - TapeDevice.ReadPort(port, ref result); - } - else - { - // devices other than the ULA will respond here - // (e.g. the AY sound chip in a 128k spectrum - - // AY register activate - on +3/2a both FFFD and BFFD active AY - if ((port & 0xc002) == 0xc000) - { - result = (int)AYDevice.PortRead(); - } - else if ((port & 0xc002) == 0x8000) - { - result = (int)AYDevice.PortRead(); - } - - // Kempston Mouse - - /* - else if ((port & 0xF002) == 0x2000) //Is bit 12 set and bits 13,14,15 and 1 reset? - { - //result = udpDrive.DiskStatusRead(); - - // disk drive is not yet implemented - return a max status byte for the menu to load - result = 255; - } - else if ((port & 0xF002) == 0x3000) - { - //result = udpDrive.DiskReadByte(); - result = 0; - } - - else if ((port & 0xF002) == 0x0) - { - if (PagingDisabled) - result = 0x1; - else - result = 0xff; - } - *//* - - // if unused port the floating memory bus should be returned (still todo) - } - */ return (byte)result; } @@ -160,9 +63,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WritePort(ushort port, byte value) { - // process IO contention - ContendPort(port); - // get a BitArray of the port BitArray portBits = new BitArray(BitConverter.GetBytes(port)); // get a BitArray of the value byte @@ -244,9 +144,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.BorderColor != (value & BORDER_BIT)) - ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.BorderColor = value & BORDER_BIT; // Buzzer @@ -282,15 +179,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } set { ROMPaged = value; } } - - /// - /// Contend port if necessary - /// - /// - public override void ContendPort(ushort addr) - { - //CPUMon.ContendPort(addr); - return; - } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index e288b67c86..80a9e9888f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -341,10 +341,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; } } - - // update ULA screen buffer if necessary - if ((addr & 49152) == 16384 && _render) - ULADevice.RenderScreen((int)CurrentFrameCycle); } /// @@ -355,8 +351,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - ContendMemory(addr); - var data = ReadBus(addr); return data; } @@ -369,6 +363,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { + /* // update ULA screen buffer if necessary BEFORE T1 write if (!SpecialPagingMode) { @@ -390,23 +385,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; } } - - ContendMemory(addr); - WriteBus(addr, value); - } - - /// - /// Contends memory if necessary - /// - public override void ContendMemory(ushort addr) - { - /* - if (IsContended(addr)) - { - var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle); - CPU.TotalExecutedCycles += delay; - } */ + + WriteBus(addr, value); } /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index ef2fad7331..6d8fa99e96 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -18,9 +18,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { bool deviceAddressed = true; - // process IO contention - ContendPort(port); - int result = 0xFF; // check AY @@ -57,30 +54,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (!deviceAddressed) { // If this is an unused port the floating memory bus should be returned - // Floating bus is read on the previous cycle - long _tStates = CurrentFrameCycle - 1; - - ULADevice.ReadFloatingBus((int)_tStates, ref result); - - /* - - // if we are on the top or bottom border return 0xff - if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) - { - result = 0xff; - } - else - { - if (ULADevice.floatingBusTable[_tStates] < 0) - { - result = 0xff; - } - else - { - result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); - } - } - */ + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); } return (byte)result; @@ -93,9 +67,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WritePort(ushort port, byte value) { - // process IO contention - ContendPort(port); - // get a BitArray of the port BitArray portBits = new BitArray(BitConverter.GetBytes(port)); // get a BitArray of the value byte @@ -179,9 +150,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - if (ULADevice.BorderColor != (value & BORDER_BIT)) - ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.BorderColor = value & BORDER_BIT; // Buzzer @@ -217,15 +185,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } set { ROMPaged = value; } } - - /// - /// Contend port if necessary - /// - /// - public override void ContendPort(ushort addr) - { - //CPUMon.ContendPort(addr); - return; - } } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index 45745dcd26..9102cfd72e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -96,7 +96,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - ContendMemory(addr); var data = ReadBus(addr); return data; } @@ -108,41 +107,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// /// public override void WriteMemory(ushort addr, byte value) - { - // update ULA screen buffer if necessary BEFORE T1 write - //if ((addr & 49152) == 16384 && _render) - //ULADevice.RenderScreen((int)CurrentFrameCycle); - - ContendMemory(addr); + { WriteBus(addr, value); } - /// - /// Contends memory if necessary - /// - public override void ContendMemory(ushort addr) - { - return; - /* - if (IsContended(addr)) - { - var off = 1; - var offset = CurrentFrameCycle + off; - if (offset < 0) - offset += ULADevice.FrameCycleLength; - if (offset >= ULADevice.FrameCycleLength) - offset -= ULADevice.FrameCycleLength; - - var delay = ULADevice.GetContentionValue((int)offset); - if (delay > 0) - { - - } - CPU.TotalExecutedCycles += delay; - } - */ - } - /// /// Checks whether supplied address is in a potentially contended bank /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index f6b01cc3be..c500aab222 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -15,9 +15,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadPort(ushort port) { - // process IO contention - ContendPort(port); - int result = 0xFF; // Check whether the low bit is reset @@ -56,29 +53,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // If this is an unused port the floating memory bus should be returned - ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); - - /* - // Floating bus is read on the previous cycle - long _tStates = CurrentFrameCycle - 1; - - // if we are on the top or bottom border return 0xff - if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod)) - { - result = 0xff; - } - else - { - if (ULADevice.floatingBusTable[_tStates] < 0) - { - result = 0xff; - } - else - { - result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]); - } - } - */ + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); } return (byte)result; @@ -91,9 +66,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WritePort(ushort port, byte value) { - // process IO contention - ContendPort(port); - // Check whether the low bit is reset // Technically the ULA should respond to every even I/O address if ((port & 0x0001) != 0) @@ -124,39 +96,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } - /// - /// Simulates IO port contention based on the supplied address - /// This method is for 48k and 128k/+2 machines only and should be overridden for other models - /// - /// - public override void ContendPort(ushort addr) - { - /* - It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port. As is the case with memory access, - this can be lengthened by the ULA. There are two effects which occur here: - - If the port address being accessed has its low bit reset, the ULA is required to supply the result, which leads to a delay if it is - currently busy handling the screen. - The address of the port being accessed is placed on the data bus. If this is in the range 0x4000 to 0x7fff, the ULA treats this as an - attempted access to contended memory and therefore introduces a delay. If the port being accessed is between 0xc000 and 0xffff, - this effect does not apply, even on a 128K machine if a contended memory bank is paged into the range 0xc000 to 0xffff. - - These two effects combine to lead to the following contention patterns: - - High byte | | - in 40 - 7F? | Low bit | Contention pattern - ------------+---------+------------------- - No | Reset | N:1, C:3 - No | Set | N:4 - Yes | Reset | C:1, C:3 - Yes | Set | C:1, C:1, C:1, C:1 - - The 'Contention pattern' column should be interpreted from left to right. An "N:n" entry means that no delay is applied at this cycle, and the Z80 continues uninterrupted for 'n' T states. A "C:n" entry means that the ULA halts the Z80; the delay is exactly the same as would occur for a contended memory access at this cycle (eg 6 T states at cycle 14335, 5 at 14336, etc on the 48K machine). After this delay, the Z80 then continues for 'n' cycles. - */ - - //CPUMon.ContendPort(addr); - return; - } - } } From af788ee108679e5eed38651e85de9a20c97cb48d Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 6 Jun 2018 13:55:57 -0400 Subject: [PATCH 21/51] z80: fix IO contention bug --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 4b4b5e50d6..4b6938b4b9 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -561,7 +561,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { BIO1, BIO2, BIO3, BIO4, PCh, 0, 0, 0 }; } private void IN_() @@ -594,7 +594,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { BIO1, BIO2, BIO3, BIO4, PCh, 0, 0, 0 }; } private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) From 275092528a5c4b9fed7f6a50dd22a0119c76b212 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 6 Jun 2018 19:34:46 -0400 Subject: [PATCH 22/51] z80: Fix some bugs in flags and WZ register Only thing remaining is INI/IND/INIR/INDR --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 28 ++++++++--------- .../CPUs/Z80A/Operations.cs | 2 +- .../CPUs/Z80A/Registers.cs | 1 + .../CPUs/Z80A/Tables_Indirect.cs | 30 +++++++++++++++++++ BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 29 ++++++++++++++++++ 5 files changed, 75 insertions(+), 15 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index 987c876bc5..3912d5668d 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -104,7 +104,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0x43: REG_OP(TR, B, E); break; // LD B, E case 0x44: REG_OP(TR, B, H); break; // LD B, H case 0x45: REG_OP(TR, B, L); break; // LD B, L - case 0x46: REG_OP_IND(TR, B, L, H); break; // LD B, (HL) + case 0x46: REG_OP_IND_HL(TR, B); break; // LD B, (HL) case 0x47: REG_OP(TR, B, A); break; // LD B, A case 0x48: REG_OP(TR, C, B); break; // LD C, B case 0x49: REG_OP(TR, C, C); break; // LD C, C @@ -112,7 +112,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0x4B: REG_OP(TR, C, E); break; // LD C, E case 0x4C: REG_OP(TR, C, H); break; // LD C, H case 0x4D: REG_OP(TR, C, L); break; // LD C, L - case 0x4E: REG_OP_IND(TR, C, L, H); break; // LD C, (HL) + case 0x4E: REG_OP_IND_HL(TR, C); break; // LD C, (HL) case 0x4F: REG_OP(TR, C, A); break; // LD C, A case 0x50: REG_OP(TR, D, B); break; // LD D, B case 0x51: REG_OP(TR, D, C); break; // LD D, C @@ -120,7 +120,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0x53: REG_OP(TR, D, E); break; // LD D, E case 0x54: REG_OP(TR, D, H); break; // LD D, H case 0x55: REG_OP(TR, D, L); break; // LD D, L - case 0x56: REG_OP_IND(TR, D, L, H); break; // LD D, (HL) + case 0x56: REG_OP_IND_HL(TR, D); break; // LD D, (HL) case 0x57: REG_OP(TR, D, A); break; // LD D, A case 0x58: REG_OP(TR, E, B); break; // LD E, B case 0x59: REG_OP(TR, E, C); break; // LD E, C @@ -128,7 +128,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0x5B: REG_OP(TR, E, E); break; // LD E, E case 0x5C: REG_OP(TR, E, H); break; // LD E, H case 0x5D: REG_OP(TR, E, L); break; // LD E, L - case 0x5E: REG_OP_IND(TR, E, L, H); break; // LD E, (HL) + case 0x5E: REG_OP_IND_HL(TR, E); break; // LD E, (HL) case 0x5F: REG_OP(TR, E, A); break; // LD E, A case 0x60: REG_OP(TR, H, B); break; // LD H, B case 0x61: REG_OP(TR, H, C); break; // LD H, C @@ -136,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0x63: REG_OP(TR, H, E); break; // LD H, E case 0x64: REG_OP(TR, H, H); break; // LD H, H case 0x65: REG_OP(TR, H, L); break; // LD H, L - case 0x66: REG_OP_IND(TR, H, L, H); break; // LD H, (HL) + case 0x66: REG_OP_IND_HL(TR, H); break; // LD H, (HL) case 0x67: REG_OP(TR, H, A); break; // LD H, A case 0x68: REG_OP(TR, L, B); break; // LD L, B case 0x69: REG_OP(TR, L, C); break; // LD L, C @@ -144,23 +144,23 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case 0x6B: REG_OP(TR, L, E); break; // LD L, E case 0x6C: REG_OP(TR, L, H); break; // LD L, H case 0x6D: REG_OP(TR, L, L); break; // LD L, L - case 0x6E: REG_OP_IND(TR, L, L, H); break; // LD L, (HL) + case 0x6E: REG_OP_IND_HL(TR, L); break; // LD L, (HL) case 0x6F: REG_OP(TR, L, A); break; // LD L, A - case 0x70: LD_8_IND(L, H, B); break; // LD (HL), B - case 0x71: LD_8_IND(L, H, C); break; // LD (HL), C - case 0x72: LD_8_IND(L, H, D); break; // LD (HL), D - case 0x73: LD_8_IND(L, H, E); break; // LD (HL), E - case 0x74: LD_8_IND(L, H, H); break; // LD (HL), H - case 0x75: LD_8_IND(L, H, L); break; // LD (HL), L + case 0x70: LD_8_IND_HL(B); break; // LD (HL), B + case 0x71: LD_8_IND_HL(C); break; // LD (HL), C + case 0x72: LD_8_IND_HL(D); break; // LD (HL), D + case 0x73: LD_8_IND_HL(E); break; // LD (HL), E + case 0x74: LD_8_IND_HL(H); break; // LD (HL), H + case 0x75: LD_8_IND_HL(L); break; // LD (HL), L case 0x76: HALT_(); break; // HALT - case 0x77: LD_8_IND(L, H, A); break; // LD (HL), A + case 0x77: LD_8_IND_HL( A); break; // LD (HL), A case 0x78: REG_OP(TR, A, B); break; // LD A, B case 0x79: REG_OP(TR, A, C); break; // LD A, C case 0x7A: REG_OP(TR, A, D); break; // LD A, D case 0x7B: REG_OP(TR, A, E); break; // LD A, E case 0x7C: REG_OP(TR, A, H); break; // LD A, H case 0x7D: REG_OP(TR, A, L); break; // LD A, L - case 0x7E: REG_OP_IND(TR, A, L, H); break; // LD A, (HL) + case 0x7E: REG_OP_IND_HL(TR, A); break; // LD A, (HL) case 0x7F: REG_OP(TR, A, A); break; // LD A, A case 0x80: REG_OP(ADD8, A, B); break; // ADD A, B case 0x81: REG_OP(ADD8, A, C); break; // ADD A, C diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs index 4ec81fe298..69c6b78a7e 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs @@ -757,7 +757,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A FlagZ = Regs[A] == 0; FlagS = Regs[A] > 127; FlagP = iff2; - Flag5 = (Regs[A] & 0x02) != 0; + Flag5 = (Regs[A] & 0x20) != 0; Flag3 = (Regs[A] & 0x08) != 0; } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index d7c7cbe90f..7f392fbe0c 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -40,6 +40,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public ushort H_s = 30; public ushort L_s = 31; public ushort DB = 32; + public ushort scratch = 33; public ushort IRQ_V = 34; // IRQ mode 1 vector public ushort NMI_V = 35; // NMI vector diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index b8f3505fa4..53b6cdf22d 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -85,6 +85,21 @@ BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } + // different because HL doesn't effect WZ + private void REG_OP_IND_HL(ushort operation, ushort dest) + { + cur_instr = new ushort[] + {IDLE, + WAIT, + RD, ALU, L, H, + operation, dest, ALU, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { H, 0, 0, PCh, 0, 0, 0 }; + } + private void LD_16_IND_nn(ushort src_l, ushort src_h) { cur_instr = new ushort[] @@ -185,6 +200,21 @@ BUSRQ = new ushort[] { dest_h, 0, 0, PCh, 0, 0, 0 }; } + // seperate HL needed since it doesn't effect the WZ pair + private void LD_8_IND_HL(ushort src) + { + cur_instr = new ushort[] + {IDLE, + WAIT, + WR, L, H, src, + IDLE, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { H, 0, 0, PCh, 0, 0, 0 }; + } + private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) { cur_instr = new ushort[] diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 34ec1bb5ff..b4b1834cc9 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -506,6 +506,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Regs[W] = 0; break; case REP_OP_I: + + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); ushort temp4 = cur_instr[instr_pntr++]; @@ -515,14 +517,34 @@ namespace BizHawk.Emulation.Cores.Components.Z80A TR16_Func(Z, W, C, B); DEC16_Func(Z, W); DEC8_Func(B); + + // take care of other flags + // taken from 'undocumented z80 documented' + FlagN = Regs[ALU].Bit(7); + FlagH = FlagC = (Regs[ALU] + (Regs[C] - 1) & 0xFF) > 0xFF; + FlagP = TableParity[((Regs[ALU] + (Regs[C] - 1) & 0xFF) & 7) ^ (Regs[B])]; } else { INC16_Func(L, H); + TR16_Func(Z, W, C, B); INC16_Func(Z, W); DEC8_Func(B); + + //Read_Func(scratch, L, H); + if (opcode == 0xA2) + { + Console.Write(Regs[ALU]); + Console.Write(" "); + } + // take care of other flags + // taken from 'undocumented z80 documented' + FlagN = Regs[ALU].Bit(7); + FlagH = FlagC = (Regs[ALU] + (Regs[W]) & 0xFF) > 0xFF; + FlagP = TableParity[((Regs[ALU] + (Regs[W]) & 0xFF) & 7) ^ Regs[Z]]; } + Repeat_Op(); break; case REP_OP_O: @@ -543,6 +565,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A TR16_Func(Z, W, C, B); INC16_Func(Z, W); } + + // take care of other flags + // taken from 'undocumented z80 documented' + FlagN = Regs[ALU].Bit(7); + FlagH = FlagC = (Regs[ALU] + Regs[L]) > 0xFF; + FlagP = TableParity[((Regs[ALU] + Regs[L]) & 7) ^ (Regs[B])]; + Repeat_Op(); break; } From afd1ba38d8e4bfa1ec3f2a616733d6f4bc77456b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 7 Jun 2018 08:10:39 -0400 Subject: [PATCH 23/51] z80: Fix remaining flags and WZ --- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 25 ++++++++--------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index b4b1834cc9..1aade3839f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -505,9 +505,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Regs[Z] = cur_instr[instr_pntr++]; Regs[W] = 0; break; - case REP_OP_I: - - + case REP_OP_I: Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); ushort temp4 = cur_instr[instr_pntr++]; @@ -519,30 +517,23 @@ namespace BizHawk.Emulation.Cores.Components.Z80A DEC8_Func(B); // take care of other flags - // taken from 'undocumented z80 documented' + // taken from 'undocumented z80 documented' and Fuse FlagN = Regs[ALU].Bit(7); - FlagH = FlagC = (Regs[ALU] + (Regs[C] - 1) & 0xFF) > 0xFF; - FlagP = TableParity[((Regs[ALU] + (Regs[C] - 1) & 0xFF) & 7) ^ (Regs[B])]; + FlagH = FlagC = ((Regs[ALU] + Regs[C] - 1) & 0xFF) < Regs[ALU]; + FlagP = TableParity[((Regs[ALU] + Regs[C] - 1) & 7) ^ Regs[B]]; } else { - INC16_Func(L, H); - + INC16_Func(L, H); TR16_Func(Z, W, C, B); INC16_Func(Z, W); DEC8_Func(B); - //Read_Func(scratch, L, H); - if (opcode == 0xA2) - { - Console.Write(Regs[ALU]); - Console.Write(" "); - } // take care of other flags - // taken from 'undocumented z80 documented' + // taken from 'undocumented z80 documented' and Fuse FlagN = Regs[ALU].Bit(7); - FlagH = FlagC = (Regs[ALU] + (Regs[W]) & 0xFF) > 0xFF; - FlagP = TableParity[((Regs[ALU] + (Regs[W]) & 0xFF) & 7) ^ Regs[Z]]; + FlagH = FlagC = ((Regs[ALU] + Regs[C] + 1) & 0xFF) < Regs[ALU]; + FlagP = TableParity[((Regs[ALU] + Regs[C] + 1) & 7) ^ Regs[B]]; } Repeat_Op(); From b0af0e48e0c3d8e5abdb69d7bf1b3654d68f1d09 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 7 Jun 2018 08:34:21 -0400 Subject: [PATCH 24/51] z80: IR contention update --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 4b6938b4b9..1618cd986d 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] {I, I, PCh, 0, 0, 0}; } @@ -78,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] {I, I, PCh, 0, 0, 0}; } // this is done in two steps technically, but the flags don't work out using existing funcitons @@ -98,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] {I, I, I, I, I, I, I, PCh, 0, 0, 0 }; } private void REG_OP(ushort operation, ushort dest, ushort src) @@ -122,7 +122,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, PCh, 0, 0, 0 }; } // note: do not use DEC here since no flags are affected by this operation @@ -314,7 +314,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] {I, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; } else { @@ -325,7 +325,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] {I, PCh, 0, 0, 0}; } } From 843dc7a69a325f71453a12b0543d33282b45249e Mon Sep 17 00:00:00 2001 From: Asnivor Date: Thu, 7 Jun 2018 15:33:58 +0100 Subject: [PATCH 25/51] ZXHawk: Small performance increase (rendering cycle now happens only when it needs to) --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 4 +--- .../SinclairSpectrum/Machine/SpectrumBase.cs | 2 ++ .../Computers/SinclairSpectrum/Machine/ULA.cs | 4 ---- .../Machine/ZXSpectrum128K/ZX128.Memory.cs | 2 ++ .../ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs | 6 ++++++ .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 6 +++++- .../ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 8 +++++++- .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 6 +++++- .../Machine/ZXSpectrum16K/ZX16.cs | 15 +-------------- .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 3 ++- .../Machine/ZXSpectrum48K/ZX48.Port.cs | 7 +++++-- 11 files changed, 36 insertions(+), 27 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index fbdc5d2134..5890279f31 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -61,8 +61,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void ExecuteCycle() { - _machine.ULADevice.RenderScreen((int)_machine.CurrentFrameCycle); - // is the next CPU cycle causing a BUSRQ or IORQ? if (BUSRQ > 0) { @@ -208,7 +206,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; // WZ: T3 case Z80A.WIO3: - lastPortAddr = AscertainBUSRQAddress(); + lastPortAddr = AscertainBUSRQAddress(); isIO = true; if (IsIOCycleContended(3)) _cpu.TotalExecutedCycles += _machine.ULADevice.GetPortContentionValue((int)_machine.CurrentFrameCycle); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index 35161bf3a3..3b5eaa6da9 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -167,7 +167,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum while (CurrentFrameCycle < ULADevice.FrameLength) { ULADevice.CheckForInterrupt(CurrentFrameCycle); + CPUMon.ExecuteCycle(); + // cycle the tape device if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) TapeDevice.TapeCycle(); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 345b468cb7..e953e2a9e0 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -589,10 +589,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // check boundaries if (toCycle > FrameCycleLength) toCycle = FrameCycleLength; - if (LastTState > toCycle) - LastTState = toCycle - 2; - if (toCycle < 0) - toCycle = 0; // render the required number of cycles for (int t = LastTState; t < toCycle; t++) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs index 99065d6b45..6be56554a3 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs @@ -134,6 +134,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7) case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; @@ -162,6 +163,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum RAM4[addr % 0x4000] = value; break; case 5: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; case 6: diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs index aec8326d86..3fec363a6e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs @@ -236,9 +236,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; case 1: case 2: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; case 3: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM7[addr % 0x4000] = value; break; } @@ -265,6 +267,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum RAM3[addr % 0x4000] = value; break; case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM7[addr % 0x4000] = value; break; } @@ -299,6 +302,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // RAM 0x4000 (RAM5 - Bank5 only) case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; @@ -327,12 +331,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum RAM4[addr % 0x4000] = value; break; case 5: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; case 6: RAM6[addr % 0x4000] = value; break; case 7: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM7[addr % 0x4000] = value; break; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index 431444b67d..a2cd41da7d 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -144,7 +144,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - ULADevice.BorderColor = value & BORDER_BIT; + if (ULADevice.BorderColor != (value & BORDER_BIT)) + { + ULADevice.RenderScreen((int)CurrentFrameCycle); + ULADevice.BorderColor = value & BORDER_BIT; + } // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index 80a9e9888f..742a10adb3 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -236,10 +236,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum break; case 1: case 2: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; case 3: - RAM7[addr % 0x4000] = value; + ULADevice.RenderScreen((int)CurrentFrameCycle); + RAM7[addr % 0x4000] = value; break; } break; @@ -265,6 +267,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum RAM3[addr % 0x4000] = value; break; case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM7[addr % 0x4000] = value; break; } @@ -299,6 +302,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // RAM 0x4000 (RAM5 - Bank5 only) case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; @@ -327,12 +331,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum RAM4[addr % 0x4000] = value; break; case 5: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM5[addr % 0x4000] = value; break; case 6: RAM6[addr % 0x4000] = value; break; case 7: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM7[addr % 0x4000] = value; break; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index 6d8fa99e96..31c2e08e44 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -150,7 +150,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - ULADevice.BorderColor = value & BORDER_BIT; + if (ULADevice.BorderColor != (value & BORDER_BIT)) + { + ULADevice.RenderScreen((int)CurrentFrameCycle); + ULADevice.BorderColor = value & BORDER_BIT; + } // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs index c17d90fe26..fef7ea7b45 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs @@ -85,6 +85,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // cannot write to ROM break; case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM0[index] = value; break; } @@ -98,11 +99,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override byte ReadMemory(ushort addr) { - /* - if (IsContended(addr)) - CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle); - */ - var data = ReadBus(addr); return data; } @@ -115,15 +111,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public override void WriteMemory(ushort addr, byte value) { - /* - // apply contention if necessary - if (IsContended(addr)) - { - ULADevice.RenderScreen((int)CurrentFrameCycle); - CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle); - } - */ - WriteBus(addr, value); } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index 9102cfd72e..bd4c2564cd 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -77,10 +77,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // cannot write to ROM break; case 1: + ULADevice.RenderScreen((int)CurrentFrameCycle); RAM0[index] = value; break; case 2: - RAM1[index] = value; + RAM1[index] = value; break; case 3: RAM2[index] = value; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index c500aab222..31fd2ac00b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -82,8 +82,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - //ULADevice.RenderScreen((int)CurrentFrameCycle); - ULADevice.BorderColor = value & BORDER_BIT; + if (ULADevice.BorderColor != (value & BORDER_BIT)) + { + ULADevice.RenderScreen((int)CurrentFrameCycle); + ULADevice.BorderColor = value & BORDER_BIT; + } // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); From cd7df2ea07905e32ce6ad5337dfcd949061a8947 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 7 Jun 2018 10:37:26 -0400 Subject: [PATCH 26/51] z80: more contention work --- .../CPUs/Z80A/Tables_Indirect.cs | 20 +- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 236 ++++++++++-------- 2 files changed, 139 insertions(+), 117 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 53b6cdf22d..2a1779aee5 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -446,16 +446,16 @@ private void LD_OP_R(ushort operation, ushort repeat_instr) { cur_instr = new ushort[] - {IDLE, - WAIT, - RD, ALU, L, H, - operation, L, H, - WAIT, - WR, E, D, ALU, - operation, E, D, - SET_FL_LD_R, 0, operation, repeat_instr}; + {IDLE, + WAIT, + RD, ALU, L, H, + operation, L, H, + WAIT, + WR, E, D, ALU, + IDLE, + SET_FL_LD_R, 0, operation, repeat_instr}; - BUSRQ = new ushort[] { H, 0, 0, D, 0, 0, D, D}; + BUSRQ = new ushort[] { H, 0, 0, D, 0, 0, D, D }; } private void CP_OP_R(ushort operation, ushort repeat_instr) @@ -464,7 +464,7 @@ {IDLE, WAIT, RD, ALU, L, H, - operation, L, H, + IDLE, DEC16, C, B, operation, Z, W, IDLE, diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 1aade3839f..b335d052bf 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -80,8 +80,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort RST = 65; public const ushort REP_OP_I = 66; public const ushort REP_OP_O = 67; - + // non-state variables + public ushort Ztemp1, Ztemp2, Ztemp3, Ztemp4; public byte temp_R; public Z80A() @@ -482,11 +483,71 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case SET_FL_LD_R: DEC16_Func(C, B); SET_FL_LD_Func(); - Repeat_Op(); + + Ztemp1 = cur_instr[instr_pntr++]; + Ztemp2 = cur_instr[instr_pntr++]; + Ztemp3 = cur_instr[instr_pntr++]; + + if (((Regs[C] | (Regs[B] << 8)) != 0) && (Ztemp3 > 0)) + { + cur_instr = new ushort[] + {TR16, Z, W, PCl, PCh, + INC16, Z, W, + DEC16, PCl, PCh, + DEC16, PCl, PCh, + IDLE, + Ztemp2, E, D, + WAIT, + OP_F, + OP}; + + BUSRQ = new ushort[] { D, D, D, D, D, PCh, 0, 0, 0 }; + } + else + { + cur_instr = new ushort[] + { Ztemp2, E, D, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + } + instr_pntr = 0; bus_pntr = 0; break; case SET_FL_CP_R: SET_FL_CP_Func(); - Repeat_Op(); + + Ztemp1 = cur_instr[instr_pntr++]; + Ztemp2 = cur_instr[instr_pntr++]; + Ztemp3 = cur_instr[instr_pntr++]; + + if (((Regs[C] | (Regs[B] << 8)) != 0) && (Ztemp3 > 0) && !FlagZ) + { + cur_instr = new ushort[] + {TR16, Z, W, PCl, PCh, + INC16, Z, W, + DEC16, PCl, PCh, + DEC16, PCl, PCh, + IDLE, + Ztemp2, L, H, + WAIT, + OP_F, + OP}; + + BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; + } + else + { + cur_instr = new ushort[] + { Ztemp2, L, H, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + } + instr_pntr = 0; bus_pntr = 0; break; case SET_FL_IR: SET_FL_IR_Func(cur_instr[instr_pntr++]); @@ -508,10 +569,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case REP_OP_I: Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - ushort temp4 = cur_instr[instr_pntr++]; - if (temp4 == DEC16) + Ztemp4 = cur_instr[instr_pntr++]; + if (Ztemp4 == DEC16) { - DEC16_Func(L, H); TR16_Func(Z, W, C, B); DEC16_Func(Z, W); DEC8_Func(B); @@ -523,8 +583,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A FlagP = TableParity[((Regs[ALU] + Regs[C] - 1) & 7) ^ Regs[B]]; } else - { - INC16_Func(L, H); + { TR16_Func(Z, W, C, B); INC16_Func(Z, W); DEC8_Func(B); @@ -536,13 +595,42 @@ namespace BizHawk.Emulation.Cores.Components.Z80A FlagP = TableParity[((Regs[ALU] + Regs[C] + 1) & 7) ^ Regs[B]]; } - Repeat_Op(); + Ztemp1 = cur_instr[instr_pntr++]; + Ztemp2 = cur_instr[instr_pntr++]; + Ztemp3 = cur_instr[instr_pntr++]; + + if ((Regs[B] != 0) && (Ztemp3 > 0)) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, PCl, PCh, + DEC16, PCl, PCh, + IDLE, + Ztemp2, L, H, + WAIT, + OP_F, + OP}; + + BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; + } + else + { + cur_instr = new ushort[] + { Ztemp2, L, H, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + } + instr_pntr = 0; bus_pntr = 0; break; case REP_OP_O: OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); - ushort temp5 = cur_instr[instr_pntr++]; - if (temp5 == DEC16) + Ztemp4 = cur_instr[instr_pntr++]; + if (Ztemp4 == DEC16) { DEC16_Func(L, H); DEC8_Func(B); @@ -563,107 +651,41 @@ namespace BizHawk.Emulation.Cores.Components.Z80A FlagH = FlagC = (Regs[ALU] + Regs[L]) > 0xFF; FlagP = TableParity[((Regs[ALU] + Regs[L]) & 7) ^ (Regs[B])]; - Repeat_Op(); + Ztemp1 = cur_instr[instr_pntr++]; + Ztemp2 = cur_instr[instr_pntr++]; + Ztemp3 = cur_instr[instr_pntr++]; + + if ((Regs[B] != 0) && (Ztemp3 > 0)) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, PCl, PCh, + DEC16, PCl, PCh, + IDLE, + IDLE, + WAIT, + OP_F, + OP}; + + BUSRQ = new ushort[] { B, B, B, B, B, PCh, 0, 0, 0 }; + } + else + { + cur_instr = new ushort[] + { IDLE, + WAIT, + OP_F, + OP }; + + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + } + instr_pntr = 0; bus_pntr = 0; break; } TotalExecutedCycles++; } - public void Repeat_Op() - { - // determine if we repeat based on what operation we are doing - // single execution versions also come here, but never repeat - ushort temp1 = cur_instr[instr_pntr++]; - ushort temp2 = cur_instr[instr_pntr++]; - ushort temp3 = cur_instr[instr_pntr++]; - - bool repeat = false; - int Reg16_d = Regs[C] | (Regs[B] << 8); - switch (temp1) - { - case 0: - repeat = Reg16_d != 0; - break; - case 1: - repeat = (Reg16_d != 0) && !FlagZ; - break; - case 2: - repeat = Regs[B] != 0; - break; - case 3: - repeat = Regs[B] != 0; - break; - } - - // if we repeat, we do a 5 cycle refresh which decrements PC by 2 - // if we don't repeat, continue on as a normal opcode fetch - if (repeat && temp3 > 0) - { - cur_instr = new ushort[] - {DEC16, PCl, PCh, - DEC16, PCl, PCh, - IDLE, - IDLE, - IDLE, - IDLE, - WAIT, - OP_F, - OP}; - - if (temp1 == 0) - { - BUSRQ = new ushort[] { D, D, D, D, D, PCh, 0, 0, 0 }; - } - else if (temp1 == 1) - { - BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; - } - else if (temp1 == 2) - { - BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; - } - else if (temp1 == 3) - { - BUSRQ = new ushort[] { B, B, B, B, B, PCh, 0, 0, 0 }; - } - - instr_pntr = 0; bus_pntr = 0; - // adjust WZ register accordingly - switch (temp1) - { - case 0: - // TEST: PC before or after the instruction? - Regs[Z] = Regs[PCl]; - Regs[W] = Regs[PCh]; - INC16_Func(Z, W); - break; - case 1: - // TEST: PC before or after the instruction? - Regs[Z] = Regs[PCl]; - Regs[W] = Regs[PCh]; - INC16_Func(Z, W); - break; - case 2: - // Nothing - break; - case 3: - // Nothing - break; - } - } - else - { - cur_instr = new ushort[] - { IDLE, - WAIT, - OP_F, - OP }; - - BUSRQ = new ushort[] { PCh, 0, 0, 0 }; - instr_pntr = 0; bus_pntr = 0; - } - } - // tracer stuff public Action TraceCallback; From 7ad65bd96ef83e3ebd4a7274bf1bb0213afeaf6b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 7 Jun 2018 11:11:56 -0400 Subject: [PATCH 27/51] z80: WZ fixes --- BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs | 2 +- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index 1618cd986d..f305eafbab 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -541,7 +541,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, WAIT, OUT, Z, W, A, - INC16, Z, W, + INC16, Z, ALU, WAIT, OP_F, OP}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index b335d052bf..8407f0d937 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -491,10 +491,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (((Regs[C] | (Regs[B] << 8)) != 0) && (Ztemp3 > 0)) { cur_instr = new ushort[] - {TR16, Z, W, PCl, PCh, - INC16, Z, W, - DEC16, PCl, PCh, + {DEC16, PCl, PCh, DEC16, PCl, PCh, + TR16, Z, W, PCl, PCh, + INC16, Z, W, IDLE, Ztemp2, E, D, WAIT, @@ -525,10 +525,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (((Regs[C] | (Regs[B] << 8)) != 0) && (Ztemp3 > 0) && !FlagZ) { cur_instr = new ushort[] - {TR16, Z, W, PCl, PCh, - INC16, Z, W, - DEC16, PCl, PCh, + {DEC16, PCl, PCh, DEC16, PCl, PCh, + TR16, Z, W, PCl, PCh, + INC16, Z, W, IDLE, Ztemp2, L, H, WAIT, From 83bbb83c64e545b7fd2a539cdc95ddbf83f9770e Mon Sep 17 00:00:00 2001 From: Asnivor Date: Thu, 7 Jun 2018 16:40:48 +0100 Subject: [PATCH 28/51] ZXHawk: Missed rendercycle call on 128k border OUT --- .../SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index ec358785d5..9fe37c4c14 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -127,7 +127,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum */ // Border - LSB 3 bits hold the border colour - ULADevice.BorderColor = value & BORDER_BIT; + if (ULADevice.BorderColor != (value & BORDER_BIT)) + { + ULADevice.RenderScreen((int)CurrentFrameCycle); + ULADevice.BorderColor = value & BORDER_BIT; + } // Buzzer BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0); From 25fe4a7a87c66a683d5e7bf8ff7ece66a39851cf Mon Sep 17 00:00:00 2001 From: Asnivor Date: Thu, 7 Jun 2018 18:00:08 +0100 Subject: [PATCH 29/51] ZXHawk: more prep for contended 128k/+2/+2a/+3 --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 62 ++++++++++++++++++- .../Computers/SinclairSpectrum/Machine/ULA.cs | 16 +++-- .../Machine/ZXSpectrum128K/ZX128.Screen.cs | 3 + .../ZX128Plus2a.Screen.cs | 3 + .../Machine/ZXSpectrum48K/ZX48.Screen.cs | 3 + 5 files changed, 81 insertions(+), 6 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 5890279f31..9708236f5d 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -237,10 +237,66 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum switch (machineType) { case MachineType.ZXSpectrum16: - case MachineType.ZXSpectrum48: + case MachineType.ZXSpectrum48: + + if ((lastPortAddr & 0xc000) == 0x4000) + highByte407f = true; + + if (highByte407f) + { + // high byte 40-7f + if (lowBitSet) + { + // high byte 40-7f + // low bit set + // C:1, C:1, C:1, C:1 + switch (T) + { + case 1: + case 2: + case 3: + case 4: + return true; + } + } + else + { + // high byte 40-7f + // low bit reset + // C:1, C:3 + switch (T) + { + case 1: + case 2: + return true; + } + } + } + else + { + // high byte not 40-7f + if (lowBitSet) + { + // high byte not 40-7f + // low bit set + // N:4 + } + else + { + // high byte not 40-7f + // low bit reset + // N:1, C:3 + switch (T) + { + case 2: + return true; + } + } + } + break; + case MachineType.ZXSpectrum128: case MachineType.ZXSpectrum128Plus2: - if ((lastPortAddr & 0xc000) == 0x4000) highByte407f = true; @@ -299,6 +355,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case MachineType.ZXSpectrum128Plus2a: case MachineType.ZXSpectrum128Plus3: + // No contention occurs as the ULA only applies contention when the Z80 MREQ line is active + // (which is not during an IO operation) break; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index e953e2a9e0..0bec3a194c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -88,6 +88,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int InterruptLength; + /// + /// Arbitrary offset into the contention array (for memory ops) + /// + public int MemoryContentionOffset; + + /// + /// Arbitrary offset into the contention array (for port ops) + /// + public int PortContentionOffset; + /// /// The time in T-States for one scanline to complete /// @@ -776,8 +786,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetContentionValue(int tstate) { - int off = 5; - tstate += off; + tstate += MemoryContentionOffset; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; @@ -793,8 +802,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetPortContentionValue(int tstate) { - int off = 5; - tstate += off; + tstate += PortContentionOffset; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs index cbd98f1128..547e0fab72 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -20,6 +20,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum InterruptLength = 36; ScanlineTime = 228; + MemoryContentionOffset = 5; + PortContentionOffset = 5; + BorderLeftTime = 24; BorderRightTime = 24; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs index e9026ce5d7..949ca558ce 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -20,6 +20,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum InterruptLength = 32; ScanlineTime = 228; + MemoryContentionOffset = 7; + PortContentionOffset = 7; + BorderLeftTime = 24; BorderRightTime = 24; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs index 96219e04db..5af98f944a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -20,6 +20,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum InterruptLength = 32; ScanlineTime = 224; + MemoryContentionOffset = 5; + PortContentionOffset = 5; + BorderLeftTime = 24; BorderRightTime = 24; From f4c47dc80aa0924f0c76c33fc10c8a16f5016d9c Mon Sep 17 00:00:00 2001 From: Asnivor Date: Thu, 7 Jun 2018 18:27:44 +0100 Subject: [PATCH 30/51] ZXHawk: modified vblank interrupt start time (128k/+2a/+3) so contention period starts at the correct time --- .../SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs | 2 +- .../Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs index 547e0fab72..3e1aed6e24 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3546900; FrameCycleLength = 70908; - InterruptStartTime = 33; + InterruptStartTime = 32; InterruptLength = 36; ScanlineTime = 228; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs index 949ca558ce..90f505d1f2 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3546900; FrameCycleLength = 70908; - InterruptStartTime = 33; + InterruptStartTime = 31; InterruptLength = 32; ScanlineTime = 228; From 6ae8f0187242f5d06704efb316dd9da2e5fb79e6 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 7 Jun 2018 18:41:50 -0400 Subject: [PATCH 31/51] z80: Fix some more contention stuff --- .../CPUs/Z80A/Registers.cs | 2 +- .../CPUs/Z80A/Tables_Direct.cs | 10 ++++----- .../CPUs/Z80A/Tables_Indirect.cs | 22 +++++++++---------- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 12 +++++++++- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index 7f392fbe0c..7d4271373b 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -58,7 +58,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort WIO4 = 108; - public bool FlagI; + public bool FlagI;/*, FlagI1, FlagI2, FlagI3, FlagI4, FlagI5, FlagI6;*/ public bool FlagW; // wait flag, when set to true reads / writes will be delayed diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index f305eafbab..f91fb31afc 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -537,11 +537,11 @@ namespace BizHawk.Emulation.Cores.Components.Z80A {TR, W, A, WAIT, RD_INC, Z, PCl, PCh, - IDLE, - WAIT, + IDLE, + WAIT, WAIT, OUT, Z, W, A, - INC16, Z, ALU, + INC16, Z, ALU, WAIT, OP_F, OP}; @@ -552,9 +552,9 @@ namespace BizHawk.Emulation.Cores.Components.Z80A private void OUT_REG_(ushort dest, ushort src) { cur_instr = new ushort[] - {IDLE, + {TR16, Z, W, C, B, + IDLE, IDLE, - TR16, Z, W, C, B, OUT, Z, W, src, INC16, Z, W, WAIT, diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index 2a1779aee5..bab93cbe1f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -17,17 +17,17 @@ OP_F, OP }; - BUSRQ = new ushort[] { src_h, 0, 0, src_h, 0, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; } private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, src_l, src_h, operation, bit, ALU, + IDLE, WAIT, WR, src_l, src_h, ALU, IDLE, @@ -35,7 +35,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; } // Note that this operation uses I_BIT, same as indexed BIT. @@ -46,15 +46,15 @@ { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, src_l, src_h, + IDLE, I_BIT, bit, ALU, WAIT, OP_F, OP }; - BUSRQ = new ushort[] { 0, src_h, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, PCh, 0, 0, 0 }; } private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -267,10 +267,10 @@ { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, src_l, src_h, INC8, ALU, + IDLE, WAIT, WR, src_l, src_h, ALU, IDLE, @@ -278,17 +278,17 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; } private void DEC_8_IND(ushort src_l, ushort src_h) { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, src_l, src_h, DEC8, ALU, + IDLE, WAIT, WR, src_l, src_h, ALU, IDLE, @@ -296,7 +296,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; } // NOTE: WZ implied for the wollowing 3 functions @@ -304,10 +304,10 @@ { cur_instr = new ushort[] {IDLE, - IDLE, WAIT, RD, ALU, Z, W, operation, ALU, + IDLE, WAIT, WR, Z, W, ALU, TR, dest, ALU, @@ -315,7 +315,7 @@ OP_F, OP }; - BUSRQ = new ushort[] { 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { W, 0, 0, W, W, 0, 0, PCh, 0, 0, 0 }; } private void I_BIT_OP(ushort operation, ushort bit, ushort dest) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 8407f0d937..33c60fc97f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -159,6 +159,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // Execute instructions public void ExecuteOne() { + /*FlagI6 = FlagI; + FlagI5 = FlagI4; + FlagI4 = FlagI3; + FlagI3 = FlagI2; + FlagI2 = FlagI1; + FlagI1 = FlagI; + */ bus_pntr++; switch (cur_instr[instr_pntr++]) { @@ -663,11 +670,14 @@ namespace BizHawk.Emulation.Cores.Components.Z80A DEC16, PCl, PCh, DEC16, PCl, PCh, IDLE, - IDLE, + DEC16, B, ALU, WAIT, OP_F, OP}; + Regs[B] = (ushort)((Regs[B] + 1) & 0xFF); + + BUSRQ = new ushort[] { B, B, B, B, B, PCh, 0, 0, 0 }; } else From f33863126c21250708142a2440a28448e4f7dc18 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 09:36:32 +0100 Subject: [PATCH 32/51] ZXHawk: Fix rendertable generation offset. btime.tap test now passes --- .../Computers/SinclairSpectrum/Machine/ULA.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 0bec3a194c..398c0c958f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -327,7 +327,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum for (var t = 0; t < _ula.FrameCycleLength; t++) { - var tStateScreen = t + _ula.InterruptStartTime; + var tStateScreen = t + 1 + _ula.InterruptStartTime; if (tStateScreen < 0) tStateScreen += _ula.FrameCycleLength; @@ -719,7 +719,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void ReadFloatingBus(int tstate, ref int result) { - int off = 1; + int off = 0; tstate += off; if (tstate >= RenderingTable.Renderer.Length) tstate -= RenderingTable.Renderer.Length; From 403a1032d8c9aa3ca3fedc44b26bdd423337c661 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 11:07:16 +0100 Subject: [PATCH 33/51] ZXHawk: 48k Interrupt, ULA tables and contention tweaked --- .../Computers/SinclairSpectrum/Machine/ULA.cs | 65 ++++--------------- .../Machine/ZXSpectrum128K/ZX128.Screen.cs | 2 + .../ZX128Plus2a.Screen.cs | 2 + .../Machine/ZXSpectrum48K/ZX48.Screen.cs | 8 ++- 4 files changed, 22 insertions(+), 55 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 398c0c958f..0124f6721e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -98,6 +98,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int PortContentionOffset; + /// + /// Arbitrary offset for render table generation + /// + public int RenderTableOffset; + + /// + /// The offset when return floating bus bytes + /// + public int FloatingBusOffset; + /// /// The time in T-States for one scanline to complete /// @@ -317,17 +327,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// private void InitRenderer(MachineType machineType) { - switch (machineType) - { - case MachineType.ZXSpectrum16: - case MachineType.ZXSpectrum48: - Offset = 0; - break; - } - for (var t = 0; t < _ula.FrameCycleLength; t++) { - var tStateScreen = t + 1 + _ula.InterruptStartTime; + var tStateScreen = t + _ula.RenderTableOffset + _ula.InterruptStartTime; if (tStateScreen < 0) tStateScreen += _ula.FrameCycleLength; @@ -458,7 +460,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // calculate contention values for (int t = 0; t < _ula.FrameCycleLength; t++) { - int shifted = (t + 1) + _ula.InterruptStartTime + Offset; + int shifted = t + _ula.RenderTableOffset + _ula.InterruptStartTime; if (shifted < 0) shifted += _ula.FrameCycleLength; shifted %= _ula.FrameCycleLength; @@ -482,46 +484,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum Renderer[t].ContentionValue = conPattern[pixByte]; } - - // calculate floating bus values - for (int t = 0; t < _ula.FrameCycleLength; t++) - { - int shifted = (t + 10) + _ula.InterruptStartTime; - if (shifted < 0) - shifted += _ula.FrameCycleLength; - shifted %= _ula.FrameCycleLength; - - Renderer[t].FloatingBusAddress = 0; - - int line = shifted / _ula.ScanlineTime; - int pix = shifted % _ula.ScanlineTime; - if (line < _ula.FirstPaperLine || line >= (_ula.FirstPaperLine + 192)) - { - Renderer[t].FloatingBusAddress = 0; - continue; - } - int scrPix = pix - _ula.FirstPaperTState; - if (scrPix < 0 || scrPix >= 128) - { - Renderer[t].FloatingBusAddress = 0; - continue; - } - - int pixByte = scrPix % 8; - int chunk = scrPix % 16; - - switch (chunk) - { - case 0: - case 2: - Renderer[t].FloatingBusAddress = CalculateByteAddress(scrPix, line); - break; - case 1: - case 3: - Renderer[t].FloatingBusAddress = CalculateAttributeAddress(scrPix, line); - break; - } - } } private ushort CalculateByteAddress(int x, int y) @@ -719,8 +681,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void ReadFloatingBus(int tstate, ref int result) { - int off = 0; - tstate += off; + tstate += FloatingBusOffset; if (tstate >= RenderingTable.Renderer.Length) tstate -= RenderingTable.Renderer.Length; if (tstate < 0) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs index 3e1aed6e24..92472c0e3b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -22,6 +22,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum MemoryContentionOffset = 5; PortContentionOffset = 5; + RenderTableOffset = 1; + FloatingBusOffset = 1; BorderLeftTime = 24; BorderRightTime = 24; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs index 90f505d1f2..2cd69dcaa7 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -22,6 +22,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum MemoryContentionOffset = 7; PortContentionOffset = 7; + RenderTableOffset = 1; + FloatingBusOffset = 1; BorderLeftTime = 24; BorderRightTime = 24; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs index 5af98f944a..96624fe1d5 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -16,12 +16,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3500000; FrameCycleLength = 69888; - InterruptStartTime = 31; + InterruptStartTime = 30; InterruptLength = 32; ScanlineTime = 224; - MemoryContentionOffset = 5; - PortContentionOffset = 5; + MemoryContentionOffset = 6; + PortContentionOffset = 6; + RenderTableOffset = 2; + FloatingBusOffset = 1; BorderLeftTime = 24; BorderRightTime = 24; From fd889250b31d4baeeed019321d8a3996d5c78e10 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 12:27:52 +0100 Subject: [PATCH 34/51] ZXHawk: 128k/+2 interrupt, ULA tables & contention tweaked --- .../Machine/ZXSpectrum128K/ZX128.Screen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs index 92472c0e3b..461baf266a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -16,13 +16,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3546900; FrameCycleLength = 70908; - InterruptStartTime = 32; + InterruptStartTime = 34; InterruptLength = 36; ScanlineTime = 228; - MemoryContentionOffset = 5; - PortContentionOffset = 5; - RenderTableOffset = 1; + MemoryContentionOffset = 6; + PortContentionOffset = 6; + RenderTableOffset = -4; FloatingBusOffset = 1; BorderLeftTime = 24; From 7ced9fdc6a5a218759ab6eb7dc22c154b316a54d Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 13:24:43 +0100 Subject: [PATCH 35/51] ZXHawk: 128k HAL10H8 chip crash emulation (INs to paging ports cause floating bus data being used to set the paging registers) --- .../Machine/ZXSpectrum128K/ZX128.Port.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index 9fe37c4c14..0596dce779 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -20,6 +20,25 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum int result = 0xFF; + // ports 0x3ffd & 0x7ffd + // traditionally thought to be write-only + if (port == 0x3ffd || port == 0x7ffd) + { + // https://faqwiki.zxnet.co.uk/wiki/ZX_Spectrum_128 + // HAL bugs + // Reads from port 0x7ffd cause a crash, as the 128's HAL10H8 chip does not distinguish between reads and writes to this port, + // resulting in a floating data bus being used to set the paging registers. + + // -asni (2018-06-08) - need this to pass the final portread tests from fusetest.tap + + // get the floating bus value + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + // use this to set the paging registers + WritePort(port, (byte)result); + // return the floating bus value + return (byte)result; + } + // check AY if (AYDevice.ReadPort(port, ref result)) return (byte)result; From faec0fb0e56f0b59ce5ad2fd2adaafe05c9d973c Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 13:43:40 +0100 Subject: [PATCH 36/51] ZXHawk: 128k/+2 High-port contention now reporting properly in fusetest --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 2 +- .../Machine/SpectrumBase.Memory.cs | 7 +++++++ .../Machine/ZXSpectrum128K/ZX128.Memory.cs | 18 ++++++++++++++++++ .../ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs | 18 ++++++++++++++++++ .../ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 18 ++++++++++++++++++ .../Machine/ZXSpectrum48K/ZX48.Memory.cs | 9 +++++++++ 6 files changed, 71 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 9708236f5d..9b8a822c15 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -297,7 +297,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case MachineType.ZXSpectrum128: case MachineType.ZXSpectrum128Plus2: - if ((lastPortAddr & 0xc000) == 0x4000) + if ((lastPortAddr & 0xc000) == 0x4000 || (lastPortAddr & 0xc000) == 0xc000 && _machine.ContendedBankPaged()) highByte407f = true; if (highByte407f) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs index 283f12cdb6..8bd72d3dcd 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs @@ -161,6 +161,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public abstract bool IsContended(ushort addr); + + /// + /// Returns TRUE if there is a contended bank paged in + /// + /// + public abstract bool ContendedBankPaged(); + #endregion #region Helper Methods diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs index 6be56554a3..6c48210679 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs @@ -232,6 +232,24 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return false; } + /// + /// Returns TRUE if there is a contended bank paged in + /// + /// + public override bool ContendedBankPaged() + { + switch (RAMPaged) + { + case 1: + case 3: + case 5: + case 7: + return true; + } + + return false; + } + /// /// ULA reads the memory at the specified address /// (No memory contention) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs index 3fec363a6e..73400dd86c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs @@ -425,6 +425,24 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return false; } + /// + /// Returns TRUE if there is a contended bank paged in + /// + /// + public override bool ContendedBankPaged() + { + switch (RAMPaged) + { + case 4: + case 5: + case 6: + case 7: + return true; + } + + return false; + } + /// /// ULA reads the memory at the specified address /// (No memory contention) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index 742a10adb3..87a9062912 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -426,6 +426,24 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return false; } + /// + /// Returns TRUE if there is a contended bank paged in + /// + /// + public override bool ContendedBankPaged() + { + switch (RAMPaged) + { + case 4: + case 5: + case 6: + case 7: + return true; + } + + return false; + } + /// /// ULA reads the memory at the specified address /// (No memory contention) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs index bd4c2564cd..932da8497b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs @@ -123,6 +123,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return false; } + /// + /// Returns TRUE if there is a contended bank paged in + /// + /// + public override bool ContendedBankPaged() + { + return false; + } + /// /// Sets up the ROM /// From a1d24400d042d9451e0583154c0226b6709fd540 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 14:39:23 +0100 Subject: [PATCH 37/51] ZXHawk: proper top border height --- .../Machine/ZXSpectrum128K/ZX128.Screen.cs | 2 +- .../ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs | 13 ++++++++++++- .../Machine/ZXSpectrum48K/ZX48.Screen.cs | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs index 461baf266a..54a0fe058f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // screen layout ScreenWidth = 256; ScreenHeight = 192; - BorderTopHeight = 48; + BorderTopHeight = 55; // 48; BorderBottomHeight = 56; BorderLeftWidth = 48; BorderRightWidth = 48; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs index 2cd69dcaa7..2611a7fd43 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -16,6 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3546900; FrameCycleLength = 70908; + /* InterruptStartTime = 31; InterruptLength = 32; ScanlineTime = 228; @@ -24,6 +25,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum PortContentionOffset = 7; RenderTableOffset = 1; FloatingBusOffset = 1; + */ + + InterruptStartTime = 33; + InterruptLength = 32; + ScanlineTime = 228; + + MemoryContentionOffset = 6; + PortContentionOffset = 6; + RenderTableOffset = -2; + FloatingBusOffset = 1; BorderLeftTime = 24; BorderRightTime = 24; @@ -37,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // screen layout ScreenWidth = 256; ScreenHeight = 192; - BorderTopHeight = 48; + BorderTopHeight = 55; BorderBottomHeight = 56; BorderLeftWidth = 48; BorderRightWidth = 48; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs index 96624fe1d5..119149c5c4 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -37,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // screen layout ScreenWidth = 256; ScreenHeight = 192; - BorderTopHeight = 48; + BorderTopHeight = 55;// 48; BorderBottomHeight = 56; BorderLeftWidth = 48; BorderRightWidth = 48; From 3ce546b774d27d32db733e6f86b9c4e3717bf927 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Fri, 8 Jun 2018 12:28:51 -0400 Subject: [PATCH 38/51] z80: Resond to interrupts at the corect time --- .../CPUs/Z80A/Interrupts.cs | 4 ++-- BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs | 2 +- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs index 9b1426505c..389fdf6e8f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -85,7 +85,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, 0, 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, 0, 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } // Interrupt mode 2 uses the I vector combined with a byte on the data bus @@ -112,7 +112,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { 0, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, W, 0 ,0 ,PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, W, 0 ,0 ,PCh, 0, 0, 0 }; } private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index 7d4271373b..8ca466d5e2 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -58,7 +58,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public const ushort WIO4 = 108; - public bool FlagI;/*, FlagI1, FlagI2, FlagI3, FlagI4, FlagI5, FlagI6;*/ + public bool FlagI, FlagI1, FlagI2, FlagI3, FlagI4, FlagI5, FlagI6; public bool FlagW; // wait flag, when set to true reads / writes will be delayed diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index 33c60fc97f..afd07e1979 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -159,13 +159,13 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // Execute instructions public void ExecuteOne() { - /*FlagI6 = FlagI; + //FlagI6 = FlagI5; FlagI5 = FlagI4; FlagI4 = FlagI3; FlagI3 = FlagI2; FlagI2 = FlagI1; FlagI1 = FlagI; - */ + bus_pntr++; switch (cur_instr[instr_pntr++]) { @@ -196,7 +196,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A NMICallback(); instr_pntr = 0; bus_pntr = 0; } - else if (iff1 && FlagI) + else if (iff1 && FlagI5) { iff1 = iff2 = false; EI_pending = 0; @@ -267,7 +267,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A NMICallback(); halted = false; } - else if (iff1 && FlagI) + else if (iff1 && FlagI5) { iff1 = iff2 = false; EI_pending = 0; @@ -670,12 +670,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A DEC16, PCl, PCh, DEC16, PCl, PCh, IDLE, - DEC16, B, ALU, + IDLE,//DEC16, B, ALU, WAIT, OP_F, OP}; - Regs[B] = (ushort)((Regs[B] + 1) & 0xFF); + //Regs[B] = (ushort)((Regs[B] + 1) & 0xFF); BUSRQ = new ushort[] { B, B, B, B, B, PCh, 0, 0, 0 }; @@ -770,6 +770,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A ser.Sync("instr_swap", ref instr_swap); ser.Sync("opcode", ref opcode); ser.Sync("FlagI", ref FlagI); + ser.Sync("FlagI1", ref FlagI1); + ser.Sync("FlagI2", ref FlagI2); + ser.Sync("FlagI3", ref FlagI3); + ser.Sync("FlagI4", ref FlagI4); + ser.Sync("FlagI5", ref FlagI5); + ser.Sync("FlagI6", ref FlagI6); ser.Sync("FlagW", ref FlagW); ser.Sync("NO Preifx", ref NO_prefix); From c47860fad7d4109294cc08823de934822214de78 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Fri, 8 Jun 2018 19:09:40 +0100 Subject: [PATCH 39/51] ZXHawk: 48k offsets updated for z80 interrupt response time change --- .../Computers/SinclairSpectrum/Machine/ULA.cs | 4 ++-- .../SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 0124f6721e..e875a09565 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -164,13 +164,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return; } - if (currentCycle < InterruptStartTime) + if (currentCycle <= InterruptStartTime) { // interrupt does not need to be raised yet return; } - if (currentCycle >= InterruptStartTime + InterruptLength) + if (currentCycle > InterruptStartTime + InterruptLength) { // interrupt should have already been raised and the cpu may or // may not have caught it. The time has passed so revoke the signal diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs index 119149c5c4..0a4c236d86 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -16,13 +16,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // timing ClockSpeed = 3500000; FrameCycleLength = 69888; - InterruptStartTime = 30; + InterruptStartTime = 33; InterruptLength = 32; ScanlineTime = 224; MemoryContentionOffset = 6; PortContentionOffset = 6; - RenderTableOffset = 2; + RenderTableOffset = -9; // 2; FloatingBusOffset = 1; BorderLeftTime = 24; From fbba7c25aed54efe1476278bf51ed805f483db70 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Mon, 11 Jun 2018 14:35:12 +0100 Subject: [PATCH 40/51] ZXHawk: New interrupt implementation --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 3 + .../SinclairSpectrum/Machine/SpectrumBase.cs | 22 ++-- .../Computers/SinclairSpectrum/Machine/ULA.cs | 117 +++++++++--------- .../Machine/ZXSpectrum128K/ZX128.Screen.cs | 26 ++-- .../ZX128Plus2a.Screen.cs | 35 ++---- .../Machine/ZXSpectrum48K/ZX48.Screen.cs | 28 ++--- 6 files changed, 104 insertions(+), 127 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 9b8a822c15..8838abe75e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -61,6 +61,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public void ExecuteCycle() { + // simulate the ULA clock cycle before the CPU cycle + _machine.ULADevice.CycleClock(TotalExecutedCycles); + // is the next CPU cycle causing a BUSRQ or IORQ? if (BUSRQ > 0) { diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index 3b5eaa6da9..58753c45e5 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -147,6 +147,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public virtual void ExecuteFrame(bool render, bool renderSound) { + ULADevice.FrameEnd = false; + ULADevice.ULACycleCounter = CurrentFrameCycle; + InputRead = false; _render = render; _renderSound = renderSound; @@ -164,15 +167,18 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum PollInput(); - while (CurrentFrameCycle < ULADevice.FrameLength) + for (;;) { - ULADevice.CheckForInterrupt(CurrentFrameCycle); - + // run the CPU Monitor cycle CPUMon.ExecuteCycle(); // cycle the tape device if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) TapeDevice.TapeCycle(); + + // has frame end been reached? + if (ULADevice.FrameEnd) + break; } OverFlow = (int)CurrentFrameCycle - ULADevice.FrameLength; @@ -190,9 +196,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum AYDevice.EndFrame(); FrameCount++; - - // setup for next frame - ULADevice.ResetInterrupt(); if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded) TapeDevice.EndFrame(); @@ -202,8 +205,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // is this a lag frame? Spectrum.IsLagFrame = !InputRead; - // FDC debug - + // FDC debug if (UPDDiskDevice != null && UPDDiskDevice.writeDebug) { // only write UPD log every second @@ -222,7 +224,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public virtual void HardReset() { - ULADevice.ResetInterrupt(); + //ULADevice.ResetInterrupt(); ROMPaged = 0; SpecialPagingMode = false; RAMPaged = 0; @@ -274,7 +276,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public virtual void SoftReset() { - ULADevice.ResetInterrupt(); + //ULADevice.ResetInterrupt(); ROMPaged = 0; SpecialPagingMode = false; RAMPaged = 0; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index e875a09565..2e9ff98b8c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -89,14 +89,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public int InterruptLength; /// - /// Arbitrary offset into the contention array (for memory ops) - /// - public int MemoryContentionOffset; - - /// - /// Arbitrary offset into the contention array (for port ops) - /// - public int PortContentionOffset; + /// Contention offset + /// + public int ContentionOffset; /// /// Arbitrary offset for render table generation @@ -137,60 +132,58 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// protected bool InterruptRaised; - /// - /// Signs that the interrupt signal has been revoked - /// - protected bool InterruptRevoked; + public long ULACycleCounter; + public long LastULATick; + public bool FrameEnd; /// - /// Resets the interrupt - this should happen every frame in order to raise - /// the VBLANK interrupt in the proceding frame - /// - public virtual void ResetInterrupt() - { - InterruptRaised = false; - InterruptRevoked = false; - } - - /// - /// Generates an interrupt in the current phase if needed + /// Cycles the ULA clock + /// Handles interrupt generation /// /// - public virtual void CheckForInterrupt(long currentCycle) + public virtual void CycleClock(long totalCycles) { - if (InterruptRevoked) + // has more than one cycle past since this last ran + // (this can be true if contention has taken place) + var ticksToProcess = totalCycles - LastULATick; + + // store the current cycle + LastULATick = totalCycles; + + // process the cycles past as well as the upcoming one + for (int i = 0; i < ticksToProcess; i++) { - // interrupt has already been handled - return; - } + ULACycleCounter++; - if (currentCycle <= InterruptStartTime) - { - // interrupt does not need to be raised yet - return; - } - - if (currentCycle > InterruptStartTime + InterruptLength) - { - // interrupt should have already been raised and the cpu may or - // may not have caught it. The time has passed so revoke the signal - InterruptRevoked = true; - _machine.CPU.FlagI = false; - return; - } - - if (InterruptRaised) - { - // INT is raised but not yet revoked - // CPU has NOT handled it yet - return; - } - - // Raise the interrupt - InterruptRaised = true; - _machine.CPU.FlagI = true; - - CalcFlashCounter(); + if (InterruptRaised) + { + // /INT pin is currently being held low + if (ULACycleCounter < InterruptLength + InterruptStartTime) + { + // ULA should still hold the /INT pin low + _machine.CPU.FlagI = true; + } + else + { + // its time (or past time) to stop holding the /INT pin low + _machine.CPU.FlagI = false; + InterruptRaised = false; + } + } + else + { + // interrupt is currently not raised + if (ULACycleCounter == FrameLength + InterruptStartTime) + { + // time to raise the interrupt + InterruptRaised = true; + _machine.CPU.FlagI = true; + FrameEnd = true; + ULACycleCounter = InterruptStartTime; + CalcFlashCounter(); + } + } + } } /// @@ -329,7 +322,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { for (var t = 0; t < _ula.FrameCycleLength; t++) { - var tStateScreen = t + _ula.RenderTableOffset + _ula.InterruptStartTime; + var tStateScreen = t + _ula.RenderTableOffset;// + _ula.InterruptStartTime; if (tStateScreen < 0) tStateScreen += _ula.FrameCycleLength; @@ -460,7 +453,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // calculate contention values for (int t = 0; t < _ula.FrameCycleLength; t++) { - int shifted = t + _ula.RenderTableOffset + _ula.InterruptStartTime; + int shifted = t + _ula.RenderTableOffset + _ula.ContentionOffset; // _ula.InterruptStartTime; if (shifted < 0) shifted += _ula.FrameCycleLength; shifted %= _ula.FrameCycleLength; @@ -747,7 +740,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetContentionValue(int tstate) { - tstate += MemoryContentionOffset; + //tstate += MemoryContentionOffset; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; @@ -763,7 +756,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public int GetPortContentionValue(int tstate) { - tstate += PortContentionOffset; + //tstate += PortContentionOffset; if (tstate >= FrameCycleLength) tstate -= FrameCycleLength; @@ -994,8 +987,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum ser.BeginSection("ULA"); if (ScreenBuffer != null) ser.Sync("ScreenBuffer", ref ScreenBuffer, false); - ser.Sync("FrameLength", ref FrameCycleLength); - ser.Sync("ClockSpeed", ref ClockSpeed); ser.Sync("BorderColor", ref BorderColor); ser.Sync("LastTState", ref LastTState); ser.Sync("flashOn", ref flashOn); @@ -1010,6 +1001,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum ser.Sync("flash", ref flash); ser.Sync("palPaper", ref palPaper); ser.Sync("palInk", ref palInk); + + ser.Sync("LastULATick", ref LastULATick); + ser.Sync("ULACycleCounter", ref ULACycleCounter); + ser.Sync("FrameEnd", ref FrameEnd); ser.EndSection(); } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs index 54a0fe058f..06b1d7d9ba 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Screen.cs @@ -13,32 +13,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public Screen128(SpectrumBase machine) : base(machine) { + // interrupt + InterruptStartTime = 3; + InterruptLength = 36; + // offsets + RenderTableOffset = 58; + ContentionOffset = 6; + FloatingBusOffset = 1; // timing ClockSpeed = 3546900; FrameCycleLength = 70908; - InterruptStartTime = 34; - InterruptLength = 36; ScanlineTime = 228; - - MemoryContentionOffset = 6; - PortContentionOffset = 6; - RenderTableOffset = -4; - FloatingBusOffset = 1; - BorderLeftTime = 24; BorderRightTime = 24; - FirstPaperLine = 63; FirstPaperTState = 64; - - Border4T = true; - Border4TStage = 2; - // screen layout + Border4T = true; + Border4TStage = 2; ScreenWidth = 256; ScreenHeight = 192; - BorderTopHeight = 55; // 48; - BorderBottomHeight = 56; + BorderTopHeight = 48; // 55; // 48; + BorderBottomHeight = 48; // 56; BorderLeftWidth = 48; BorderRightWidth = 48; ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs index 2611a7fd43..a95d06d8ce 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -13,43 +13,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public Screen128Plus2a(SpectrumBase machine) : base(machine) { + // interrupt + InterruptStartTime = 0; + InterruptLength = 32; + // offsets + RenderTableOffset = 58; + ContentionOffset = 9; + FloatingBusOffset = 1; // timing ClockSpeed = 3546900; FrameCycleLength = 70908; - /* - InterruptStartTime = 31; - InterruptLength = 32; ScanlineTime = 228; - - MemoryContentionOffset = 7; - PortContentionOffset = 7; - RenderTableOffset = 1; - FloatingBusOffset = 1; - */ - - InterruptStartTime = 33; - InterruptLength = 32; - ScanlineTime = 228; - - MemoryContentionOffset = 6; - PortContentionOffset = 6; - RenderTableOffset = -2; - FloatingBusOffset = 1; - BorderLeftTime = 24; BorderRightTime = 24; - FirstPaperLine = 63; FirstPaperTState = 64; - + // screen layout Border4T = true; Border4TStage = 2; - - // screen layout ScreenWidth = 256; ScreenHeight = 192; - BorderTopHeight = 55; - BorderBottomHeight = 56; + BorderTopHeight = 48;// 55; + BorderBottomHeight = 48; // 56; BorderLeftWidth = 48; BorderRightWidth = 48; ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs index 0a4c236d86..d572f44e37 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Screen.cs @@ -13,32 +13,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public Screen48(SpectrumBase machine) : base(machine) { - // timing - ClockSpeed = 3500000; - FrameCycleLength = 69888; - InterruptStartTime = 33; + // interrupt + InterruptStartTime = 3; InterruptLength = 32; + // offsets + RenderTableOffset = 56; + ContentionOffset = 6; + FloatingBusOffset = 1; + // timing + ClockSpeed = 3500000; + FrameCycleLength = 69888; ScanlineTime = 224; - - MemoryContentionOffset = 6; - PortContentionOffset = 6; - RenderTableOffset = -9; // 2; - FloatingBusOffset = 1; - BorderLeftTime = 24; BorderRightTime = 24; - FirstPaperLine = 64; FirstPaperTState = 64; - + // screen layout Border4T = true; Border4TStage = 0; - - // screen layout ScreenWidth = 256; ScreenHeight = 192; - BorderTopHeight = 55;// 48; - BorderBottomHeight = 56; + BorderTopHeight = 48;// 55;// 48; + BorderBottomHeight = 48;// 56; BorderLeftWidth = 48; BorderRightWidth = 48; ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth; From 13a9c5bdc482ceb7992b725a3714efd2663b69bb Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 12 Jun 2018 10:16:43 +0100 Subject: [PATCH 41/51] ZXHawk: Added POKE memory menu option --- .../BizHawk.Client.EmuHawk.csproj | 9 + BizHawk.Client.EmuHawk/MainForm.Designer.cs | 24 +- BizHawk.Client.EmuHawk/MainForm.Events.cs | 5 + BizHawk.Client.EmuHawk/MainForm.cs | 1 + .../ZXSpectrumPokeMemory.Designer.cs | 165 +++++ .../config/ZXSpectrum/ZXSpectrumPokeMemory.cs | 39 ++ .../ZXSpectrum/ZXSpectrumPokeMemory.resx | 624 ++++++++++++++++++ .../SinclairSpectrum/ZXSpectrum.Util.cs | 254 +------ 8 files changed, 873 insertions(+), 248 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.Designer.cs create mode 100644 BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs create mode 100644 BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.resx diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 5b51df2137..a5b9eaf9d6 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -509,6 +509,12 @@ ZXSpectrumAudioSettings.cs + + Form + + + ZXSpectrumPokeMemory.cs + Form @@ -1431,6 +1437,9 @@ ZXSpectrumAudioSettings.cs + + ZXSpectrumPokeMemory.cs + ZXSpectrumNonSyncSettings.cs diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 57d6c30767..d2d28f2b94 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -384,6 +384,7 @@ this.zXSpectrumToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ZXSpectrumCoreEmulationSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ZXSpectrumControllerConfigurationMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ZXSpectrumAudioSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ZXSpectrumNonSyncSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainStatusBar = new StatusStripEx(); @@ -457,7 +458,7 @@ this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timerMouseIdle = new System.Windows.Forms.Timer(this.components); - this.ZXSpectrumAudioSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ZXSpectrumPokeMemoryMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); @@ -3401,7 +3402,8 @@ this.ZXSpectrumCoreEmulationSettingsMenuItem, this.ZXSpectrumControllerConfigurationMenuItem, this.ZXSpectrumAudioSettingsMenuItem, - this.ZXSpectrumNonSyncSettingsMenuItem}); + this.ZXSpectrumNonSyncSettingsMenuItem, + this.ZXSpectrumPokeMemoryMenuItem}); this.zXSpectrumToolStripMenuItem.Name = "zXSpectrumToolStripMenuItem"; this.zXSpectrumToolStripMenuItem.Size = new System.Drawing.Size(87, 19); this.zXSpectrumToolStripMenuItem.Text = "ZX Spectrum"; @@ -3421,6 +3423,13 @@ this.ZXSpectrumControllerConfigurationMenuItem.Text = "Joystick Configuration"; this.ZXSpectrumControllerConfigurationMenuItem.Click += new System.EventHandler(this.ZXSpectrumControllerConfigurationMenuItem_Click); // + // ZXSpectrumAudioSettingsMenuItem + // + this.ZXSpectrumAudioSettingsMenuItem.Name = "ZXSpectrumAudioSettingsMenuItem"; + this.ZXSpectrumAudioSettingsMenuItem.Size = new System.Drawing.Size(201, 22); + this.ZXSpectrumAudioSettingsMenuItem.Text = "Audio Settings"; + this.ZXSpectrumAudioSettingsMenuItem.Click += new System.EventHandler(this.ZXSpectrumAudioSettingsMenuItem_Click); + // // ZXSpectrumNonSyncSettingsMenuItem // this.ZXSpectrumNonSyncSettingsMenuItem.Name = "ZXSpectrumNonSyncSettingsMenuItem"; @@ -4054,12 +4063,12 @@ this.timerMouseIdle.Interval = 2000; this.timerMouseIdle.Tick += new System.EventHandler(this.TimerMouseIdle_Tick); // - // ZXSpectrumAudioSettingsMenuItem + // ZXSpectrumPokeMemoryMenuItem // - this.ZXSpectrumAudioSettingsMenuItem.Name = "ZXSpectrumAudioSettingsMenuItem"; - this.ZXSpectrumAudioSettingsMenuItem.Size = new System.Drawing.Size(201, 22); - this.ZXSpectrumAudioSettingsMenuItem.Text = "Audio Settings"; - this.ZXSpectrumAudioSettingsMenuItem.Click += new System.EventHandler(this.ZXSpectrumAudioSettingsMenuItem_Click); + this.ZXSpectrumPokeMemoryMenuItem.Name = "ZXSpectrumPokeMemoryMenuItem"; + this.ZXSpectrumPokeMemoryMenuItem.Size = new System.Drawing.Size(201, 22); + this.ZXSpectrumPokeMemoryMenuItem.Text = "POKE Memory"; + this.ZXSpectrumPokeMemoryMenuItem.Click += new System.EventHandler(this.ZXSpectrumPokeMemoryMenuItem_Click); // // MainForm // @@ -4530,5 +4539,6 @@ private System.Windows.Forms.ToolStripMenuItem ZXSpectrumCoreEmulationSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem ZXSpectrumNonSyncSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem ZXSpectrumAudioSettingsMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumPokeMemoryMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index ba02157085..3cbf90c572 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -2487,6 +2487,11 @@ namespace BizHawk.Client.EmuHawk new ZXSpectrumAudioSettings().ShowDialog(); } + private void ZXSpectrumPokeMemoryMenuItem_Click(object sender, EventArgs e) + { + new ZXSpectrumPokeMemory().ShowDialog(); + } + #endregion #region Help diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 25a6409e01..ff19f07096 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -4298,6 +4298,7 @@ namespace BizHawk.Client.EmuHawk { GenericCoreConfig.DoDialog(this, "PC-FX Settings"); } + private bool Rewind(ref bool runFrame, long currentTimestamp, out bool returnToRecording) { diff --git a/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.Designer.cs b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.Designer.cs new file mode 100644 index 0000000000..c2f10b196f --- /dev/null +++ b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.Designer.cs @@ -0,0 +1,165 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class ZXSpectrumPokeMemory + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ZXSpectrumPokeMemory)); + this.OkBtn = new System.Windows.Forms.Button(); + this.CancelBtn = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.numericUpDownAddress = new System.Windows.Forms.NumericUpDown(); + this.label3 = new System.Windows.Forms.Label(); + this.numericUpDownByte = new System.Windows.Forms.NumericUpDown(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownAddress)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownByte)).BeginInit(); + this.SuspendLayout(); + // + // OkBtn + // + this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkBtn.Location = new System.Drawing.Point(150, 109); + this.OkBtn.Name = "OkBtn"; + this.OkBtn.Size = new System.Drawing.Size(60, 23); + this.OkBtn.TabIndex = 3; + this.OkBtn.Text = "&OK"; + this.OkBtn.UseVisualStyleBackColor = true; + this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click); + // + // CancelBtn + // + this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelBtn.Location = new System.Drawing.Point(216, 109); + this.CancelBtn.Name = "CancelBtn"; + this.CancelBtn.Size = new System.Drawing.Size(60, 23); + this.CancelBtn.TabIndex = 4; + this.CancelBtn.Text = "&Cancel"; + this.CancelBtn.UseVisualStyleBackColor = true; + this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 14); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(273, 13); + this.label1.TabIndex = 17; + this.label1.Text = "Enter an address to POKE along with a single byte value"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 52); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(93, 13); + this.label4.TabIndex = 27; + this.label4.Text = "Address (0-65535)"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 27); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(266, 13); + this.label2.TabIndex = 29; + this.label2.Text = "(Address values that target ROM space will be ignored)"; + // + // numericUpDownAddress + // + this.numericUpDownAddress.Location = new System.Drawing.Point(15, 69); + this.numericUpDownAddress.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numericUpDownAddress.Name = "numericUpDownAddress"; + this.numericUpDownAddress.Size = new System.Drawing.Size(90, 20); + this.numericUpDownAddress.TabIndex = 30; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(123, 52); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(70, 13); + this.label3.TabIndex = 31; + this.label3.Text = "Value (0-255)"; + // + // numericUpDownByte + // + this.numericUpDownByte.Location = new System.Drawing.Point(126, 68); + this.numericUpDownByte.Maximum = new decimal(new int[] { + 255, + 0, + 0, + 0}); + this.numericUpDownByte.Name = "numericUpDownByte"; + this.numericUpDownByte.Size = new System.Drawing.Size(67, 20); + this.numericUpDownByte.TabIndex = 32; + // + // ZXSpectrumPokeMemory + // + this.AcceptButton = this.OkBtn; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelBtn; + this.ClientSize = new System.Drawing.Size(288, 144); + this.Controls.Add(this.numericUpDownByte); + this.Controls.Add(this.label3); + this.Controls.Add(this.numericUpDownAddress); + this.Controls.Add(this.label2); + this.Controls.Add(this.label4); + this.Controls.Add(this.label1); + this.Controls.Add(this.CancelBtn); + this.Controls.Add(this.OkBtn); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "ZXSpectrumPokeMemory"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Poke Memory"; + + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownAddress)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownByte)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button OkBtn; + private System.Windows.Forms.Button CancelBtn; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.NumericUpDown numericUpDownAddress; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.NumericUpDown numericUpDownByte; + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs new file mode 100644 index 0000000000..de0c799f24 --- /dev/null +++ b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using System.Windows.Forms; + +using BizHawk.Client.Common; +using BizHawk.Emulation.Cores.Computers.SinclairSpectrum; +using System.Text; + +namespace BizHawk.Client.EmuHawk +{ + public partial class ZXSpectrumPokeMemory : Form + { + private ZXSpectrum.ZXSpectrumSettings _settings; + + public ZXSpectrumPokeMemory() + { + InitializeComponent(); + } + + private void OkBtn_Click(object sender, EventArgs e) + { + var speccy = (ZXSpectrum)Global.Emulator; + var addr = (ushort)numericUpDownAddress.Value; + var val = (byte)numericUpDownByte.Value; + + speccy.PokeMemory(addr, val); + + DialogResult = DialogResult.OK; + Close(); + } + + private void CancelBtn_Click(object sender, EventArgs e) + { + GlobalWin.OSD.AddMessage("POKE memory aborted"); + DialogResult = DialogResult.Cancel; + Close(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.resx b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.resx new file mode 100644 index 0000000000..ca821b54f8 --- /dev/null +++ b/BizHawk.Client.EmuHawk/config/ZXSpectrum/ZXSpectrumPokeMemory.resx @@ -0,0 +1,624 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAwAMDAQAAAABABoBgAAxgAAACAgEAAAAAQA6AIAAC4HAAAYGBAAAAAEAOgBAAAWCgAAEBAQAAAA + BAAoAQAA/gsAADAwAAAAAAgAqA4AACYNAAAgIAAAAAAIAKgIAADOGwAAGBgAAAAACADIBgAAdiQAABAQ + AAAAAAgAaAUAAD4rAAAwMAAAAAAgAKglAACmMAAAICAAAAAAIACoEAAATlYAABgYAAAAACAAiAkAAPZm + AAAQEAAAAAAgAGgEAAB+cAAAKAAAADAAAABgAAAAAQAEAAAAAACABAAAAAAAAAAAAAAQAAAAEAAAAAAA + AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP// + /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAHR3AAAAAAAAAAAAAAAAAAAAAAAAAAAAdHdEcAAAAAAAAAAAAAAAAA + AAAAAAAAAHd0d3QAAAAAAAAAAAAAAAAAAAAAAAAAAEd8d3UAAAAAAAAAAAAAAAAAAAAAAAAAB3yHfHZw + AAAAAAAAAAAAAAAAAAAAAAAAd3fIyHVwAAAAAAAAAAAAAAAAAAAAAAAAfHh3jIxwAAAAAAAAAAAAAAAA + AAAAAAAHd8jIyHdgAAAAAAAAAAAAAAAAAAAAAAAHd4yHfIdAAAAAAAAAAAAAAAAAAAAAAAAHyMjIyMhQ + AAAAAAAAAAAAAAAAAAAAAAB3d3eMh4dgAAAAAAAAAAAAAAAAAAAAAAB8jIyIfIdQAAAAAAAAAAAAAAAA + AAAAAAB3h4jIiMh3AAAAAAAAAAAAAAAAAAAAAAB8jIeHeIjHAAAAAAAAAAAAAAAAAAAAAAeIiHh4eMiE + AAAAAAAAAAAAB0dHcAAAAAd8h4eIiIiHcAAAAAAAAAB0d3d3RwAAAAeIeIiIiIh3RwAAAAAAAHR3d8h3 + dAAAAAfIh4iIiHiIx0cAAAAAdHh3eIeHhwAAAAeHiIiIiIiId3R3dHR0eHd4h4eHhAAAAAd4eIiIiIiH + x3d2d3eId4iIiIiIhwAAAAd4eIiI+IiIh3d3eHh3iIiIiIeHwAAAAAfIjHeIiIiIyIeHh4iIiIiIiIiI + cAAAAAeIQ0R3h3iIiMiIiIiIiIiIiIiEAAAAAAfIR3d3d0iIiIh4iIeIiIiIiHhAAAAAAAB4d3d3SHiI + h4fTiIi3iIiIeIwAAAAAAAB3h4d3eIeIiHiJiIuIiIh4jHAAAAAAAAAHyId3h3h4iIh4iIiIiIiHeAAA + AAAAAAAAB8iMiMjIiIiIh4h3aMjHAAAAAAAAAAAAAAdYyIeIiIiMjId6d4eAAAAAAAAAAAAAAAAHdsjH + eIeH6MiId3AAAAAAAAAAAAAAAIiIh4V8jIh4eIfHcAAAAAAAAAAAAACIiIh3AAAHd3h3fHcAAAAAAAAA + AAAAAAiIjHgAAAAAAHx8eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA//////// + AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A + H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP//// + AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA + AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/ + AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP// + /////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC + AAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/ + AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAAAAAAAAAAAAA + AAd0dAAAAAAAAAAAAAAAAAB3x3cAAAAAAAAAAAAAAAAAd3fHcAAAAAAAAAAAAAAAB3yMh3AAAAAAAAAA + AAAAAAfIeMdwAAAAAAAAAAAAAAAHjIyHQAAAAAAAAAAAAAAAfId4yHAAAAAAAAAAAAAAAHjIyIdQAAAA + AAAAAAAAAAB3iId4YAAAAAAAAAdwAAAAjIiIiIUAAAAAAHd3dAAAB4iIiHh8cAAAAHd3x4dwAAd4iIiI + h3Z3d3R3yIh4cAAHh4iIiIfHd3d4iIiIh3AAB3jHiIiIiHeHiIiIiIwAAAh3dXh4iMiIiIiIiIhwAAAA + yGd0d4iIeIi4iIiMAAAAAIeHd4iIh32IiIiIcAAAAAAAd4jIyIiIiHeHyAAAAAAAAAB3h4iIh8h3dwAA + AAAAAAAIh8fIh4eIaAAAAAAAAACIiHAAB8jIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////// + ////////////////////n////g////wP///8B///+Af///gH///4B///8Af///AH///wB//n8AP/A+AB + /AHgAAAB4AAAAeAAAAPgAAAH8AAAD/AAAB/8AAA//wAA//4AA//weA////////////////////////// + //8oAAAAGAAAADAAAAABAAQAAAAAACABAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAA + AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRwAAAAAAAAAAAAB3dAAAAAAAAAAAAA + d8dwAAAAAAAAAAAAfId3AAAAAAAAAAAHeMjHAAAAAAAAAAAHyHh3AAAAAAAAAAAHh3eEAAAAAAAAAAAI + yIiHAAAAAHd2cAAIiIiIQAAAd3d4UACHiIiId3d3eHiIcACHh4iIyHeHiIiIcAAIR3d4iIiIiIiMAAAH + d3eIh3iIiIhwAAAAeMh4iIiHiMAAAAAAAHfIiMh4aAAAAAAAiIgHyIfIAAAAAAAIgAAAAIAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD8f/8A+H//APB/ + /wDwP/8A4D//AOA//wDgP/8A4D/BAOAfAQDAAAEAwAABAOAAAwDgAAcA8AAfAPwAPwDwgP8A5/f/AP// + /wD///8A////ACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA + AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAd1AAAAAAAAB8cAAAAAAAB4eAAAAAAAAHyMgAAAAAAAiIhwAAAHcACI + iHcAd3hwAIz4jIeIiIAAd3eIiIiIAACHeIiIiHAAAACMeMh4AAAAiAAIgAAAAAAAAAAAAAAAAAAAAAAA + AAD//wAA//8AAP//AADj/wAA4/8AAMP/AADB/wAAwfkAAMDBAADAAQAAwAMAAMAHAADwDwAAzn8AAP// + AAD//wAAKAAAADAAAABgAAAAAQAIAAAAAAAACQAAAAAAAAAAAAAAAQAAAAEAAAAAAAA9OzsAZD8/AGg8 + PABtPj4AQkNDAEZIRwBWQkIAV0REAF5AQABbRkYAVklJAFxPTwBTU1MAXFJSAF5ZWQBkQEAAYUREAGZF + RQBqQkEAYEtLAGNPTwBwQUEAfUZGAHJKSgB2SUkAfU9PAGBRUQBgVFQAZlZWAGZYWABqWVkAclZWAHpU + VAB9W1oAbmJiAGtoaABtaWkAcWdnAHdnZwB8Y2MAe2pqAHJxcQB+dHQAd3l5AHl6egCGT08AiU9PAIFP + UACGU1MAjVFRAIlWVgCMV1cAg1xbAIxaWQCQUlIAlVJSAJFXVgCXVVUAmVVVAJZaWQCSXV0AlV9eAJpZ + WgCeW1sAml5eAKBZWgCgXFwAql9fAIRmZQCIZWQAhWtrAI5ragCTYmEAnGBhAJ9kYwCaZmYAk25uAJ1s + awCFdHQAiXd3AIt+fgCWd3cAmHR0AJV5eQCbfHwAo2JhAKZhYQChZWUApGVkAKplZACsZGQAqmhnAKZr + agCnbGsAqmloAKlubQCsbW0AtGZnALhsbACxb3AAv29wAKVxcACrc3IAr35+ALN0cwC5c3MAvXBxALR4 + dgC1fHsAunt6AMNtbgDGb3AAw3FyAMZwcQDGdXUAyHR1AMp3eADBeXkAxnt7AMB/fgDLensANLBSAEWf + TgBBtFwAPMdnADHkdgDciiIAvoF/AISrdwDln0sA35lhAN2XfADgmmEA8LdlAO61cAArWPIALWT+AEh5 + +gDOf4AAfoCAAHiA1ABZv9wAZrnUAGK+2ABxnv4Ad6P/ADPX/QBw0OcAW+D7AIKEgwCPgoIAjI2NAJuC + ggCUiIgAmYqKAJGSkgCjhIQAqoKCAKKLiwC+hIMAsoqKALaSgQCum5sAsZubALqqlQCdgr4Ar6ytALGh + oAC6pKQAwoSDAMyBggDGiIYAyYiHAMWMigDMjIoA0ISFANKHiADUjIwA2Y6NAMCUjQDIk44A0JCPANaP + kADHlZQAzpSSAMScmwDUkpIA2ZSVANWYlgDampcA2ZeYANWcnADam5sA4p2cAMChjwDeoJ4A5aCFAOaj + jQDlpJoA2p6hAMOkowDOoaEAy62tANegoADdoqEA2aGpANGsrwDdq6kAwbG4ANGysQDdtLQA2ri3AOGk + owDjqKYA66ylAOGnqADjq6oA6a2rAOOwrwDssK4A5K+wAOaztADttLIA57i2AO24tgDmurgA6rq6APC1 + swDyuLYA9Ly5APi+uwD1wL0A+cC9AKKMwACkk8QAqprMALSayACptsEAlaDkAOy/wACRxtQAgOv9AJnr + 9wDEwsoA5sbGAOzCwgDuyMcA7MzMAPPEwgDxy8oA9dPTAPja2gAAAAAAAAAAAP///wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAoIJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAACYXODs4BCUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + KTNDQ0M7OAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALllbYmJZQBcAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYYWNwcHBwWy8mAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFLanBwcHBwYz0eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABpqcHBwcHBwZVkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl11w + cHBwcHBwcGcSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIXdwcHBwcHBwcGkSAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPXBwcHBwcHBwd2wYAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAACXbnBwdXB5dXl0eW4hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAid3R5eXl5eXl5q6wzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9eXV5 + i7CxsbGxsblLKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABndYuwsbm8uby5vMFnHgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJt3q7G3vMHB1cLBwdWuEgAAAAAAAAAAAAAAAAAA + AAAAAAAeEhMSCiUAAAAAAAAAAEexsbm/1dXZ2dnZ1da5ZgwAAAAAAAAAAAAAAAAAAAAjEjNZaW5qXRMl + AAAAAAAAADW5s7/V2N7i4uLi3dzZrQQPAAAAAAAAAAAAAAAAHxhZbm5uaWltd6ASAAAAAAAAAEmzvMLZ + 3uP29/fw4uTkuUAWCy0AAAAAAAAAAB4YYXd3gG13vbm5vb8zAAAAAAAAAE6xwdXd4/b6+/r38OTl1Vlc + OAMIFAweFBQSM2mtrYB3vdXT0NXExNU1AAAAAAAAAE65wtXe8Pr7/Pz79+fn1WphZ25pXV1mbHetrXd3 + tdXT4vXw49nZ3NYgAAAAAAAAAEu3wdje9vv7/Pz79+fn34B3d2xtoHeud66uudXT4vD39/Dj49zk5G0A + AAAAAAAAAD2xwcwoH0/L/Pukyenp5K27u7m5uczM0Nve4vb3+vr56OPl5eXl1igAAAAAAAAAADWxwQgB + BQYNmveZK/Dp6cG/wcTV2eP3+vr6+/r6+ejm5ufn5+nkIgAAAAAAAAAAAJmruR4sjC2WLFCdDd3p6dXW + 1tXI3vn67pCO9Ojp6efo5+fm59wiAAAAAAAAAAAAAABLsZ0FmC0qKgHMRcjp6dzc1Y2KiO3RlfKTj+np + 5ubm5eXk1SIAAAAAAAAAAAAAAACdab/Lp5aWnEfV1cHm6ebk6pGSiabZ8fOU0uXl5eTk3NyuRQAAAAAA + AAAAAAAAAAAAn0ux0KFTaMHBv7nC6efp3Ovv7OTm3OPl3Nzc3NfW1U6fAAAAAAAAAAAAAAAAAAAAAABF + Wa25t7yxs7Gw5+fn5Obk18XG3NyBfHvD1cSgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAFUzarGwsHl5sefn + 39zEgoZ/hL19fnqirj2jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj09ZXV0cLzn3NXChYeDub+1pbQ9 + VQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0rXj+rpInTBDcHCz5NW/ucG5u7GAM1QAAAAAAAAAAAAAAAAA + AAAAAAAAAADLytDi9tOemQAAAAAAUy9EecLEsa1uPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPj11Mme + VakAAAAAAAAAAAAATS84M0akAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA//////// + AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A + H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP//// + AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA + AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/ + AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP// + /////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAgAAAAAAAAE + AAAAAAAAAAAAAAABAAAAAQAAAAAAAFFNTQBRUlIAU1RUAGJHRwBiT08Aa0lIAGJTUwBrVlYAYllZAGZc + XABpWloAb1xbAHNTUwB7V1YAc1hXAHFbWwBkZWUAaWFhAG5kZABpamkAcGFhAHlubgB2cHAAf3V1AH55 + eQB8fX0AgUpKAI1PTwCLWFcAhlhYAI9ZWQCKXFsAm1ZWAJJZWQCWWVgAmlpbAJtcWwCiXFwAl2BfAIBg + YACAZ2YAgG9vAI9oaACWZWQAmGBhAJ5kZACcaWoAmm9vAIV0dACNcHAAiXZ2AIB8fACac3IAm3V0AJ51 + dQCZfHwAnHx8AKNmZgCnZmYAqmJiAK5jYwCvb24AtWVmALBtbgC5bW0AvmxtAKx+fQCxcnIAtHBwALZz + dACydXQAtnd2ALlwcAC5dnYAt3p5ALh5eAC8fHsAun18ALx+fQDGb3AAxnBxAMdzdADAd3YAyHJzAMlz + dADJdXYAynd4AMd/fwDMe3wAzXx9AHunbwBhvHIAYsN4ANuLOwC2hn4A4Zt5APC3ZABte9sAX47+AHWM + 5QAl0foAY+P8AIeDgwCFhoYAioSEAJOIiACWi4sAmpKRAKGCgQCmhYUAqYGBAKuDhACniooApYyMAKiO + jQCyhYMAvoWEALeNjQCrj5AAr5eXALSVlAC9lJMAmbCEAK6RugDBgYAAwoSCAMWDhADChoQAxYeFAM6A + gQDFiIYAxoqIAMqIiQDMi4oAy4yKAMiPjQDPj44A0ISFANKJigDUi4wA04+NANWNjgDKkY8A0JCOANud + iQDWj5AAzJSTAM2XlgDGm5oA1pGSANOUkgDVl5EA1pOUANiVlgDYmJUA2ZeYANKenADbmpsA3pmYANuc + mgDbn5wA1aacAN6gngDqqZoA3Z+gAMyjowDCra0AxqysAMqpqQDboaAA3qKiAN6logDbp6UA3aWkANer + qgDWsbMA0rW0ANe0tADfs7IA4aSiAOGlpQDkp6UA46imAOWopgDsraIA6qimAOGoqADhrqwA6a2rAOqv + rADpsK4A7LGuAOGzswDlsbEA7bKxAO+1sgDotrYA5rm3AO+4twDot7sA6bq5AOu9uwDrv70A8bazAPG2 + tADxuLUA9Lm2APC9uwD2vboA9L+9APi+uwD4v7wA8sC+APXAvgD5wL0AkILJAKqXzACsu8cAqr/LALLV + 3QDawMIA48XFAOvDwQDswMAA7cTDAO/ExQDgxsgA8cbEAPTGxADwyskA9MvJAPLNzQD21dYA+NjZAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAMEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHCEcBQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAayU9PSYbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdQlBSQiJpAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAM0pSUlJQPRcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnUlJSUlJGFQAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAFJSUlJSUkoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzUlJSWVJZfxAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5XWYqKioqGDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASoqMkpqa + mqAsAAAAAAAAAAAAAAAAAABoNAAAAAAAAACMjJyuvLy2toYHAAAAAAAAAAAAABcOIDouBgAAAAAAc4yc + tsHKysPAriIKAAAAAAAAABYgRk1LTX+DEAAAAABukqXB4ejo4dHPQCIEChcXEwggTXV/k66unKMpAAAA + AG6Srsro6ero0dN/Rk1NRk2Dg4STrsbh4cHAt2sAAAAAbpKuOXPe6ajW15KGg4OGk528yuHo5eHPz882 + AAAAAAB4jCkDAxSoMabXt5yjt8ro3ePo5dbT09HTdAAAAAAAAABGcBFoGgFwdtfDwHxi2dpmZcrX09HP + z0MAAAAAAAAAAHh/qWwaOa6cz9PNZGPYsdzbzc3DwLk2AAAAAAAAAAAAAAAvhpKakoyg19HNyKS5wHtb + orZ/cwAAAAAAAAAAAAAAAAAANkaKWVm5zb1gYV6cXVxfNgAAAAAAAAAAAAAAAAAAALGvlTIuP1K5tqCR + l4xfLwAAAAAAAAAAAAAAAAAAsbPBenkAAAAAcCVYjE0scwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////+f///+D////A////wH + ///4B///+Af///gH///wB///8Af///AH/+fwA/8D4AH8AeAAAAHgAAAB4AAAA+AAAAfwAAAP8AAAH/wA + AD//AAD//gAD//B4D////////////////////////////ygAAAAYAAAAMAAAAAEACAAAAAAAQAIAAAAA + AAAAAAAAAAEAAAABAAAAAAAAWlJSAHBJSQB1SEgAe1dXAHdYWAB5WlkAel1dAGBiYgB1bGwAfWtrAHh2 + dgB9fn4Ag01NAIRXVwCIV1cAhV9eAItbWgCgX14ApV1dAJhgXwCNYGAAnWtqAJhtbQCCdnYAh3x8AI15 + eACeensAqGBgAKhoZwCga2oArGpqALNqagCzb28AtG1tALltbQCxb3AApnVzAKlzcwCqdHMApnp6AKd+ + fgCpensAq3x7ALZ3dgC8dHQAvH59AMZvcADGcHEAxXN0AMhycwDJdncAynh5AMx5egDNfn8Ajo1wAOek + VgDGgH8A4p53AEZ2+gB8u4AAd8PaAIuEhACOh4cAjo6OAJ+DggCejo4Ao4SEAKSIiACsi4sAqo2MAK6P + jgC+gYAAvoaGAL+KiACskJAAtJeXALWenQC5np4At6iOAKmyjgC9nroAwYSDAMaGhADOhoYAxomHAMiK + iQDJjYwA0oeIANOOjwDUjY0A2ZiPANaPkADGkZEAx5eXAMySkADGnZwA1ZOSANeTlADWl5YA2JSVANGZ + mADan50A3J6dAOCcmwDVoJ8A7K2fAMOtrQDXo6IA3aCgAN+kpADVq6oA3ay3AMu0tADPtrYA3L+/AOCi + oQDhpqUA5KelAOinpgDlq6gA46usAOOvrQDqrqwA7LGuAOayswDjtrQA5re1AOqysQDts7EA57y6AO+8 + ugDrvL0A8LOwAPC1sgDwtrQA87q3APS6twD2vboA8b69APi/vAD2wb4A+cC9AJmTzwDHqMMAu8PMAIHf + 8QDByNAA7cLCAO3FwwDvxsQA5cjIAOzOzgDwxcQA9cbEAPPP0AD10tIAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + BQMJAAAAAAAAAAAAAAAAAAAAAAAAAAAPHBMNAAAAAAAAAAAAAAAAAAAAAAAAABojLy8TAAAAAAAAAAAA + AAAAAAAAAAAAAB0wMDAiPgAAAAAAAAAAAAAAAAAAAAAAQjAwMDAtGAAAAAAAAAAAAAAAAAAAAAAAFzIy + NTU5CgAAAAAAAAAAAAAAAAAAAAAAIjZYWFxcBwAAAAAAAAAAAAAAAAAAAAAANlxtdW11JQAAAAAAAAAA + PgcRDgkAAAAAXG1/lISAZgMAAAAAABkVLC5SVhcAAABNY3WWnJuLfB8UBAcQHkhWaX91dSsAAABNY2BM + mJeCiVJSVl9laX+WloSJgEIAAAAAXAEIC0tGjnR0dJaRk5qNjIyJQwAAAAAAJkNADBtdjIaPO1GSPYuJ + hnVEAAAAAAAAAClISWRcd4xwkGp8UE90VwAAAAAAAAAAAAAAKSQ1NYZ7OjhbPDdGAAAAAAAAAAAAAHNv + YGsAKyJoXFYmRwAAAAAAAAAAAAAAcnIAAAAAAAAATgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP// + /wD///8A////APx//wD4f/8A8H//APA//wDgP/8A4D//AOA//wDgP8EA4B8BAMAAAQDAAAEA4AADAOAA + BwDwAB8A/AA/APCA/wDn9/8A////AP///wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAQAAAAAAAAAA + AAAAAQAAAAEAAAAAAABjZGQAdmRjAHtpaQB/eHgAgU9PAKBaWgCFbm0AlWtqAKptbgCwZ2cAsGhoAKxw + cACteHkAvnJyAMZvcADGcHEAy3l5AMx9fgCFmXQAwIB/ANeUfQDhoX8AlIqJAJWMjACYiIgAoIaGAK2K + igCxh4cAvoGAALKKigC4iYgAuJWVAL2cnACss50AuqKhAL+mpgDLgoIAxImHAMeNjADLkI8AxpWTANCS + kQDYlZUA1J6dANqZmgDdnp4A1J+oAMaiogDOr68AzLKyANi5uADhpaIA4qypAOWtqADrrqsA4bKwAOay + sgDtuLYA57++AOy4uADxtLIA8be0APa9ugDswL4A9sG+ALCcxwC5ncIA06zBALnH0QC2ytQA7sPDAPLS + 0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAZBgUAAAAAAAAAAAAAAAAACw8KAAAAAAAAAAAAAAAAGhAQDgAAAAAAAAAAAAAAAAkRESUYAAAA + AAAAAAAAAAAlKy4uBwAAAAAAAAcDAAAAKzlHPCYCAAAYCB0oKgAAAC0wSDs0FB0nLDlAOiwAAAANAQQb + Pi9DRkVBPzUAAAAAJB4cKz5EQjMiNSkAAAAAAAAAHwwRNxYVEyQAAAAAAAAxMgAAACEgAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA4/8AAOP/AADD/wAAwf8AAMH5 + AADAwQAAwAEAAMADAADABwAA8A8AAM5/AAD//wAA//8AACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAkAAAAJAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAUAAAAOAEBAVUAAABUAAAANQAAABAAAAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAkFBSUvGRl5TCkpwlYuLtxDJCTQFw0NmQAA + AEkAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGAwMKE8rK6V6RET2klJR/5ZS + U/+OT0//ZDc38B0QEJoAAAAyAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYDAwYVzAwoopP + T/ygXVz/oFtb/55ZWf+bWFf/k1NT/1UvL9wGAwNcAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AARNKipxhk5O+adkY/+uZWX/tWdo/7VmZ/+qYWH/nltb/3hERPcfERGCAAAAFgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADEZGS1zQ0LXqGdm/7ptbf/Fb3D/x3Bx/8hwcf/BbW7/q2Vl/4hPT/82HR2gAAAAIAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAB1gxMYyYXl3/vXFx/8Zwcf/HcHH/x3Bx/8dwcf/HcHH/uG1t/5NY + V/9EJia2AAAAKQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPB8fNH1MS+K4cnH/x3Fy/8dwcf/HcHH/x3Bx/8dw + cf/HcHH/wHBx/51gX/9PLCzGAAAAMwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXjU1h6NnZv/Fc3T/x3Bx/8dw + cf/HcHH/x3Bx/8dwcf/HcHH/w3Jz/6ZoZ/9ZMzPTAQAAPQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyFxccektK0b12 + dv/HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xXR0/69wb/9jOjneBwMDSQAAAAUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABNKSlNlmBf9sh3d//HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xnd3/7Z4d/9sQUDnDgcHVQAA + AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABkOjqKsXFw/8lyc//HcXL/yHJz/8l0df/JdXb/yXV2/8l1dv/JdHX/ynt7/7+B + f/94SknvFgsLZQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACILCxB7TUzDwXd3/8lyc//KdXb/y3h5/8x7fP/NfX7/zX5+/819 + fv/NfH3/zoOC/8iJiP+GVVX3Hg8QegAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMiIi+SXl3oynp7/8t4ef/NfX7/z4GC/9GE + hf/Sh4j/04iJ/9KIiP/Rhof/04uK/8+RkP+XY2L9KxcXlwAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABwAA + AA0AAAAPAAAACwAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUvL1enbW37zn5+/85/ + gP/Rhob/1IuM/9aPkP/XkpP/2JOU/9iTlP/XkZH/15OT/9eZl/+rdHP/QSUlvAAAADwAAAAFAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAACQAA + ABgAAAAvAgEBSwcDA2EFAgJoAAAAWAAAADYAAAARAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGU8 + O4W5eXn/0IKD/9KIif/Wj5D/2ZWW/9ubm//dnp//3qCg/92foP/cnZ3/3Jyc/9+in//CiYf/Zj8/4wYC + AnAAAAAbAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAA + AA4AAAAnCQQEUCISEoQ+IiKzVzEx1mU6OuZiOTnmRigo0hgNDZsAAABMAAAAEAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAABnVJSK/HhIP/04eI/9aQkf/amJn/3qCh/+Gmp//jq6v/5Kyt/+OsrP/iqan/4aal/+ap + p//Umpj/nmxr/C8ZGboAAABXAAAAGAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAIAAAAOAQAALRkNDWY+IiKpZDo63YZRUfigZGP/sHBv/7V0c/+xcnH/oWZm/2k+PvEfEBCcAAAAMQAA + AAMAAAAAAAAAAAAAAAAAAAAALhAQFIZXVs/RjIz/1Y2O/9qYmP/eoaL/46qr/+aysv/ot7f/6rm5/+m4 + uf/otbX/5q+v/+uvrf/jqab/wYeF/28/P/QhEhKvAAAAXwAAACgAAAANAAAABQAAAAMAAAACAAAAAwAA + AAUAAAAKAAAAFQAAADAdDg9oSSkptHZHRu2dYmL+t3Z1/758e/+6enn/tnh3/7d5eP+8fn3/w4SD/7Z6 + ef9eODfbBgICTgAAAAgAAAAAAAAAAAAAAAAAAAAAPhwcJJVjYuPXkZH/2JOU/92fn//iqqr/57O0/+u8 + vP/uwsL/78XG/+/Exf/twMD/67i4/+60sv/wtrP/zZKQ/5taWv9xQED2MRsaxAgEBIcAAABaAAAAQQAA + ADcAAAA2AAAAOwAAAEUEAgJZHA4OfUcnJ7l5SkntqGxr/8CAfv/DgoH/vH59/7p+ff/DiIb/zZGP/9GT + kf/UlJP/1peV/9eZl/+GVlbuGQsLVwAAAAcAAAAAAAAAAAAAAAAAAAAARiIiLZ9rauvZk5P/2peY/+Ck + pP/lsLD/6ru7/+/Fxf/yzMz/9NDQ//PPz//xycr/7sDA//K5tv/1u7j/36Kg/6dmZf+mZWX/j1ZW/WM6 + OutDJSXQNBwcvDAaGrQ0HBy1PiIivUwsLMtkPDzfh1VU9a1xcP/EhIP/xIWE/7+Cgf/Ch4b/zZST/9mk + ov/grq3/4a6t/96lo//eoJ7/36Kg/+Cjof+IWVjnGwwMQwAAAAIAAAAAAAAAAAAAAAAAAAAARyQkL6Br + auzZk5P/25qb/+GnqP/ntLT/7cDA//LLy//209T/+NjY//fX1//00ND/8cbG//W9u//4vrz/46ak/7d0 + c/+vb27/s3Jy/7d2df+ucXD/pWpp/6Npaf+nbWz/sHVz/7p9fP/EhYT/yImI/8WIhv/DiIb/ypGP/9eg + n//hr63/57q5/+rCwP/rwsD/6bq4/+evrf/nq6n/6q6r/9qgnv9wRkbDBwAAHgAAAAAAAAAAAAAAAAAA + AAAAAAAASCQkLZ1nZuvYkpP/25uc/+Opqv/qtrf/7cHB//TOzv/52Nj/+tzc//na2v/xz9D/8MfH//fA + vv/6wb7/6a6r/8OBgP/DgoD/vX58/7h7ev+8fn3/woOC/8aHhv/HiYj/xoqJ/8aLif/Ijoz/zZST/9eg + nv/hrav/6Lm3/+zCwf/uyMf/78nH/+/Dwf/uvLr/7ba0/+60sf/vtLL/8ri1/7J+fflMKSltAAAABAAA + AAAAAAAAAAAAAAAAAAAAAAAAQyEhI5JcXOPWj5D/3Juc/8qVlf+BZmb/bl5e/4l4eP/AqKj/8tPT//LO + zv+5p6b/w6qq//fBv//7wr//8LWy/86Ojf/Ojoz/0ZGP/9GSkP/OkY//zpOR/9GamP/VoJ//2qel/+Gv + rf/nt7X/6727/+3Dwf/wycf/8czL//LLyf/yxsT/8cC+//G7uf/yubf/87m3//S7uP/4vrv/1J6c/3JH + RrAdCgsWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANRcXEYJNTcvPiIn/15aW/2VNTf85Ojr/Q0VF/0JF + RP9dXFz/n5GR/+S/v/+bh4f/hXp6/+25uP/7wr//9bu4/9qcmv/Zmpj/252b/96gnf/ipKH/5q+s/+u+ + vP/vycf/8srI/+3Hxv/wysj/9c7M//TNy//0ysj/9MbE//TBv//1vrz/9r26//e9u//4vrv/+L+8//vB + vv/hqqf/g1ZVzDwcHC4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW4+Ppq/env/05OT/2ZX + V/9rbm7/fX9//3l6ev99f3//cHJy/5F9ff+ff3//XFhY/9eop//8wr//+L+8/+Wppv/ipaP/5qil/96i + pP/Kmaz/1qi1//LGxP/tyMf/qb3J/23E3P9kw9//vMTN//jDwP/3wb//+MC9//i/vf/5v73/+b+8//i/ + vP/3vrv/+L68/92mo/+IWlnRRSMjOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFcv + L0mbX1/y15GS/6GAgP9XV1b/iYuL/4CBgf98fX3/cnR0/1dPT/++j4//km9w/9Sfnv/6wL3/+cC9/+6z + sP/ssK3/0Z+u/4OH1P9YffD/QGPs/7KYyv/Ct7z/Ytrz/3Ts//8s2f//cbvU//m+u//4v7z/+L67//e9 + uv/1vLn/9Lq3//O5tv/zuLX/0puZ/4RVVctGIyM4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAADIXFwdrPDySq2ts/diZmf/ApKT/sKur/4CBgP95enr/iYiI/49zdP/do6P/36Ch/96e + nv/zuLX/+sK///W7uP/1ubT/qZC//2qY+/9tnf//MGT6/56FxP/esK//nMbS/57n8/9+z+T/ybG3//a6 + t//zubb/8re0//C1s//utLH/7rKw/+qvrP++iIb9dklJtkMgISoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHIyMSazw8kZ5hYvXNjI3/2aSk/7OMjP+bd3f/sIKC/9KV + lv/cnJz/2peY/9aRkf/koqL/+sG+//nAvf/5v7z/4amw/6qZx/+aouP/qpvP/+mxtv/2urj/6rGv/+S6 + u//ptrX/466n/+Ovqf/ssK7/6q6s/+isqv/oq6n/2J2b/6JubfFoPT2NOxoaFwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBoaCFowMFd7SEjAomZm9sWC + gv/XkZL/25SV/9iSk//Wj5D/1IyN/9KHiP/UiIj/8bOx//rCv//3vbv/9ru4//O3s//xuLX/7q6e/+ej + hf/npIn/7bCp/+Otp/+KsX3/ULdm/1WjWv+7oYz/5KWk/9uenP+4gH79glJRzVYuLlQgCAkGAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAA8HBwQVy4uS3FBQaCPV1fjsG5v/cmAgf/ShYb/0YKD/85+f//LeXr/2I2M//e8uf/1vLn/7rOx/+2y + sP/lpJX/5qFY/+6xXP/djS3/35h9/86gl/9SwW7/Nd90/0WxXP+vlH//wYSE/49cW+VlOTmBQR4eHAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGk7OhqIWFd8oG5u8J5qav+eX2D/tmts/8Z0df/KdHX/yXJz/92T + k//3vLn/7LGu/+Snpf/dm5L/4Z1q/+61dP/fmmX/15WM/9eYlv/Bm43/r6uR/6uNgP+WYWDtbkBAnUwn + JzQVAQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiFJSBnhC + QgpqNDQJWSUlB08dHQdfKisKfENDFJJWViinbGtRvYOCjtOcm8/pt7X157y6/7eOjfhxRUW7aTk5m4RK + StehWlr6uGdo/8Zwcf/dkpH/8bSx/+OnpP/YmZj/1ZWT/9ealP/Vl5X/0JCP/8eIhv+zdnb/lFtc6nA/ + QKRSKio/JQwNBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADTn6AB2qioDMuUlCHBhYU8voCAWcCBgXTEhoaLzZGQqdeensngrKvn47Sz/NOop/+yiIfyi2Bgs2k+ + PlZXKysPAAAAAUYlJRxcMTFYcj4+pYpMTeWmXF3+xnl5/9+Zl//dnJr/z46M/8KCgf+vc3L/ll9e831L + S8hlOTl/TigoMy0REQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABzQUIDnmprDriGhifHlpZMzp6eeNCgoZ7On5+2yJqaybuPj9WnfHzVj2RkunVJ + SYNbLy8/PRQUCgAAAAAAAAAAAAAAAAAAAAAAAAAAKRUVBU0pKSphNDRtd0BAsotNTd2ZW1vrkVlY4HtJ + Sb5lOTmCUysrQTsbGxEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWCwsA2Y4OA5xQkImdkhIRHhKSll0R0dibUBAWWI2 + NkNUKCgoOhISDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMhkZB0km + Jh5LJiYsRSEhITATFAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP// + /////wAA////////AAD///////8AAP///////wAA////////AAD/+H////8AAP/gH////wAA/8Af//// + AAD/gA////8AAP+AD////wAA/wAP////AAD/AA////8AAP4AB////wAA/gAH////AAD8AAf///8AAPwA + B////wAA/AAH////AAD8AAf///8AAPgAB////wAA+AAH//4HAAD4AAP/8AEAAPgAAf/AAQAA8AAA/wAA + AADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAEAAPAAAAAAAQAA8AAAAAADAADwAAAAAAcAAPAA + AAAADwAA+AAAAAAfAAD4AAAAAD8AAPwAAAAAfwAA/gAAAAD/AAD/gAAAA/8AAP/gAAAH/wAAgAAAAB// + AAAAAAAAf/8AAAAD4AP//wAAgB/8H///AAD///////8AAP///////wAA////////AAD///////8AAP// + /////wAA////////AAAoAAAAIAAAAEAAAAABACAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAYAAAAZAAAAGQAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAARCQkYOh8fb0ooKK80HByiCQUFTAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAIhERFmA2Np2ITUz3lVNT/4dLS/5IKCi9AAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAANjODiBllhY+61kZP+vY2P/pV5e/3xHRvEhEhJfAAAAAgAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASSgoN41VVeS6bW3/xW9w/8dwcf+9bG3/klZW/jogIIEAAAAGAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ1RkWcs2xs/8dxcv/HcHH/x3Bx/8Zwcf+iYWH/SSkpmAAA + AAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUC0tMZtgX+fGcnP/x3Bx/8dwcf/HcHH/x3Fy/61q + av9UMTGqAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxRER1tm9v/8hxcv/HcHH/x3Bx/8dw + cf/HcnP/tnRz/185OboAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAACIxXV7TEdHT/yHJz/8l1 + dv/Kd3j/ynd4/8p4eP/Bf37/bURDywAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNKysjo2Zm4Mt4 + ef/NfH3/z4GC/9GFhf/RhYb/0YWF/82Mi/9+UVHeCAICOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAJAAAACwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAGc+ + Pkm1c3P30IGC/9OJiv/XkZL/2ZaW/9mWl//YlJX/2JmY/5hnZfMeEBBrAAAABwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA0FAgItHhAQWzAbG4IqFxeHDQcHWwAAABkAAAAAAAAAAAAA + AAAAAAAAek1MdMN/f//VjI3/2piZ/9+io//hqKn/4qmp/+Clpf/jpqT/wImH/04xMLwAAAA6AAAABQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABEbDg5GRygokW5CQs+MVlbxnGJh/JdfXvxnPz7hHA8PbgAA + AAwAAAAAAAAAAAAAAACMW1qbz4qK/9qXl//gpqb/5rKz/+q6u//rvLz/6La2/+qxr//epKL/j1lZ+DUc + HLACAQFPAAAAHQAAAA8AAAAPAAAAEwAAACIbDg5MVDExnYZUU+SpbWz+uXl4/7x+fP/AgoD/xoeF/72A + f/9fOzu1AAAAHAAAAAAAAAAAAAAABJhkZK/VkZH/3Z+g/+axsf/twMD/8svL//LNzf/vxcX/8Lq4/+6z + sf+1dHP/j1VU+144N9g7IiKqMhwclDcfH5RGKSmiYTw7v4tZWOiydXT+woOC/8aKiP/Ol5X/2aWj/9ui + of/cnpz/2pyb/35TUrgAAAAVAAAAAAAAAAAAAAAFmmVkstaTk//hpaX/7Lm6//TLy//419f/+NnZ//TP + z//1wb//9Lq3/8aGhP+1dHP/s3Rz/6xwb/+pb27+rnNy/7Z7ev/BhIL/yY2L/8+WlP/apqT/5be2/+vB + v//rvrz/6bKw/+uvrf/Um5n/bUVEgAAAAAMAAAAAAAAAAAAAAAOTXV2q1ZGR/9CYmP+dfX7/o4yM/9e8 + vP/z0tL/zLOz/+u8u//5v7z/1peV/8uLif/Ki4r/yoyL/86Ukv/TnJv/2qSi/+Gtq//nuLb/7cPB//DJ + x//xxsT/8b+9//G6t//zubf/77az/6d1dM89Hx8lAAAAAAAAAAAAAAAAAAAAAIJOTojNiIn/jGlp/01O + Tv9UVlb/dnNz/7uhof+Pfn7/xJ+e//zCv//lqKb/3J2b/+Chnv/hpaT/7Ly5/+vHxv/MxMn/0MjN//LK + yf/1x8X/9sLA//a/vP/3vrv/+L+8//S7uP+5hoXhYTo5RwAAAAAAAAAAAAAAAAAAAAAAAAAAaTs7RrVz + dPKmfn7/cXJx/4SGhv97fX3/b2Zm/516ev+7kJD/+sG+//C2s//lqqr/rpbA/3aB2/+ql83/tMHK/2jc + 9P9OzOz/2r3B//q/vP/3vrv/9ry6//a8uf/ss7D/tYGA32c+Pk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAvEhIHg01Njbp9fvrCn5//nI+P/4R7ev+fgID/2Jyd/9ybnP/ytrT/+b+8/+ewtf+Mld3/ZI36/5eI + zv/Ttrn/sNLc/6/Czv/stLT/8re0/++0sf/tsq//2qCe/6Rxb8phODg+AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABCIB8MeUZGbqRpata8gYH8x4mJ/9eTk//YkpP/04qL/+Cbmv/5wL3/9726/+Sw + t//Zrrn/56qY/+2smf/lr6n/nLWJ/4Gtdf/Pppn/3qGf/7yEg/KJWViYTyoqIAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQh0dGXJAQGOXXl7NtnR1/8V7fP/MfH3/znt8/+il + o//0urj/7LCu/+Whg//rq13/35VX/9Kek/9yvXz/ZbNv/6iCdfqYY2O/aj4+TCUJCgcAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACcamsBjFRVB4FERAh9PT0JjU1ND6VnZx+/hINF0JqZiNOjoty0iIf2hFBQw5lX + V8+wY2P4xXR0/+aioP/oq6j/2pqT/92fif/Vlor/yYqJ/7N8efiVZmPGdERFYkEfHxIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAALiFhgXFkJEdx5CQSMqSknbNlZWbz5uaws2cnOXBlJPnqH18r4dc + XFFULy8OSCUlFm07O0+FSUmeoV1d3sF9fPrGhoX/snZ295xkZNiFUlKbbD4+T0UdHxIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc0JDA5FgYRKdbm46onR0Zp9ycnuWampzhFlZVmY6 + OikvDAwHAAAAAAAAAAAAAAAAAAAAAB0ODgRULCwhbjo7UXhERGVrPDxHTCYmGxAAAQMAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP//////////////////////D////gf///wH///4A///+AP///AD///wA///8AP//+AD + ///gA//D4AH+AeAA+ADgAAAAwAAAAMAAAADAAAAB4AAAA+AAAAfgAAAP8AAAH/wAAD8AAAD/AAAD/wB4 + D//H////////////////////KAAAABgAAAAwAAAAAQAgAAAAAABgCQAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAABMAAAAtAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAgIO1cwMM1qOjrsHhAQmwAA + ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAATCgogfUhI6ahgYP6lXV3+f0hI9wIBAT0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsGBgFPLy6kuW1t/sZv + cP/Gb3D/oF9e/hMKCmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4QECynZmX7xnBx/sdwcf/HcHH/tG1t/h8REYMAAAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAx + MIzFc3T+xm9w/sdwcf7HcHH+vHR0/jAcHJkAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ4OAYVSUtfIcnP/yXZ3/st5ef/LeHn/xoB//kQq + KrEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAJxYWGrNvb/7Nfn//0oeI/tSNjf/UjI3/1ZOS/mE+PtQAAAAXAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAIAAAARAAAALQAAADUAAAARAAAAAAAAAAAAAAAAQyYmUM6Ghv/Wj5D/3J2e/uCl + pf/fpKT/4KOi/qRycPkHBARlAAAABQAAAAAAAAAAAAAAAAAAAAAAAAADAQAAJh8REYBYNTXMhVJR8XxM + TO8gEhKeAAAAEAAAAAAAAAAAbUVEe9aPkP7doKD+5rKz/uu9vv7rvLz+6rKx/tqfnf5iNzfnCAQEcwAA + ACoAAAAbAAAAIQIBATorGBiQhFNT67Z3dv68fn3+wYSD/siKiP6aZmX2AQAAKQAAAAAAAAAAd05Ni9eT + lP/jq6z/7cLC/vXS0v/zz9D/8b69/uyxrv+samr/l15d+2tDQ+NkPz7bdkxL451nZve+gYD/yY2M/tWg + n//jtrT/46+t/uOmpP+mdHPwBQMDFAAAAAAAAAAAdkpJh9iUlf7Hl5f+tJeX/uzOzv7lyMj+57y6/vS6 + t/7HhoX+xYaE/saJh/7MkpD+0ZmY/tejov7mt7X+7cXD/vDFxP7vvLr+8Le0/u2zsf5PMzOMDQcHAQAA + AAAAAAAAYTg4X9OOj/9aUlL/YGJi/nh2dv+skJD/qo2M/vnAvf/dn53/4KKg/+Cnp/7vxsT/u8PM/sHI + 0P/1xsT/9sG+/ve+u//3vrv/87q3/ntVVLkkFhYIAAAAAAAAAAAAAAAAVC8wD6BkZOWjhIT/jo6O/n1+ + fv+eenv/xpGR/vi/vP/wtbL/mZPP/0Z2+v69nrr/gd/x/nfD2v/2vLr/9Lq3/vG2tP/lq6j/elJRrjQg + IAoAAAAAAAAAAAAAAAAAAAAAAAAAAGc7OyeOWVnGv4eH/r2Fhf7YlZb+1Y6P/uinpv74v7z+3ay3/seo + w/7srZ/+7LGv/qmyjv63qI7+5Kel/r2GhPZ1S0p1QCcmAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAd0pKOpReXtKxb3D/yXl6/sx5ev/ws7D/6q6s/+Ked/7npFb/2ZiP/ny7gP+OjW/9h1dWr2I7 + OiMAAAAAAAAAAAAAAAAAAAAAAAAAALSCggSqcXIbo2dnN61xcVS/h4eIzp2c2cKWle2OY2OGbz4+Y4xN + Tr6zaWn84Jyb/9aXlv7Ji4r/p25t9INTUqZlPDw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJJg + YASjcnMorH9/a6h7e4yabm6Df1NTU3VKSgwAAAAAAAAAAAAAAABgNDQgcj8/bntHR4ZnPDxTVTExDQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////APx//wD4P/8A8D//AOA//wDgH/8A4B//AMAf + /wDAH8EAwA8AAMAAAADAAAAAwAAAAMAAAQDAAAMA4AAHAPgAHwAAAH8AAcH/AP///wD///8A////ACgA + AAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQc + HA5LKSlUNBwcSAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsO + DgV/SkqHm1hY+X5HR90tGRkuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAB4SEhCr2Zm7sZwcf+oYWL5UC8vUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAACnl9fnMRwcf/IcXL/tmxs/mI8PGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAa0NCGbRsbdbMenv/zn5//8R9ff9ySkmCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAA + AAkAAAAAAAAAAItYWDvFfn/y2ZWW/92fn//anJv/jWFgvwAAAB0AAAAAAAAAAAAAAAIzHBwiYjs7a3pM + S6pqQkKjLBoaMwAAAACeZ2dZ05KS/em0tP/vxMT/77u6/8CHhfpmPDyvRysqYlExMV1ySEiGnWdn07qB + gPzLkI//w4iG/HJLS3YAAAAAomloXsyRkf/DoKD/48bG/+jAv//hpKL/vX17/7h/fPu/iYj7z5qZ/+Gw + rv/rvLr/77q3/9ScmuR9U1I+AAAAAJZbWz2ndnbxdG9v/4yCgv+4lJP/77Wy/86erP+6nsH/tsXR/8PH + 0P/4wsD/9b26/+Cppu2peXdiAAAAAQAAAABYKCgHn2lqe6eCguSsgoL90pKS//Cxrv/TrcP/s5y+/8i3 + s/+quab/26mh/82UktSgbm1TBAAAAwAAAACud3cEvYGBC7N6ehyyfHtyt39+3bNub9vLgYH05qak/+Kg + g//OlH39jZR04Zd0aYmDT1EiAAAAAAAAAAAAAAAAr3t7D7aCgki5h4Z8uImJgah+fUltPz8ajU1ORq1s + bI6vdHOgm2RkaYxJUiZgCygCAAAAAAAAAAAAAAAAAAAAAGo9PQF9UVEHcEdHCTodHQIAAAAAAAAAAAAA + AAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AADh/wAAwf8AAMH/ + AACB/wAAgfkAAIDAAACAAAAAgAAAAIAAAACAAQAAAAcAAAAPAAAOfwAA//8AAA== + + + \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs index 4cb9656858..0408016eec 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs @@ -7,249 +7,11 @@ using System.Threading.Tasks; namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { + /// + /// Utilities + /// public partial class ZXSpectrum { - /* - * CPU Helper Methods - */ - - public ushort RegPC - { - get { return (ushort)((_cpu.Regs[0] << 8 | _cpu.Regs[1])); } - set - { - _cpu.Regs[1] = (ushort)(value & 0xFF); - _cpu.Regs[0] = (ushort)((value >> 8) & 0xFF); - } - } - - public ushort RegIX - { - get { return (ushort)((_cpu.Regs[15] << 8 | _cpu.Regs[16] )); } - set - { - _cpu.Regs[16] = (ushort)(value & 0xFF); - _cpu.Regs[15] = (ushort)((value >> 8) & 0xFF); - } - } - - public ushort RegDE - { - get { return (ushort)((_cpu.Regs[8] << 8 | _cpu.Regs[9] )); } - set - { - _cpu.Regs[9] = (ushort)(value & 0xFF); - _cpu.Regs[8] = (ushort)((value >> 8) & 0xFF); - } - } - - public ushort RegAF - { - get { return (ushort)((_cpu.Regs[4] << 8 | _cpu.Regs[5])); } - set - { - _cpu.Regs[5] = (ushort)(value & 0xFF); - _cpu.Regs[4] = (ushort)((value >> 8) & 0xFF); - } - } - - - /// - /// Gets the IX word value - /// - /// - public ushort Get16BitIX() - { - return Convert.ToUInt16(_cpu.Regs[_cpu.Ixh] | _cpu.Regs[_cpu.Ixl] << 8); - } - - /// - /// Set the IX word value - /// - /// - /// - public void Set16BitIX(ushort IX) - { - _cpu.Regs[_cpu.Ixh] = (ushort)(IX & 0xFF); - _cpu.Regs[_cpu.Ixl] = (ushort)((IX >> 8) & 0xff); - } - - /// - /// Gets the AF word value - /// - /// - public ushort Get16BitAF() - { - return Convert.ToUInt16(_cpu.Regs[_cpu.A] | _cpu.Regs[_cpu.F] << 8); - } - - /// - /// Set the AF word value - /// - /// - /// - public void Set16BitAF(ushort AF) - { - _cpu.Regs[_cpu.A] = (ushort)(AF & 0xFF); - _cpu.Regs[_cpu.F] = (ushort)((AF >> 8) & 0xff); - } - - /// - /// Gets the AF shadow word value - /// - /// - public ushort Get16BitAF_() - { - return Convert.ToUInt16(_cpu.Regs[_cpu.A_s] | _cpu.Regs[_cpu.F_s] << 8); - } - - /// - /// Set the AF shadow word value - /// - /// - /// - public void Set16BitAF_(ushort AF_) - { - _cpu.Regs[_cpu.A_s] = (ushort)(AF_ & 0xFF); - _cpu.Regs[_cpu.F_s] = (ushort)((AF_ >> 8) & 0xff); - } - - /// - /// Gets the DE word value - /// - /// - public ushort Get16BitDE() - { - return Convert.ToUInt16(_cpu.Regs[_cpu.E] | _cpu.Regs[_cpu.D] << 8); - } - - /// - /// Set the DE word value - /// - /// - /// - public void Set16BitDE(ushort DE) - { - _cpu.Regs[_cpu.D] = (ushort)(DE & 0xFF); - _cpu.Regs[_cpu.E] = (ushort)((DE >> 8) & 0xff); - } - - - /// - /// Z80 Status Indicator Flag Reset masks - /// - /// - [Flags] - public enum FlagsResetMask : byte - { - /// Sign Flag - S = 0x7F, - - /// Zero Flag - Z = 0xBF, - - /// This flag is not used. - R5 = 0xDF, - - /// Half Carry Flag - H = 0xEF, - - /// This flag is not used. - R3 = 0xF7, - - /// Parity/Overflow Flag - PV = 0xFB, - - /// Add/Subtract Flag - N = 0xFD, - - /// Carry Flag - C = 0xFE, - } - - /// - /// Z80 Status Indicator Flag Set masks - /// - /// - [Flags] - public enum FlagsSetMask : byte - { - /// Sign Flag - /// - /// The Sign Flag (S) stores the state of the most-significant bit of - /// the Accumulator (bit 7). When the Z80 CPU performs arithmetic - /// operations on signed numbers, the binary twos complement notation - /// is used to represent and process numeric information. - /// - S = 0x80, - - /// - /// Zero Flag - /// - /// - /// The Zero Flag is set (1) or cleared (0) if the result generated by - /// the execution of certain instructions is 0. For 8-bit arithmetic and - /// logical operations, the Z flag is set to a 1 if the resulting byte in - /// the Accumulator is 0. If the byte is not 0, the Z flag is reset to 0. - /// - Z = 0x40, - - /// This flag is not used. - R5 = 0x20, - - /// Half Carry Flag - /// - /// The Half Carry Flag (H) is set (1) or cleared (0) depending on the - /// Carry and Borrow status between bits 3 and 4 of an 8-bit arithmetic - /// operation. This flag is used by the Decimal Adjust Accumulator (DAA) - /// instruction to correct the result of a packed BCD add or subtract operation. - /// - H = 0x10, - - /// This flag is not used. - R3 = 0x08, - - /// Parity/Overflow Flag - /// - /// The Parity/Overflow (P/V) Flag is set to a specific state depending on - /// the operation being performed. For arithmetic operations, this flag - /// indicates an overflow condition when the result in the Accumulator is - /// greater than the maximum possible number (+127) or is less than the - /// minimum possible number (–128). This overflow condition is determined by - /// examining the sign bits of the operands. - /// - PV = 0x04, - - /// Add/Subtract Flag - /// - /// The Add/Subtract Flag (N) is used by the Decimal Adjust Accumulator - /// instruction (DAA) to distinguish between the ADD and SUB instructions. - /// For ADD instructions, N is cleared to 0. For SUB instructions, N is set to 1. - /// - N = 0x02, - - /// Carry Flag - /// - /// The Carry Flag (C) is set or cleared depending on the operation being performed. - /// - C = 0x01, - - /// - /// Combination of S, Z, and PV - /// - SZPV = S | Z | PV, - - /// - /// Combination of N, and H - /// - NH = N | H, - - /// - /// Combination of R3, and R5 - /// - R3R5 = R3 | R5 - } - /// /// Helper method that returns a single INT32 from a BitArray /// @@ -264,5 +26,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum bitArray.CopyTo(array, 0); return array[0]; } + + /// + /// POKEs a memory bus address + /// + /// + /// + public void PokeMemory(ushort addr, byte value) + { + _machine.WriteBus(addr, value); + } } } From 651ec7f12228e9a5dc6acd2c9c1267f8ff01b7ca Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 12 Jun 2018 11:08:03 +0100 Subject: [PATCH 42/51] ZXHawk: CoreNameStatusBarButton tooltip shows emulated spectrum model --- BizHawk.Client.EmuHawk/MainForm.cs | 12 ++++++-- .../SinclairSpectrum/ZXSpectrum.Util.cs | 29 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index ff19f07096..1db1805b44 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -2752,8 +2752,16 @@ namespace BizHawk.Client.EmuHawk var attributes = Emulator.Attributes(); CoreNameStatusBarButton.Text = Emulator.DisplayName(); - CoreNameStatusBarButton.Image = Emulator.Icon(); - CoreNameStatusBarButton.ToolTipText = attributes.Ported ? "(ported) " : ""; + CoreNameStatusBarButton.Image = Emulator.Icon(); + CoreNameStatusBarButton.ToolTipText = attributes.Ported ? "(ported) " : ""; + + + if (Emulator.SystemId == "ZXSpectrum") + { + var core = (Emulation.Cores.Computers.SinclairSpectrum.ZXSpectrum)Emulator as Emulation.Cores.Computers.SinclairSpectrum.ZXSpectrum; + CoreNameStatusBarButton.ToolTipText = core.GetMachineType(); + + } } private void ToggleKeyPriority() diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs index 0408016eec..2444e87c30 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs @@ -36,5 +36,34 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { _machine.WriteBus(addr, value); } + + + public string GetMachineType() + { + string m = ""; + switch (SyncSettings.MachineType) + { + case MachineType.ZXSpectrum16: + m = "(Sinclair) ZX Spectrum 16K"; + break; + case MachineType.ZXSpectrum48: + m = "(Sinclair) ZX Spectrum 48K"; + break; + case MachineType.ZXSpectrum128: + m = "(Sinclair) ZX Spectrum 128K"; + break; + case MachineType.ZXSpectrum128Plus2: + m = "(Amstrad) ZX Spectrum 128K +2"; + break; + case MachineType.ZXSpectrum128Plus2a: + m = "(Amstrad) ZX Spectrum 128K +2a"; + break; + case MachineType.ZXSpectrum128Plus3: + m = "(Amstrad) ZX Spectrum 128K +3"; + break; + } + + return m; + } } } From 63593b4e2c0550b708248d5611c6eb8fb0fcceed Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 12 Jun 2018 11:40:11 +0100 Subject: [PATCH 43/51] ZXHawk: Media menu to change tapes and disks --- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 65 +++++++++++++++++-- BizHawk.Client.EmuHawk/MainForm.Events.cs | 72 +++++++++++++++++++++ 2 files changed, 130 insertions(+), 7 deletions(-) diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index d2d28f2b94..57df31fabc 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -386,6 +386,10 @@ this.ZXSpectrumControllerConfigurationMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ZXSpectrumAudioSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ZXSpectrumNonSyncSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ZXSpectrumPokeMemoryMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ZXSpectrumMediaMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ZXSpectrumTapesSubMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.ZXSpectrumDisksSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainStatusBar = new StatusStripEx(); this.DumpStatusButton = new System.Windows.Forms.ToolStripDropDownButton(); @@ -458,7 +462,8 @@ this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timerMouseIdle = new System.Windows.Forms.Timer(this.components); - this.ZXSpectrumPokeMemoryMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zxt1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zxt2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); @@ -3403,7 +3408,8 @@ this.ZXSpectrumControllerConfigurationMenuItem, this.ZXSpectrumAudioSettingsMenuItem, this.ZXSpectrumNonSyncSettingsMenuItem, - this.ZXSpectrumPokeMemoryMenuItem}); + this.ZXSpectrumPokeMemoryMenuItem, + this.ZXSpectrumMediaMenuItem}); this.zXSpectrumToolStripMenuItem.Name = "zXSpectrumToolStripMenuItem"; this.zXSpectrumToolStripMenuItem.Size = new System.Drawing.Size(87, 19); this.zXSpectrumToolStripMenuItem.Text = "ZX Spectrum"; @@ -3437,6 +3443,41 @@ this.ZXSpectrumNonSyncSettingsMenuItem.Text = "Non-Sync Settings"; this.ZXSpectrumNonSyncSettingsMenuItem.Click += new System.EventHandler(this.ZXSpectrumNonSyncSettingsMenuItem_Click); // + // ZXSpectrumPokeMemoryMenuItem + // + this.ZXSpectrumPokeMemoryMenuItem.Name = "ZXSpectrumPokeMemoryMenuItem"; + this.ZXSpectrumPokeMemoryMenuItem.Size = new System.Drawing.Size(201, 22); + this.ZXSpectrumPokeMemoryMenuItem.Text = "POKE Memory"; + this.ZXSpectrumPokeMemoryMenuItem.Click += new System.EventHandler(this.ZXSpectrumPokeMemoryMenuItem_Click); + // + // ZXSpectrumMediaMenuItem + // + this.ZXSpectrumMediaMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.ZXSpectrumTapesSubMenu, + this.ZXSpectrumDisksSubMenu}); + this.ZXSpectrumMediaMenuItem.Name = "ZXSpectrumMediaMenuItem"; + this.ZXSpectrumMediaMenuItem.Size = new System.Drawing.Size(201, 22); + this.ZXSpectrumMediaMenuItem.Text = "Media"; + this.ZXSpectrumMediaMenuItem.DropDownOpened += new System.EventHandler(this.ZXSpectrumMediaMenuItem_DropDownOpened); + // + // ZXSpectrumTapesSubMenu + // + this.ZXSpectrumTapesSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.zxt1ToolStripMenuItem}); + this.ZXSpectrumTapesSubMenu.Name = "ZXSpectrumTapesSubMenu"; + this.ZXSpectrumTapesSubMenu.Size = new System.Drawing.Size(152, 22); + this.ZXSpectrumTapesSubMenu.Text = "Tapes"; + this.ZXSpectrumTapesSubMenu.DropDownOpened += new System.EventHandler(this.ZXSpectrumTapesSubMenu_DropDownOpened); + // + // ZXSpectrumDisksSubMenu + // + this.ZXSpectrumDisksSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.zxt2ToolStripMenuItem}); + this.ZXSpectrumDisksSubMenu.Name = "ZXSpectrumDisksSubMenu"; + this.ZXSpectrumDisksSubMenu.Size = new System.Drawing.Size(152, 22); + this.ZXSpectrumDisksSubMenu.Text = "Disks"; + this.ZXSpectrumDisksSubMenu.DropDownOpened += new System.EventHandler(this.ZXSpectrumDisksSubMenu_DropDownOpened); + // // Atari7800HawkCoreMenuItem // this.Atari7800HawkCoreMenuItem.Name = "Atari7800HawkCoreMenuItem"; @@ -4063,12 +4104,17 @@ this.timerMouseIdle.Interval = 2000; this.timerMouseIdle.Tick += new System.EventHandler(this.TimerMouseIdle_Tick); // - // ZXSpectrumPokeMemoryMenuItem + // zxt1ToolStripMenuItem // - this.ZXSpectrumPokeMemoryMenuItem.Name = "ZXSpectrumPokeMemoryMenuItem"; - this.ZXSpectrumPokeMemoryMenuItem.Size = new System.Drawing.Size(201, 22); - this.ZXSpectrumPokeMemoryMenuItem.Text = "POKE Memory"; - this.ZXSpectrumPokeMemoryMenuItem.Click += new System.EventHandler(this.ZXSpectrumPokeMemoryMenuItem_Click); + this.zxt1ToolStripMenuItem.Name = "zxt1ToolStripMenuItem"; + this.zxt1ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.zxt1ToolStripMenuItem.Text = "zxt1"; + // + // zxt2ToolStripMenuItem + // + this.zxt2ToolStripMenuItem.Name = "zxt2ToolStripMenuItem"; + this.zxt2ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.zxt2ToolStripMenuItem.Text = "zxt2"; // // MainForm // @@ -4540,5 +4586,10 @@ private System.Windows.Forms.ToolStripMenuItem ZXSpectrumNonSyncSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem ZXSpectrumAudioSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem ZXSpectrumPokeMemoryMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumMediaMenuItem; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumTapesSubMenu; + private System.Windows.Forms.ToolStripMenuItem ZXSpectrumDisksSubMenu; + private System.Windows.Forms.ToolStripMenuItem zxt1ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem zxt2ToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 3cbf90c572..e9048cab55 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -25,6 +25,7 @@ using BizHawk.Emulation.Cores.Computers.AppleII; using BizHawk.Client.ApiHawk; using BizHawk.Emulation.Cores.Computers.Commodore64; using BizHawk.Emulation.Cores.Nintendo.Gameboy; +using BizHawk.Emulation.Cores.Computers.SinclairSpectrum; namespace BizHawk.Client.EmuHawk { @@ -2492,6 +2493,77 @@ namespace BizHawk.Client.EmuHawk new ZXSpectrumPokeMemory().ShowDialog(); } + private void ZXSpectrumMediaMenuItem_DropDownOpened(object sender, EventArgs e) + { + if (Emulator is ZXSpectrum) + { + ZXSpectrumTapesSubMenu.Enabled = ((ZXSpectrum)Emulator)._tapeInfo.Count > 0; + ZXSpectrumDisksSubMenu.Enabled = ((ZXSpectrum)Emulator)._diskInfo.Count > 0; + } + } + + private void ZXSpectrumTapesSubMenu_DropDownOpened(object sender, EventArgs e) + { + ZXSpectrumTapesSubMenu.DropDownItems.Clear(); + + if (Emulator is ZXSpectrum) + { + var speccy = (ZXSpectrum)Emulator; + var currSel = speccy._machine.TapeMediaIndex; + + for (int i = 0; i < speccy._tapeInfo.Count; i++) + { + string name = speccy._tapeInfo[i].Name; + + var menuItem = new ToolStripMenuItem + { + Name = i + "_" + name, + Text = i + ": " + name, + Checked = currSel == i + }; + + int dummy = i; + menuItem.Click += (o, ev) => + { + speccy._machine.TapeMediaIndex = dummy; + }; + + ZXSpectrumTapesSubMenu.DropDownItems.Add(menuItem); + } + } + } + + private void ZXSpectrumDisksSubMenu_DropDownOpened(object sender, EventArgs e) + { + ZXSpectrumDisksSubMenu.DropDownItems.Clear(); + + if (Emulator is ZXSpectrum) + { + var speccy = (ZXSpectrum)Emulator; + var currSel = speccy._machine.DiskMediaIndex; + + for (int i = 0; i < speccy._diskInfo.Count; i++) + { + string name = speccy._diskInfo[i].Name; + + var menuItem = new ToolStripMenuItem + { + Name = i + "_" + name, + Text = i + ": " + name, + Checked = currSel == i + }; + + int dummy = i; + menuItem.Click += (o, ev) => + { + speccy._machine.DiskMediaIndex = dummy; + }; + + ZXSpectrumDisksSubMenu.DropDownItems.Add(menuItem); + } + } + } + #endregion #region Help From 5ec469f2f31b1b4ab3e95183d28307d4529b2845 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Tue, 12 Jun 2018 14:22:28 +0100 Subject: [PATCH 44/51] ZXHawk: Tape status (F10) now reports tape progress in addition to current block progress --- .../SinclairSpectrum/ZXSpectrum.Messaging.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs index 8c7f6baf14..7b14980b30 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs @@ -410,6 +410,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum sb.Append(p.ToString("N0") + "%"); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); sb.Clear(); + + // get position within the tape itself + sb.Append("Tape Pos: "); + var ind = _machine.TapeDevice.CurrentDataBlockIndex; + int cnt = 0; + for (int i = 0; i < ind; i++) + { + cnt += _machine.TapeDevice.DataBlocks[i].DataPeriods.Count; + } + // now we are at our current block + int ourPos = cnt + pos; + cnt += end; + // count periods in the remaining blocks + for (int i = ind + 1; i < _machine.TapeDevice.DataBlocks.Count; i++) + { + cnt += _machine.TapeDevice.DataBlocks[i].DataPeriods.Count; + } + // work out overall position within the tape + p = 0; + p = ((double)ourPos / (double)cnt) * (double)100; + sb.Append(p.ToString("N0") + "%"); + SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } #endregion From 8c3afc189a4a7a7d1faa49dfdd67c02d94dd0393 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 12 Jun 2018 16:51:21 -0400 Subject: [PATCH 45/51] z80: add a MEMRQ vector for memory contention for zx spectrum --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 1 + .../CPUs/Z80A/Interrupts.cs | 4 + .../CPUs/Z80A/Tables_Direct.cs | 86 ++++++++++++++----- .../CPUs/Z80A/Tables_Indirect.cs | 57 +++++++++--- BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 12 ++- 5 files changed, 123 insertions(+), 37 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index 3912d5668d..6574be6ff3 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -22,6 +22,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A public ushort instr_swap; public ushort[] cur_instr; public ushort[] BUSRQ; + public ushort[] MEMRQ; public byte opcode; public bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix; public bool IXCB_prefetch, IYCB_prefetch; // value is fetched before opcode diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs index 389fdf6e8f..1781a5eebe 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -46,6 +46,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } // Mode 0 interrupts only take effect if a CALL or RST is on the data bus @@ -65,6 +66,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0 }; } // Just jump to $0038 @@ -86,6 +88,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { I, 0, 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { I, 0, 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } // Interrupt mode 2 uses the I vector combined with a byte on the data bus @@ -113,6 +116,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { I, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, W, 0 ,0 ,PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { I, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60}; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs index f91fb31afc..d5a2e8c3a2 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -15,7 +15,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } // NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers @@ -29,6 +30,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void EXX_() @@ -40,6 +42,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } // this exchanges 2 16 bit registers @@ -52,6 +55,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void INC_16(ushort src_l, ushort src_h) @@ -64,7 +68,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, I, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { I, I, PCh, 0, 0, 0}; + MEMRQ = new ushort[] { 0, 0, PCh, 0, 0, 0 }; } @@ -78,7 +83,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, I, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { I, I, PCh, 0, 0, 0}; + MEMRQ = new ushort[] { 0, 0, PCh, 0, 0, 0 }; } // this is done in two steps technically, but the flags don't work out using existing funcitons @@ -98,7 +104,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, I, I, I, I, I, I, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { I, I, I, I, I, I, I, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP(ushort operation, ushort dest, ushort src) @@ -109,7 +116,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } // Operations using the I and R registers take one T-cycle longer @@ -123,6 +131,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { I, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, PCh, 0, 0, 0 }; } // note: do not use DEC here since no flags are affected by this operation @@ -145,7 +154,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { I, PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, PCh, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } else { @@ -159,7 +169,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, PCh, 0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { I, PCh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, PCh, 0, 0, PCh, 0, 0, 0 }; } } @@ -171,7 +182,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A IDLE, HALT }; - BUSRQ = new ushort[] {PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void JR_COND(bool cond) @@ -192,7 +204,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } else { @@ -205,7 +218,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0 }; } } @@ -225,7 +239,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, 0 }; } else { @@ -241,7 +256,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0 }; } } @@ -259,7 +275,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } private void RETI_() @@ -276,7 +293,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } private void RETN_() @@ -293,7 +311,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } @@ -314,7 +333,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] { I, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } else { @@ -325,7 +345,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {I, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { I, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, PCh, 0, 0, 0 }; } } @@ -338,10 +359,10 @@ namespace BizHawk.Emulation.Cores.Components.Z80A WAIT, RD_INC, Z, PCl, PCh, IDLE, - DEC16, SPl, SPh, WAIT, - RD_INC, W, PCl, PCh, - IDLE, + RD, W, PCl, PCh, + INC16, PCl, PCh, + DEC16, SPl, SPh, WAIT, WR_DEC, SPl, SPh, PCh, IDLE, @@ -352,7 +373,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] {PCh, 0, 0, PCh, 0, 0, PCh, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } else { @@ -369,6 +391,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, 0, 0, 0 }; } } @@ -381,6 +404,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void BIT_OP(ushort operation, ushort bit, ushort src) @@ -392,6 +416,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void PUSH_(ushort src_l, ushort src_h) @@ -410,6 +435,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { I, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } @@ -428,6 +454,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { SPh, 0, 0, SPh, 0, 0, PCh, 0, 0, 0 }; } private void RST_(ushort n) @@ -446,6 +473,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { I, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, SPh, 0, 0, SPh, 0, 0, W, 0, 0, 0 }; } private void PREFIX_(ushort src) @@ -457,6 +485,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A PREFIX, src}; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void PREFETCH_(ushort src) @@ -483,6 +512,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A PREFIX, src,}; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, PCh }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0, 0 }; } private void DI_() @@ -494,6 +524,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void EI_() @@ -505,6 +536,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void JP_16(ushort src_l, ushort src_h) @@ -516,6 +548,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { src_h, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, 0 }; } private void LD_SP_16(ushort src_l, ushort src_h) @@ -529,6 +562,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { I, I, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, PCh, 0, 0, 0 }; } private void OUT_() @@ -546,7 +580,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP}; - BUSRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0}; + BUSRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; } private void OUT_REG_(ushort dest, ushort src) @@ -562,6 +597,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { BIO1, BIO2, BIO3, BIO4, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { BIO1, BIO2, BIO3, BIO4, PCh, 0, 0, 0 }; } private void IN_() @@ -580,6 +616,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, WIO1, WIO2, WIO3, WIO4, PCh, 0, 0, 0 }; } private void IN_REG_(ushort dest, ushort src) @@ -595,6 +632,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { BIO1, BIO2, BIO3, BIO4, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { BIO1, BIO2, BIO3, BIO4, PCh, 0, 0, 0 }; } private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -613,6 +651,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { I, I, I, I, I, I, I, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } private void INT_MODE_(ushort src) @@ -624,6 +663,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } private void RRD_() @@ -645,6 +685,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { H, 0, 0, H, H, H, H, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void RLD_() @@ -666,6 +707,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { H, 0, 0, H, H, H, H, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs index bab93cbe1f..9c13e3d062 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -18,6 +18,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) @@ -36,6 +37,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } // Note that this operation uses I_BIT, same as indexed BIT. @@ -55,6 +57,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, src_h, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -69,6 +72,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -83,6 +87,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } // different because HL doesn't effect WZ @@ -98,6 +103,7 @@ OP }; BUSRQ = new ushort[] { H, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { H, 0, 0, PCh, 0, 0, 0 }; } private void LD_16_IND_nn(ushort src_l, ushort src_h) @@ -121,6 +127,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_16_nn(ushort dest_l, ushort dest_h) @@ -144,6 +151,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_8_IND_nn(ushort src) @@ -164,6 +172,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_8_nn(ushort dest) @@ -184,6 +193,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src) @@ -198,6 +208,7 @@ OP }; BUSRQ = new ushort[] { dest_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { dest_h, 0, 0, PCh, 0, 0, 0 }; } // seperate HL needed since it doesn't effect the WZ pair @@ -213,6 +224,7 @@ OP }; BUSRQ = new ushort[] { H, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { H, 0, 0, PCh, 0, 0, 0 }; } private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -230,6 +242,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, dest_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, dest_h, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h) @@ -244,6 +257,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, PCh, 0, 0, 0 }; } private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) @@ -261,6 +275,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } private void INC_8_IND(ushort src_l, ushort src_h) @@ -279,6 +294,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } private void DEC_8_IND(ushort src_l, ushort src_h) @@ -297,6 +313,7 @@ OP }; BUSRQ = new ushort[] { src_h, 0, 0, src_h, src_h, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { src_h, 0, 0, 0, src_h, 0, 0, PCh, 0, 0, 0 }; } // NOTE: WZ implied for the wollowing 3 functions @@ -316,6 +333,7 @@ OP }; BUSRQ = new ushort[] { W, 0, 0, W, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { W, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_BIT_OP(ushort operation, ushort bit, ushort dest) @@ -334,6 +352,7 @@ OP }; BUSRQ = new ushort[] { W, 0, 0, W, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { W, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_BIT_TE(ushort bit) @@ -349,6 +368,7 @@ OP }; BUSRQ = new ushort[] { W, 0, 0, W, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { W, 0, 0, 0, PCh, 0, 0, 0 }; } private void I_OP_n(ushort operation, ushort src_l, ushort src_h) @@ -356,13 +376,13 @@ cur_instr = new ushort[] {IDLE, WAIT, - RD_INC, ALU, PCl, PCh, + RD, ALU, PCl, PCh, IDLE, IDLE, TR16, Z, W, src_l, src_h, ADDS, Z, W, ALU, ZERO, IDLE, - IDLE, + INC16, PCl, PCh, WAIT, RD, ALU, Z, W, operation, ALU, @@ -375,6 +395,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, W, 0, 0, W, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_OP_n_n(ushort src_l, ushort src_h) @@ -385,10 +406,10 @@ RD_INC, ALU, PCl, PCh, ADDS, Z, W, ALU, ZERO, WAIT, - RD_INC, ALU, PCl, PCh, - IDLE, + RD, ALU, PCl, PCh, IDLE, IDLE, + INC16, PCl, PCh, WAIT, WR, Z, W, ALU, IDLE, @@ -397,6 +418,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, PCh, PCh, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, PCh, 0, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h) @@ -404,13 +426,13 @@ cur_instr = new ushort[] {IDLE, WAIT, - RD_INC, ALU, PCl, PCh, + RD, ALU, PCl, PCh, IDLE, TR16, Z, W, src_l, src_h, IDLE, ADDS, Z, W, ALU, ZERO, IDLE, - IDLE, + INC16, PCl, PCh, WAIT, RD, ALU, Z, W, operation, dest, ALU, @@ -419,6 +441,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, W, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, PCh, 0, 0, 0 }; } private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) @@ -426,13 +449,13 @@ cur_instr = new ushort[] {IDLE, WAIT, - RD_INC, ALU, PCl, PCh, + RD, ALU, PCl, PCh, IDLE, IDLE, TR16, Z, W, dest_l, dest_h, ADDS, Z, W, ALU, ZERO, IDLE, - IDLE, + INC16, PCl, PCh, WAIT, WR, Z, W, src, IDLE, @@ -441,6 +464,7 @@ OP }; BUSRQ = new ushort[] { PCh, 0, 0, PCh, PCh, PCh, PCh, PCh, Z, 0, 0, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0, 0, 0, 0, 0, Z, 0, 0, PCh, 0, 0, 0 }; } private void LD_OP_R(ushort operation, ushort repeat_instr) @@ -456,6 +480,7 @@ SET_FL_LD_R, 0, operation, repeat_instr}; BUSRQ = new ushort[] { H, 0, 0, D, 0, 0, D, D }; + MEMRQ = new ushort[] { H, 0, 0, D, 0, 0, 0, 0 }; } private void CP_OP_R(ushort operation, ushort repeat_instr) @@ -471,6 +496,7 @@ SET_FL_CP_R, 1, operation, repeat_instr}; BUSRQ = new ushort[] { H, 0, 0, H, H, H, H, H }; + MEMRQ = new ushort[] { H, 0, 0, 0, 0, 0, 0, 0 }; } private void IN_OP_R(ushort operation, ushort repeat_instr) @@ -486,6 +512,7 @@ REP_OP_I, L, H, ALU, operation, 2, operation, repeat_instr }; BUSRQ = new ushort[] { I, BIO1, BIO2, BIO3, BIO4, H, 0, 0}; + MEMRQ = new ushort[] { 0, BIO1, BIO2, BIO3, BIO4, H, 0, 0 }; } private void OUT_OP_R(ushort operation, ushort repeat_instr) @@ -501,6 +528,7 @@ REP_OP_O, C, B, ALU, operation, 3, operation, repeat_instr }; BUSRQ = new ushort[] { I, H, 0, 0, BIO1, BIO2, BIO3, BIO4 }; + MEMRQ = new ushort[] { 0, H, 0, 0, BIO1, BIO2, BIO3, BIO4 }; } // this is an indirect change of a a 16 bit register with memory @@ -509,25 +537,26 @@ cur_instr = new ushort[] {IDLE, WAIT, - RD, Z, dest_l, dest_h, - INC16, dest_l, dest_h, - IDLE, + RD_INC, Z, dest_l, dest_h, + IDLE, WAIT, RD, W, dest_l, dest_h, IDLE, + IDLE, WAIT, WR_DEC, dest_l, dest_h, src_h, - IDLE, - IDLE, IDLE, WAIT, WR, dest_l, dest_h, src_l, + IDLE, + IDLE, TR16, src_l, src_h, Z, W, WAIT, OP_F, OP }; - BUSRQ = new ushort[] { dest_h, 0, 0, 0, dest_h, 0, 0, dest_h, 0, 0, 0, 0, dest_h, 0, 0, PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { dest_h, 0, 0, dest_h, 0, 0, dest_h, dest_h, 0, 0, dest_h, 0, 0, dest_h, dest_h, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { dest_h, 0, 0, dest_h, 0, 0, 0, dest_h, 0, 0, dest_h, 0, 0, 0, 0, PCh, 0, 0, 0 }; } } } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index afd07e1979..a128c8958f 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -103,6 +103,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; instr_pntr = 0; bus_pntr = 0; NO_prefix = true; } @@ -509,6 +510,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { D, D, D, D, D, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } else { @@ -518,7 +520,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP_F, OP }; - BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } instr_pntr = 0; bus_pntr = 0; break; @@ -543,6 +546,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } else { @@ -553,6 +557,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } instr_pntr = 0; bus_pntr = 0; break; @@ -620,6 +625,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP}; BUSRQ = new ushort[] { H, H, H, H, H, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } else { @@ -630,6 +636,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } instr_pntr = 0; bus_pntr = 0; break; @@ -679,6 +686,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { B, B, B, B, B, PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { 0, 0, 0, 0, 0, PCh, 0, 0, 0 }; } else { @@ -689,6 +697,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A OP }; BUSRQ = new ushort[] { PCh, 0, 0, 0 }; + MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } instr_pntr = 0; bus_pntr = 0; break; @@ -767,6 +776,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A ser.Sync("bus_pntr", ref bus_pntr); ser.Sync("cur_instr", ref cur_instr, false); ser.Sync("BUSRQ", ref BUSRQ, false); + ser.Sync("MEMRQ", ref MEMRQ, false); ser.Sync("instr_swap", ref instr_swap); ser.Sync("opcode", ref opcode); ser.Sync("FlagI", ref FlagI); From 9a906cd8af49e8b1bb6df2d5bbf90dc01bf3dbd6 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 12 Jun 2018 16:57:11 -0400 Subject: [PATCH 46/51] z80: add memptr variable --- BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 1 + BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs | 26 ++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs index 6574be6ff3..9b308b76e3 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -19,6 +19,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A // variables for executing instructions public int instr_pntr = 0; public int bus_pntr = 0; + public int mem_pntr = 0; public ushort instr_swap; public ushort[] cur_instr; public ushort[] BUSRQ; diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs index a128c8958f..a96e76beb8 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -104,7 +104,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { PCh, 0, 0, 0 }; MEMRQ = new ushort[] { PCh, 0, 0, 0 }; - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; NO_prefix = true; } @@ -167,7 +167,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A FlagI2 = FlagI1; FlagI1 = FlagI; - bus_pntr++; + bus_pntr++; mem_pntr++; switch (cur_instr[instr_pntr++]) { case IDLE: @@ -195,7 +195,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A iff1 = false; NMI_(); NMICallback(); - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; } else if (iff1 && FlagI5) { @@ -222,7 +222,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A break; } IRQCallback(); - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; } else { @@ -230,7 +230,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A if (TraceCallback != null) TraceCallback(State()); RegPC++; FetchInstruction(); - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; } temp_R = (byte)(Regs[R] & 0x7F); @@ -301,7 +301,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A temp_R &= 0x7F; Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; break; case RD: Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); @@ -446,7 +446,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A RegPC++; FetchInstruction(); - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; // only the first prefix in a double prefix increases R, although I don't know how / why if (prefix_src < 4) { @@ -523,7 +523,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { PCh, 0, 0, 0 }; MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; break; case SET_FL_CP_R: SET_FL_CP_Func(); @@ -559,7 +559,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { PCh, 0, 0, 0 }; MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; break; case SET_FL_IR: SET_FL_IR_Func(cur_instr[instr_pntr++]); @@ -570,8 +570,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A case WAIT: if (FlagW) { - instr_pntr--; - bus_pntr--; + instr_pntr--; bus_pntr--; mem_pntr--; } break; case RST: @@ -638,7 +637,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { PCh, 0, 0, 0 }; MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; break; case REP_OP_O: OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); @@ -699,7 +698,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A BUSRQ = new ushort[] { PCh, 0, 0, 0 }; MEMRQ = new ushort[] { PCh, 0, 0, 0 }; } - instr_pntr = 0; bus_pntr = 0; + instr_pntr = 0; bus_pntr = 0; mem_pntr = 0; break; } TotalExecutedCycles++; @@ -774,6 +773,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80A ser.Sync("instr_pntr", ref instr_pntr); ser.Sync("bus_pntr", ref bus_pntr); + ser.Sync("mem_pntr", ref mem_pntr); ser.Sync("cur_instr", ref cur_instr, false); ser.Sync("BUSRQ", ref BUSRQ, false); ser.Sync("MEMRQ", ref MEMRQ, false); From 9166b0b9319d29b14993cd15b79cb6f169ca50f0 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 13 Jun 2018 07:55:23 +0100 Subject: [PATCH 47/51] ZXHawk: wire up +2a/+3 memory contention model (MREQ) --- .../Computers/SinclairSpectrum/Machine/CPUMonitor.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 8838abe75e..50ff4ced4a 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -30,7 +30,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public ushort BUSRQ { - get { return _cpu.BUSRQ[_cpu.bus_pntr]; } + get + { + switch (machineType) + { + case MachineType.ZXSpectrum128Plus2a: + case MachineType.ZXSpectrum128Plus3: + return _cpu.MEMRQ[_cpu.bus_pntr]; + default: + return _cpu.BUSRQ[_cpu.mem_pntr]; + } + } } #endregion From 7ce55e660176c08f1472ab8800f5373296cb90fc Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 13 Jun 2018 09:24:43 +0100 Subject: [PATCH 48/51] ZXHawk: ReadPort method was incorrectly snagging occational floating bus requests and processing them as kempston joystick input --- .../SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs | 6 ++++-- .../Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 6 ++++-- .../Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 6 ++++-- .../SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs | 8 +++++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index 0596dce779..a1dcc1427e 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -43,9 +43,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (AYDevice.ReadPort(port, ref result)) return (byte)result; - // Kempston joystick input takes priority over all other input + byte lowByte = (byte)(port & 0xff); + + // Kempston joystick input takes priority over keyboard input // if this is detected just return the kempston byte - if ((port & 0xe0) == 0 || (port & 0x20) == 0) + if (lowByte == 0x1f) { if (LocateUniqueJoystick(JoystickType.Kempston) != null) return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index a2cd41da7d..214442e49f 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -24,9 +24,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (AYDevice.ReadPort(port, ref result)) return (byte)result; - // Kempston joystick input takes priority over all other input + byte lowByte = (byte)(port & 0xff); + + // Kempston joystick input takes priority over all keyboard input // if this is detected just return the kempston byte - if ((port & 0xe0) == 0 || (port & 0x20) == 0) + if (lowByte == 0x1f) { if (LocateUniqueJoystick(JoystickType.Kempston) != null) return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index 31c2e08e44..f71ab0af90 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -24,9 +24,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (AYDevice.ReadPort(port, ref result)) return (byte)result; - // Kempston joystick input takes priority over all other input + byte lowByte = (byte)(port & 0xff); + + // Kempston joystick input takes priority over all keyboard input // if this is detected just return the kempston byte - if ((port & 0xe0) == 0 || (port & 0x20) == 0) + if (lowByte == 0x1f) { if (LocateUniqueJoystick(JoystickType.Kempston) != null) return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index 31fd2ac00b..632caceac2 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -20,10 +20,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // Check whether the low bit is reset // Technically the ULA should respond to every even I/O address bool lowBitReset = (port & 0x0001) == 0; - - // Kempston joystick input takes priority over all other input + byte lowByte = (byte)(port & 0xff); + + // Kempston joystick input takes priority over keyboard input // if this is detected just return the kempston byte - if ((port & 0xe0) == 0 || (port & 0x20) == 0) + if (lowByte == 0x1f) { if (LocateUniqueJoystick(JoystickType.Kempston) != null) return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine; @@ -31,6 +32,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // not a lag frame InputRead = true; } + // Even ports always address the ULA else if (lowBitReset) { // Even I/O address so get input from keyboard From 373db358054707a354ff91261d7644c0cfe6123c Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 13 Jun 2018 11:53:05 +0100 Subject: [PATCH 49/51] ZXHawk: implemented +2a/+3 floating bus (confirmed working with 2017 release of 'A Yankee in Iraq') --- .../SinclairSpectrum/Machine/CPUMonitor.cs | 9 ++- .../Machine/SpectrumBase.Memory.cs | 7 +- .../SinclairSpectrum/Machine/SpectrumBase.cs | 2 + .../Computers/SinclairSpectrum/Machine/ULA.cs | 66 +++++++++++++++---- .../Machine/ZXSpectrum128K/ZX128.Port.cs | 4 +- .../ZX128Plus2a.Memory.cs | 6 ++ .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 2 +- .../ZX128Plus2a.Screen.cs | 4 +- .../ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 2 + .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 2 +- .../Machine/ZXSpectrum48K/ZX48.Port.cs | 2 +- 11 files changed, 87 insertions(+), 19 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs index 50ff4ced4a..9ae88a6e8d 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs @@ -62,6 +62,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public ushort lastPortAddr; + /// + /// If true, the next read memory operation has been contended + /// + public bool NextMemReadContended; + #endregion #region Methods @@ -87,6 +92,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (cont > 0) { _cpu.TotalExecutedCycles += cont; + NextMemReadContended = true; } } } @@ -393,7 +399,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public void SyncState(Serializer ser) { ser.BeginSection("CPUMonitor"); - ser.Sync("", ref lastPortAddr); + ser.Sync("lastPortAddr", ref lastPortAddr); + ser.Sync("NextMemReadContended", ref NextMemReadContended); ser.EndSection(); } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs index 8bd72d3dcd..e3511847b8 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs @@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// Signs that all paging is disabled /// If this is TRUE, then 128k and above machines need a hard reset before paging is allowed again /// - protected bool PagingDisabled; + public bool PagingDisabled; /// /// Index of the currently paged ROM @@ -87,6 +87,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// protected int PagingConfiguration; + /// + /// The last byte that was read after contended cycles + /// + public byte LastContendedReadByte; + #endregion #region Memory Related Methods diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index 58753c45e5..c2968a08a2 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -357,11 +357,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum ser.Sync("PagingConfiguration", ref PagingConfiguration); ser.Sync("ROMhigh", ref ROMhigh); ser.Sync("ROMlow", ref ROMlow); + ser.Sync("LastContendedReadByte", ref LastContendedReadByte); KeyboardDevice.SyncState(ser); BuzzerDevice.SyncState(ser); TapeBuzzer.SyncState(ser); ULADevice.SyncState(ser); + CPUMon.SyncState(ser); if (AYDevice != null) { diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs index 2e9ff98b8c..448c7f9251 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ULA.cs @@ -667,12 +667,31 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } } + /// + /// Generates the port lookup table for +2a/+3 allowed floating bus ports + /// + public void GenerateP3PortTable() + { + List table = new List(); + for (int i = 0; i < 0x1000; i++) + { + ushort r = (ushort)(1 + (4 * i)); + if (r > 4093) + break; + table.Add(r); + } + + Plus3FBPortTable = table.ToArray(); + } + + private ushort[] Plus3FBPortTable = new ushort[1]; + /// /// Returns floating bus value (if available) /// /// /// - public void ReadFloatingBus(int tstate, ref int result) + public void ReadFloatingBus(int tstate, ref int result, ushort port) { tstate += FloatingBusOffset; if (tstate >= RenderingTable.Renderer.Length) @@ -688,13 +707,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum case MachineType.ZXSpectrum48: case MachineType.ZXSpectrum128: case MachineType.ZXSpectrum128Plus2: - /* - if (item.FloatingBusAddress > 0) - { - result = _machine.FetchScreenMemory(item.FloatingBusAddress); - //result = 0x00; - } - */ + switch (item.RAction) { case RenderTable.RenderAction.BorderAndFetchByte1: @@ -708,15 +721,46 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum result = _machine.FetchScreenMemory(item.AttributeAddress); break; default: - //result = _machine.FetchScreenMemory(fetchA2); break; } - - break; case MachineType.ZXSpectrum128Plus2a: case MachineType.ZXSpectrum128Plus3: + + // http://sky.relative-path.com/zx/floating_bus.html + if (_machine.PagingDisabled) + { + result = 0xff; + break; + } + + // check whether fb is found on this port + ushort pLook = Array.Find(Plus3FBPortTable, s => s == port); + if (pLook == 0) + { + result = 0xff; + break; + } + + // floating bus on +2a/+3 always returns a byte with Bit0 set + switch (item.RAction) + { + case RenderTable.RenderAction.BorderAndFetchByte1: + case RenderTable.RenderAction.Shift1AndFetchByte2: + case RenderTable.RenderAction.Shift2AndFetchByte1: + result = (byte)(_machine.FetchScreenMemory(item.ByteAddress) | 0x01); + break; + case RenderTable.RenderAction.BorderAndFetchAttribute1: + case RenderTable.RenderAction.Shift1AndFetchAttribute2: + case RenderTable.RenderAction.Shift2AndFetchAttribute1: + result = (byte)(_machine.FetchScreenMemory(item.AttributeAddress) | 0x01); + break; + default: + result = (byte)(_machine.LastContendedReadByte | 0x01); + break; + } + break; } } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs index a1dcc1427e..b34d860f86 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs @@ -32,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // -asni (2018-06-08) - need this to pass the final portread tests from fusetest.tap // get the floating bus value - ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result, port); // use this to set the paging registers WritePort(port, (byte)result); // return the floating bus value @@ -71,7 +71,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (!deviceAddressed) { // If this is an unused port the floating memory bus should be returned - ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result, port); } return (byte)result; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs index 73400dd86c..ebb6f7c399 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs @@ -358,6 +358,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override byte ReadMemory(ushort addr) { var data = ReadBus(addr); + if (CPUMon.NextMemReadContended) + { + LastContendedReadByte = data; + CPUMon.NextMemReadContended = false; + } + return data; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs index 214442e49f..cf43ced6e5 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs @@ -52,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (!deviceAddressed) { // If this is an unused port the floating memory bus should be returned - ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result, port); } return (byte)result; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs index a95d06d8ce..53c0f3a0cb 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Screen.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // offsets RenderTableOffset = 58; ContentionOffset = 9; - FloatingBusOffset = 1; + FloatingBusOffset = 0; // timing ClockSpeed = 3546900; FrameCycleLength = 70908; @@ -43,6 +43,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum MachineType.ZXSpectrum128Plus2a); SetupScreenSize(); + + GenerateP3PortTable(); } #endregion diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index 87a9062912..fed504bf1c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -358,6 +358,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public override byte ReadMemory(ushort addr) { var data = ReadBus(addr); + if (CPUMon.NextMemReadContended) + LastContendedReadByte = data; return data; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs index f71ab0af90..0f74207c16 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs @@ -56,7 +56,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum if (!deviceAddressed) { // If this is an unused port the floating memory bus should be returned - ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result, port); } return (byte)result; diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs index 632caceac2..e0a91aa2d6 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs @@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // If this is an unused port the floating memory bus should be returned - ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result); + ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result, port); } return (byte)result; From 837c681bd532d21d7b9269432f0c66cd568ef64e Mon Sep 17 00:00:00 2001 From: Asnivor Date: Wed, 13 Jun 2018 11:57:43 +0100 Subject: [PATCH 50/51] ZXHawk: missed a bool --- .../Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs index fed504bf1c..33509faa6b 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs @@ -359,7 +359,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum { var data = ReadBus(addr); if (CPUMon.NextMemReadContended) + { LastContendedReadByte = data; + CPUMon.NextMemReadContended = false; + } + return data; } From 93dab42ba6b71328b0557057c0c462749c234e5b Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 13 Jun 2018 08:29:07 -0400 Subject: [PATCH 51/51] z80: Start up values for SP and AF --- BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs index 8ca466d5e2..ceb6017a7e 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -127,6 +127,12 @@ namespace BizHawk.Emulation.Cores.Components.Z80A Regs[i] = 0; } + // These registers are set as part of the reset process + Regs[A] = 0xFF; + Regs[F] = 0xFF; + Regs[SPl] = 0xFF; + Regs[SPh] = 0xFF; + // the IRQ1 vector is 0x38 Regs[IRQ_V] = 0x38; // The NMI vector is constant 0x66