ZXHawk: Support double-sided *.dsk images and throw an exception if the images are not 42 track disks

This commit is contained in:
Asnivor 2018-09-11 11:21:59 +01:00
parent d4a48a8ee1
commit faaf4d2f18
3 changed files with 246 additions and 3 deletions

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -141,6 +142,63 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
diskImages.Add(m);
Spectrum._diskInfo.Add(Spectrum._gameInfo[cnt]);
break;
case SpectrumMediaType.DiskDoubleSided:
// this is a bit tricky. we will attempt to parse the double sided disk image byte array,
// then output two separate image byte arrays
List<byte[]> working = new List<byte[]>();
foreach (DiskType type in Enum.GetValues(typeof(DiskType)))
{
bool found = false;
switch (type)
{
case DiskType.CPCExtended:
found = CPCExtendedFloppyDisk.SplitDoubleSided(m, working);
break;
case DiskType.CPC:
found = CPCFloppyDisk.SplitDoubleSided(m, working);
break;
}
if (found)
{
// add side 1
diskImages.Add(working[0]);
// add side 2
diskImages.Add(working[1]);
Common.GameInfo one = new Common.GameInfo();
Common.GameInfo two = new Common.GameInfo();
var gi = Spectrum._gameInfo[cnt];
for (int i = 0; i < 2; i++)
{
Common.GameInfo work = new Common.GameInfo();
if (i == 0)
{
work = one;
}
else if (i == 1)
{
work = two;
}
work.FirmwareHash = gi.FirmwareHash;
work.Hash = gi.Hash;
work.Name = gi.Name + " (Parsed Side " + (i + 1) + ")";
work.Region = gi.Region;
work.NotInDatabase = gi.NotInDatabase;
work.Status = gi.Status;
work.System = gi.System;
Spectrum._diskInfo.Add(work);
}
}
else
{
}
}
break;
}
cnt++;
@ -192,7 +250,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
if (hdr.ToUpper().Contains("EXTENDED CPC DSK") || hdr.ToUpper().Contains("MV - CPC"))
{
// spectrum .dsk disk file
return SpectrumMediaType.Disk;
// check for number of sides
var sides = data[0x31];
if (sides == 1)
return SpectrumMediaType.Disk;
else
return SpectrumMediaType.DiskDoubleSided;
}
if (hdr.ToUpper().StartsWith("FDI"))
{
@ -231,6 +294,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
None,
Tape,
Disk
Disk,
DiskDoubleSided
}
}

View File

@ -1,5 +1,7 @@
using System.Text;
using BizHawk.Common;
using System;
using System.Collections.Generic;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
@ -53,6 +55,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
throw new System.NotImplementedException(sbm.ToString());
}
if (DiskHeader.NumberOfTracks > 42)
{
StringBuilder sbm = new StringBuilder();
sbm.AppendLine();
sbm.AppendLine();
sbm.AppendLine("The detected disk is an " + DiskHeader.NumberOfTracks + " track disk image.");
sbm.AppendLine("This is currently incompatible with the emulated +3 disk drive (42 tracks).");
sbm.AppendLine("Likely the disk image is an 80 track betadisk or opus image, the drives and controllers for which are not currently emulated in ZXHawk");
throw new System.NotImplementedException(sbm.ToString());
}
for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
{
DiskHeader.TrackSizes[i] = data[pos++] * 256;
@ -144,6 +157,88 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
return true;
}
/// <summary>
/// Takes a double-sided disk byte array and converts into 2 single-sided arrays
/// </summary>
/// <param name="data"></param>
/// <param name="results"></param>
/// <returns></returns>
public static bool SplitDoubleSided(byte[] data, List<byte[]> results)
{
// look for standard magic string
string ident = Encoding.ASCII.GetString(data, 0, 16);
if (!ident.ToUpper().Contains("EXTENDED CPC DSK"))
{
// incorrect format
return false;
}
byte[] S0 = new byte[data.Length];
byte[] S1 = new byte[data.Length];
// disk info block
Array.Copy(data, 0, S0, 0, 0x100);
Array.Copy(data, 0, S1, 0, 0x100);
// change side number
S0[0x31] = 1;
S1[0x31] = 1;
// extended format can have different track sizes
int[] trkSizes = new int[data[0x30] * data[0x31]];
int pos = 0x34;
for (int i = 0; i < data[0x30] * data[0x31]; i++)
{
trkSizes[i] = data[pos] * 256;
// clear destination trk sizes (will be added later)
S0[pos] = 0;
S1[pos] = 0;
pos++;
}
// start at track info blocks
int mPos = 0x100;
int s0Pos = 0x100;
int s0tCount = 0;
int s1tCount = 0;
int s1Pos = 0x100;
int tCount = 0;
while (tCount < data[0x30] * data[0x31])
{
// which side is this?
var side = data[mPos + 0x11];
if (side == 0)
{
// side 1
Array.Copy(data, mPos, S0, s0Pos, trkSizes[tCount]);
s0Pos += trkSizes[tCount];
// trk size table
S0[0x34 + s0tCount++] = (byte)(trkSizes[tCount] / 256);
}
else if (side == 1)
{
// side 2
Array.Copy(data, mPos, S1, s1Pos, trkSizes[tCount]);
s1Pos += trkSizes[tCount];
// trk size table
S1[0x34 + s1tCount++] = (byte)(trkSizes[tCount] / 256);
}
mPos += trkSizes[tCount++];
}
byte[] s0final = new byte[s0Pos];
byte[] s1final = new byte[s1Pos];
Array.Copy(S0, 0, s0final, 0, s0Pos);
Array.Copy(S1, 0, s1final, 0, s1Pos);
results.Add(s0final);
results.Add(s1final);
return true;
}
/// <summary>
/// State serlialization
/// </summary>

