Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 134 additions & 2 deletions BizHawk.sln

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/BizHawk.Client.Common/RomGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public RomGame(HawkFile file, string patch)
{
RomData = FileData;
}
else if (file.Extension is ".cdt" or ".csw" or ".dsk" or ".pzx" or ".tap" or ".tzx" or ".wav")
else if (file.Extension is ".cdt" or ".csw" or ".dsk" or ".pzx" or ".tap" or ".trd" or ".scl" or ".tzx" or ".wav")
{
// these are not roms. unfortunately if treated as such there are certain edge-cases
// where a header offset is detected. This should mitigate this issue until a cleaner solution is found
Expand Down
11 changes: 10 additions & 1 deletion src/BizHawk.Client.Common/RomLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,15 @@ private void LoadOther(
_ => rom.GameInfo.System,
};

// Container-agnostic flux images (.scp/.hfe) carry no reliable platform id in their header, and
// the gamedb extension switch (in BizHawk.Emulation.Common) cannot decode flux; identify by
// content here, where the Cores flux decoders are reachable. Defers to the chooser if unsure.
if (string.IsNullOrEmpty(rom.GameInfo.System) && ext is ".scp" or ".hfe")
{
var fluxSystem = Emulation.Cores.Floppy.FluxDiskFormatIdentifier.IdentifySystem(rom.FileData);
if (!string.IsNullOrEmpty(fluxSystem)) rom.GameInfo.System = fluxSystem;
}

if (string.IsNullOrEmpty(rom.GameInfo.System))
{
// Has the user picked a preference for this extension?
Expand Down Expand Up @@ -1097,7 +1106,7 @@ private static class RomFileExtensions

public static readonly IReadOnlyCollection<string> WSWAN = new[] { "ws", "wsc", "pc2" };

public static readonly IReadOnlyCollection<string> ZXSpectrum = new[] { "tzx", "tap", "dsk", "pzx", "ipf" };
public static readonly IReadOnlyCollection<string> ZXSpectrum = new[] { "tzx", "tap", "dsk", "pzx", "ipf", "scp", "hfe", "fdi", "udi", "trd", "scl" };

public static readonly IReadOnlyCollection<string> AutoloadFromArchive = Array.Empty<string>()
.Concat(A26)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ public partial class ZxSpectrumCoreEmulationSettings : Form

private readonly ZXSpectrum.ZXSpectrumSyncSettings _syncSettings;

// Gigascreen frame blending is a display-only (non-sync) Setting, but it is shown here alongside the
// other picture options (border type). It is saved separately via PutCoreSettings so toggling it does
// not reboot the core or affect movie sync.
private readonly ZXSpectrum.ZXSpectrumSettings _settings;

public ZxSpectrumCoreEmulationSettings(ISettingsAdapter settable)
{
_settable = settable;
_syncSettings = (ZXSpectrum.ZXSpectrumSyncSettings) _settable.GetSyncSettings();
_settings = (ZXSpectrum.ZXSpectrumSettings) _settable.GetSettings();
InitializeComponent();
Icon = Properties.Resources.GameControllerIcon;
}
Expand Down Expand Up @@ -44,25 +50,72 @@ private void IntvControllerSettings_Load(object sender, EventArgs e)

// autoload tape
autoLoadcheckBox1.Checked = _syncSettings.AutoLoadTape;

// gigascreen frame blending (non-sync display setting)
gigascreenBlendCheckBox.Checked = _settings.GigascreenFrameBlend;

// turbo tape loading - only takes effect when Deterministic Emulation is off, so the turbo controls
// are disabled (greyed out) whenever deterministic emulation is enabled
flashLoadcheckBox1.Checked = _syncSettings.TapeLoadSpeed == ZXSpectrum.TapeLoadSpeed.Instant;

// turbo multiplier slider: internal range 1..10 maps to 5x..50x (multiplier = Value * 5)
int storedMult = _syncSettings.TapeLoadTurboMultiplier;
if (storedMult < 5) storedMult = 5;
else if (storedMult > 50) storedMult = 50;
turboMultiplierTrackBar.Value = storedMult / 5;
UpdateTurboMultiplierLabel();

UpdateTurboControlsEnabled();
determEmucheckBox1.CheckedChanged += (_, _) => UpdateTurboControlsEnabled();
flashLoadcheckBox1.CheckedChanged += (_, _) => UpdateTurboControlsEnabled();
}

private void TurboMultiplierTrackBar_Scroll(object sender, EventArgs e) => UpdateTurboMultiplierLabel();

private void UpdateTurboMultiplierLabel() => turboMultiplierValueLabel.Text = $"{turboMultiplierTrackBar.Value * 5}x";

private void UpdateTurboControlsEnabled()
{
// turbo loading only applies on a non-deterministic core
flashLoadcheckBox1.Enabled = !determEmucheckBox1.Checked;
// the multiplier only matters when turbo loading is both available and ticked
bool turboActive = flashLoadcheckBox1.Enabled && flashLoadcheckBox1.Checked;
turboMultiplierTrackBar.Enabled = turboActive;
turboMultiplierValueLabel.Enabled = turboActive;
}

private void OkBtn_Click(object sender, EventArgs e)
{
var tapeLoadSpeed = flashLoadcheckBox1.Checked ? ZXSpectrum.TapeLoadSpeed.Instant : ZXSpectrum.TapeLoadSpeed.Accurate;
int turboMultiplier = turboMultiplierTrackBar.Value * 5;

bool changed =
_syncSettings.MachineType.ToString() != MachineSelectionComboBox.SelectedItem.ToString()
|| _syncSettings.BorderType.ToString() != borderTypecomboBox1.SelectedItem.ToString()
|| _syncSettings.DeterministicEmulation != determEmucheckBox1.Checked
|| _syncSettings.AutoLoadTape != autoLoadcheckBox1.Checked;
|| _syncSettings.AutoLoadTape != autoLoadcheckBox1.Checked
|| _syncSettings.TapeLoadSpeed != tapeLoadSpeed
|| _syncSettings.TapeLoadTurboMultiplier != turboMultiplier;

if (changed)
{
_syncSettings.MachineType = (MachineType)Enum.Parse(typeof(MachineType), MachineSelectionComboBox.SelectedItem.ToString());
_syncSettings.BorderType = (ZXSpectrum.BorderType)Enum.Parse(typeof(ZXSpectrum.BorderType), borderTypecomboBox1.SelectedItem.ToString());
_syncSettings.DeterministicEmulation = determEmucheckBox1.Checked;
_syncSettings.AutoLoadTape = autoLoadcheckBox1.Checked;
_syncSettings.TapeLoadSpeed = tapeLoadSpeed;
_syncSettings.TapeLoadTurboMultiplier = turboMultiplier;

_settable.PutCoreSyncSettings(_syncSettings);
}

// non-sync display setting: applied live (no reboot), so handled independently of 'changed' above
if (gigascreenBlendCheckBox.Checked != _settings.GigascreenFrameBlend)
{
_settings.GigascreenFrameBlend = gigascreenBlendCheckBox.Checked;
_settable.PutCoreSettings(_settings);
}

DialogResult = DialogResult.OK;
Close();
}
Expand Down
3 changes: 3 additions & 0 deletions src/BizHawk.Emulation.Common/Database/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,9 @@ public static GameInfo GetGameInfo(byte[] romData, string fileName)
case ".PZX":
case ".CSW":
case ".WAV":
case ".UDI": // Ultra Disk Image - ZX Spectrum only
case ".TRD": // TR-DOS disk - ZX Spectrum (Beta 128 / Pentagon) only
case ".SCL": // TR-DOS packed disk - ZX Spectrum only
game.System = VSystemID.Raw.ZXSpectrum;
break;

Expand Down
26 changes: 26 additions & 0 deletions src/BizHawk.Emulation.Cores/CPUs/Z80AOpt/Disassemblable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;

using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.Z80A; // reuse the shared Z80ADisassembler tables

namespace BizHawk.Emulation.Cores.Components.Z80AOpt
{
// IDisassemblable is implemented by delegating to the shared Z80ADisassembler
// (the mnemonic tables live in the original Z80A core and are not perf-critical,
// so they are reused rather than forked).
public sealed partial class Z80AOpt<TLink> : IDisassemblable
{
public string Cpu
{
get => "Z80";
set { }
}

public string PCRegisterName => "PC";

public IEnumerable<string> AvailableCpus { get; } = [ "Z80" ];

public string Disassemble(MemoryDomain m, uint addr, out int length)
=> Z80ADisassembler.Disassemble((ushort)addr, a => m.PeekByte(a), out length);
}
}
Loading
Loading