View File

@ -1,5 +1,7 @@
using System.Text;
using BizHawk.Common;
using System;
using System.Collections.Generic;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
@ -53,6 +55,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
throw new System.NotImplementedException(sbm.ToString());
}
if (DiskHeader.NumberOfTracks > 42)
{
StringBuilder sbm = new StringBuilder();
sbm.AppendLine();
sbm.AppendLine();
sbm.AppendLine("The detected disk is an " + DiskHeader.NumberOfTracks + " track disk image.");
sbm.AppendLine("This is currently incompatible with the emulated +3 disk drive (42 tracks).");
sbm.AppendLine("Likely the disk image is an 80 track betadisk or opus image, the drives and controllers for which are not currently emulated in ZXHawk");
throw new System.NotImplementedException(sbm.ToString());
}
// standard CPC format all track sizes are the same in the image
for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
{
@ -149,6 +162,77 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
return true;
}
/// <summary>
/// Takes a double-sided disk byte array and converts into 2 single-sided arrays
/// </summary>
/// <param name="data"></param>
/// <param name="results"></param>
/// <returns></returns>
public static bool SplitDoubleSided(byte[] data, List<byte[]> results)
{
// look for standard magic string
string ident = Encoding.ASCII.GetString(data, 0, 16);
if (!ident.ToUpper().Contains("MV - CPC"))
{
// incorrect format
return false;
}
byte[] S0 = new byte[data.Length];
byte[] S1 = new byte[data.Length];
// disk info block
Array.Copy(data, 0, S0, 0, 0x100);
Array.Copy(data, 0, S1, 0, 0x100);
// change side number
S0[0x31] = 1;
S1[0x31] = 1;
var trkSize = MediaConverter.GetWordValue(data, 0x32);
// start at track info blocks
int mPos = 0x100;
int s0Pos = 0x100;
int s1Pos = 0x100;
var numTrks = data[0x30];
var numSides = data[0x31];
while (mPos < trkSize * data[0x30] * data[0x31])
{
// which side is this?
var side = data[mPos + 0x11];
if (side == 0)
{
// side 1
Array.Copy(data, mPos, S0, s0Pos, trkSize);
s0Pos += trkSize;
}
else if (side == 1)
{
// side 2
Array.Copy(data, mPos, S1, s1Pos, trkSize);
s1Pos += trkSize;
}
else
{
}
mPos += trkSize;
}
byte[] s0final = new byte[s0Pos];
byte[] s1final = new byte[s1Pos];
Array.Copy(S0, 0, s0final, 0, s0Pos);
Array.Copy(S1, 0, s1final, 0, s1Pos);
results.Add(s0final);
results.Add(s1final);
return true;
}
/// <summary>
/// State serlialization
/// </summary>