ZXHawk: Starting on UDI and IPF disk image support (although neither are fully working or hooked up yet)

This commit is contained in:
Asnivor 2018-09-13 10:44:48 +01:00
parent faaf4d2f18
commit c76e2f35a0
10 changed files with 797 additions and 14 deletions

View File

@ -288,9 +288,11 @@
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.Memory.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.Port.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum16K\ZX16.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\CPCExtendedFloppyDisk.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\CPCFloppyDisk.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\CPCFormat\CPCExtendedFloppyDisk.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\CPCFormat\CPCFloppyDisk.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\DiskType.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\IPFFormat\IPFFloppyDisk.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Disk\UDIFormat\UDI1_0FloppyDisk.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\MediaConverter.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\MediaConverterType.cs" />
<Compile Include="Computers\SinclairSpectrum\Media\Snapshot\SZX\SZX.Objects.cs" />

View File

@ -816,6 +816,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
fdd = new CPCFloppyDisk();
found = fdd.ParseDisk(diskData);
break;
case DiskType.IPF:
fdd = new IPFFloppyDisk();
found = fdd.ParseDisk(diskData);
break;
case DiskType.UDI:
fdd = new UDI1_0FloppyDisk();
found = fdd.ParseDisk(diskData);
break;
}
if (found)

View File

@ -158,6 +158,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
case DiskType.CPC:
found = CPCFloppyDisk.SplitDoubleSided(m, working);
break;
case DiskType.UDI:
found = UDI1_0FloppyDisk.SplitDoubleSided(m, working);
break;
}
if (found)
@ -262,6 +265,26 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// spectrum .fdi disk file
return SpectrumMediaType.Disk;
}
if (hdr.ToUpper().StartsWith("CAPS"))
{
// IPF format file
return SpectrumMediaType.Disk;
}
if (hdr.ToUpper().StartsWith("UDI!") && data[0x08] == 0)
{
// UDI v1.0
if (hdr.StartsWith("udi!"))
{
throw new NotSupportedException("ZXHawk currently does not supported UDIv1.0 with compression.");
}
else
{
if (data[0x0A] == 0x01)
return SpectrumMediaType.DiskDoubleSided;
else
return SpectrumMediaType.Disk;
}
}
// tape checking
if (hdr.ToUpper().StartsWith("ZXTAPE!"))

View File

@ -14,6 +14,21 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// <summary>
/// Extended CPCEMU disk format (used in the built-in +3 disk drive)
/// </summary>
CPCExtended
CPCExtended,
/// <summary>
/// Interchangeable Preservation Format
/// </summary>
IPF,
/// <summary>
/// Ultra Disk Image Format (v1.0)
/// </summary>
UDI,
/// <summary>
/// Ultra Disk Image Format (v1.1)
/// </summary>
UDIv1_1
}
}

View File

@ -602,13 +602,22 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
public byte NumberOfSectors { get; set; }
public byte GAP3Length { get; set; }
public byte FillerByte { get; set; }
public Sector[] Sectors { get; set; }
public virtual Sector[] Sectors { get; set; }
#region UDI
public virtual byte TrackType { get; set; }
public virtual int TLEN { get; set; }
public virtual int CLEN { get { return TLEN / 8 + (TLEN % 8 / 7) / 8; } }
public virtual byte[] TrackData { get; set; }
#endregion
/// <summary>
/// Presents a contiguous byte array of all sector data for this track
/// (including any multiple weak/random data)
/// </summary>
public byte[] TrackSectorData
public virtual byte[] TrackSectorData
{
get
{
@ -626,15 +635,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
public class Sector
{
public byte TrackNumber { get; set; }
public byte SideNumber { get; set; }
public byte SectorID { get; set; }
public byte SectorSize { get; set; }
public byte Status1 { get; set; }
public byte Status2 { get; set; }
public int ActualDataByteLength { get; set; }
public byte[] SectorData { get; set; }
public bool ContainsMultipleWeakSectors { get; set; }
public virtual byte TrackNumber { get; set; }
public virtual byte SideNumber { get; set; }
public virtual byte SectorID { get; set; }
public virtual byte SectorSize { get; set; }
public virtual byte Status1 { get; set; }
public virtual byte Status2 { get; set; }
public virtual int ActualDataByteLength { get; set; }
public virtual byte[] SectorData { get; set; }
public virtual bool ContainsMultipleWeakSectors { get; set; }
public int WeakReadIndex = 0;

View File

@ -0,0 +1,461 @@
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
public class IPFFloppyDisk : FloppyDisk
{
/// <summary>
/// The format type
/// </summary>
public override DiskType DiskFormatType => DiskType.IPF;
/// <summary>
/// Attempts to parse incoming disk data
/// </summary>
/// <param name="diskData"></param>
/// <returns>
/// TRUE: disk parsed
/// FALSE: unable to parse disk
/// </returns>
public override bool ParseDisk(byte[] data)
{
// look for standard magic string
string ident = Encoding.ASCII.GetString(data, 0, 16);
if (!ident.ToUpper().Contains("CAPS"))
{
// incorrect format
return false;
}
int pos = 0;
List<IPFBlock> blocks = new List<IPFBlock>();
while (pos < data.Length)
{
try
{
var block = IPFBlock.ParseNextBlock(ref pos, this, data, blocks);
if (block == null)
{
// EOF
break;
}
if (block.RecordType == RecordHeaderType.None)
{
// unknown block
}
blocks.Add(block);
}
catch (Exception ex)
{
}
}
// now process the blocks
var infoBlock = blocks.Where(a => a.RecordType == RecordHeaderType.INFO).FirstOrDefault();
var IMGEblocks = blocks.Where(a => a.RecordType == RecordHeaderType.IMGE).ToList();
var DATAblocks = blocks.Where(a => a.RecordType == RecordHeaderType.DATA).ToList();
DiskHeader.NumberOfTracks = (byte)(IMGEblocks.Count());
DiskHeader.NumberOfSides = (byte)(infoBlock.INFOmaxSide + 1);
DiskTracks = new Track[DiskHeader.NumberOfTracks];
for (int t = 0; t < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; t++)
{
// each imge block represents one track
var img = IMGEblocks[t];
DiskTracks[t] = new Track();
var trk = DiskTracks[t];
var blockCount = img.IMGEblockCount;
var dataBlock = DATAblocks.Where(a => a.DATAdataKey == img.IMGEdataKey).FirstOrDefault();
trk.SideNumber = (byte)img.IMGEside;
trk.TrackNumber = (byte)img.IMGEtrack;
trk.Sectors = new Sector[blockCount];
// process data block descriptors
int p = 0;
for (int d = 0; d < blockCount; d++)
{
var extraDataAreaStart = 32 * blockCount;
trk.Sectors[d] = new Sector();
var sector = trk.Sectors[d];
int dataBits = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
int gapBits = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
int dataBytes;
int gapBytes;
int gapOffset;
int cellType;
if (infoBlock.INFOencoderType == 1)
{
dataBytes = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
gapBytes = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
}
else if (infoBlock.INFOencoderType == 2)
{
gapOffset = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
cellType = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
}
int encoderType = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
int? blockFlags = null;
if (infoBlock.INFOencoderType == 2)
{
blockFlags = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p);
}
p += 4;
int gapDefault = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
int dataOffset = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
// gap stream elements
if (infoBlock.INFOencoderType == 2 && gapBits != 0 && blockFlags != null)
{
if (!blockFlags.Value.Bit(1) && !blockFlags.Value.Bit(0))
{
// no gap stream
}
if (!blockFlags.Value.Bit(1) && blockFlags.Value.Bit(0))
{
// Forward gap stream list only
}
if (blockFlags.Value.Bit(1) && !blockFlags.Value.Bit(0))
{
// Backward gap stream list only
}
if (blockFlags.Value.Bit(1) && blockFlags.Value.Bit(0))
{
// Forward and Backward stream lists
}
}
// data stream elements
if (dataBits != 0)
{
var dsLocation = dataOffset;
for (;;)
{
byte dataHead = dataBlock.DATAextraDataRaw[dsLocation++];
if (dataHead == 0)
{
// end of data stream list
break;
}
var sampleSize = ((dataHead & 0xE0) >> 5);
var dataType = dataHead & 0x1F;
byte[] dSize = new byte[sampleSize];
Array.Copy(dataBlock.DATAextraDataRaw, dsLocation, dSize, 0, sampleSize);
var dataSize = MediaConverter.GetBEInt32FromByteArray(dSize);
dsLocation += dSize.Length;
int dataLen;
byte[] dataStream = new byte[0];
if (blockFlags != null && blockFlags.Value.Bit(2))
{
// bits
if (dataType != 5)
{
dataLen = dataSize / 8;
if (dataSize % 8 != 0)
{
// bits left over
}
dataStream = new byte[dataLen];
Array.Copy(dataBlock.DATAextraDataRaw, dsLocation, dataStream, 0, dataLen);
}
}
else
{
// bytes
if (dataType != 5)
{
dataStream = new byte[dataSize];
Array.Copy(dataBlock.DATAextraDataRaw, dsLocation, dataStream, 0, dataSize);
}
}
// dataStream[] now contains the data
switch (dataType)
{
// SYNC
case 1:
break;
// DATA
case 2:
if (dataStream.Length == 7)
{
// ID
// first byte IAM
sector.TrackNumber = dataStream[1];
sector.SideNumber = dataStream[2];
sector.SectorID = dataStream[3];
sector.SectorSize = dataStream[4];
}
else if (dataStream.Length > 255)
{
// DATA
// first byte DAM
if (dataStream[0] == 0xF8)
{
// deleted address mark
//sector.Status1
}
sector.SectorData = new byte[dataStream.Length - 1 - 2];
Array.Copy(dataStream, 1, sector.SectorData, 0, dataStream.Length - 1 - 2);
}
break;
// GAP
case 3:
break;
// RAW
case 4:
break;
// FUZZY
case 5:
break;
default:
break;
}
dsLocation += dataStream.Length;
}
}
}
}
return true;
}
public class IPFBlock
{
public RecordHeaderType RecordType;
public int BlockLength;
public int CRC;
public byte[] RawBlockData;
public int StartPos;
#region INFO
public int INFOmediaType;
public int INFOencoderType;
public int INFOencoderRev;
public int INFOfileKey;
public int INFOfileRev;
public int INFOorigin;
public int INFOminTrack;
public int INFOmaxTrack;
public int INFOminSide;
public int INFOmaxSide;
public int INFOcreationDate;
public int INFOcreationTime;
public int INFOplatform1;
public int INFOplatform2;
public int INFOplatform3;
public int INFOplatform4;
public int INFOdiskNumber;
public int INFOcreatorId;
#endregion
#region IMGE
public int IMGEtrack;
public int IMGEside;
public int IMGEdensity;
public int IMGEsignalType;
public int IMGEtrackBytes;
public int IMGEstartBytePos;
public int IMGEstartBitPos;
public int IMGEdataBits;
public int IMGEgapBits;
public int IMGEtrackBits;
public int IMGEblockCount;
public int IMGEencoderProcess;
public int IMGEtrackFlags;
public int IMGEdataKey;
#endregion
#region DATA
public int DATAlength;
public int DATAbitSize;
public int DATAcrc;
public int DATAdataKey;
public byte[] DATAextraDataRaw;
#endregion
public static IPFBlock ParseNextBlock(ref int startPos, FloppyDisk disk, byte[] data, List<IPFBlock> blockCollection)
{
IPFBlock ipf = new IPFBlock();
ipf.StartPos = startPos;
if (startPos >= data.Length)
{
// EOF
return null;
}
// assume the startPos passed in is actually the start of a new block
// look for record header ident
string ident = Encoding.ASCII.GetString(data, startPos, 4);
startPos += 4;
try
{
ipf.RecordType = (RecordHeaderType)Enum.Parse(typeof(RecordHeaderType), ident);
}
catch
{
ipf.RecordType = RecordHeaderType.None;
}
// setup for actual block size
ipf.BlockLength = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.CRC = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.RawBlockData = new byte[ipf.BlockLength];
Array.Copy(data, ipf.StartPos, ipf.RawBlockData, 0, ipf.BlockLength);
switch (ipf.RecordType)
{
// Nothing to process / unknown
// just move ahead
case RecordHeaderType.CAPS:
case RecordHeaderType.TRCK:
case RecordHeaderType.DUMP:
case RecordHeaderType.CTEI:
case RecordHeaderType.CTEX:
default:
startPos = ipf.StartPos + ipf.BlockLength;
break;
// INFO block
case RecordHeaderType.INFO:
// INFO header is followed immediately by an INFO block
ipf.INFOmediaType = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOencoderType = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOencoderRev = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOfileKey = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOfileRev = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOorigin = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOminTrack = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOmaxTrack = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOminSide = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOmaxSide = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOcreationDate = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOcreationTime = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOplatform1 = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOplatform2 = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOplatform3 = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOplatform4 = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOdiskNumber = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.INFOcreatorId = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
startPos += 12; // reserved
break;
case RecordHeaderType.IMGE:
ipf.IMGEtrack = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEside = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEdensity = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEsignalType = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEtrackBytes = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEstartBytePos = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEstartBitPos = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEdataBits = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEgapBits = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEtrackBits = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEblockCount = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEencoderProcess = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEtrackFlags = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.IMGEdataKey = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
startPos += 12; // reserved
break;
case RecordHeaderType.DATA:
ipf.DATAlength = MediaConverter.GetBEInt32(data, startPos);
if (ipf.DATAlength == 0)
{
ipf.DATAextraDataRaw = new byte[0];
ipf.DATAlength = 0;
}
else
{
ipf.DATAextraDataRaw = new byte[ipf.DATAlength];
}
startPos += 4;
ipf.DATAbitSize = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.DATAcrc = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
ipf.DATAdataKey = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
if (ipf.DATAlength != 0)
{
Array.Copy(data, startPos, ipf.DATAextraDataRaw, 0, ipf.DATAlength);
}
startPos += ipf.DATAlength;
break;
}
return ipf;
}
}
public enum RecordHeaderType
{
None,
CAPS,
DUMP,
DATA,
TRCK,
INFO,
IMGE,
CTEI,
CTEX,
}
/// <summary>
/// State serlialization
/// </summary>
/// <param name="ser"></param>
public override void SyncState(Serializer ser)
{
ser.BeginSection("Plus3FloppyDisk");
ser.Sync("CylinderCount", ref CylinderCount);
ser.Sync("SideCount", ref SideCount);
ser.Sync("BytesPerTrack", ref BytesPerTrack);
ser.Sync("WriteProtected", ref WriteProtected);
ser.SyncEnum("Protection", ref Protection);
ser.Sync("DirtyData", ref DirtyData);
if (DirtyData)
{
}
// sync deterministic track and sector counters
ser.Sync(" _randomCounter", ref _randomCounter);
RandomCounter = _randomCounter;
ser.EndSection();
}
}
}

View File

@ -0,0 +1,217 @@
using BizHawk.Common;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
public class UDI1_0FloppyDisk : FloppyDisk
{
/// <summary>
/// The format type
/// </summary>
public override DiskType DiskFormatType => DiskType.UDI;
/// <summary>
/// Attempts to parse incoming disk data
/// </summary>
/// <param name="diskData"></param>
/// <returns>
/// TRUE: disk parsed
/// FALSE: unable to parse disk
/// </returns>
public override bool ParseDisk(byte[] data)
{
// look for standard magic string
string ident = Encoding.ASCII.GetString(data, 0, 4);
if (!ident.StartsWith("UDI!") && !ident.StartsWith("udi!"))
{
// incorrect format
return false;
}
if (data[0x08] != 0)
{
// wrong version
return false;
}
if (ident == "udi!")
{
// cant handle compression yet
return false;
}
DiskHeader.DiskIdent = ident;
DiskHeader.NumberOfTracks = (byte)(data[0x09] + 1);
DiskHeader.NumberOfSides = (byte)(data[0x0A] + 1);
DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
int fileSize = MediaConverter.GetInt32(data, 4); // not including the final 4-byte checksum
// ignore extended header
var extHdrSize = MediaConverter.GetInt32(data, 0x0C);
int pos = 0x10 + extHdrSize;
// process track information
for (int t = 0; t < DiskHeader.NumberOfTracks; t++)
{
DiskTracks[t] = new UDIv1Track();
DiskTracks[t].TrackNumber = (byte)t;
DiskTracks[t].SideNumber = 0;
DiskTracks[t].TrackType = data[pos++];
DiskTracks[t].TLEN = MediaConverter.GetWordValue(data, pos); pos += 2;
DiskTracks[t].TrackData = new byte[DiskTracks[t].TLEN + DiskTracks[t].CLEN];
Array.Copy(data, pos, DiskTracks[t].TrackData, 0, DiskTracks[t].TLEN + DiskTracks[t].CLEN);
pos += DiskTracks[t].TLEN + DiskTracks[t].CLEN;
}
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, 4);
if (!ident.StartsWith("UDI!") && !ident.StartsWith("udi!"))
{
// incorrect format
return false;
}
if (data[0x08] != 0)
{
// wrong version
return false;
}
if (ident == "udi!")
{
// cant handle compression yet
return false;
}
byte[] S0 = new byte[data.Length];
byte[] S1 = new byte[data.Length];
// header
var extHdr = MediaConverter.GetInt32(data, 0x0C);
Array.Copy(data, 0, S0, 0, 0x10 + extHdr);
Array.Copy(data, 0, S1, 0, 0x10 + extHdr);
// change side number
S0[0x0A] = 0;
S1[0x0A] = 0;
int pos = 0x10 + extHdr;
int fileSize = MediaConverter.GetInt32(data, 4); // not including the final 4-byte checksum
int s0Pos = pos;
int s1Pos = pos;
// process track information
for (int t = 0; t < (data[0x09] + 1) * 2; t++)
{
var TLEN = MediaConverter.GetWordValue(data, pos + 1);
var CLEN = TLEN / 8 + (TLEN % 8 / 7) / 8;
var blockSize = TLEN + CLEN + 3;
// 2 sided image: side 0 tracks will all have t as an even number
try
{
if (t == 0 || t % 2 == 0)
{
Array.Copy(data, pos, S0, s0Pos, blockSize);
s0Pos += blockSize;
}
else
{
Array.Copy(data, pos, S1, s1Pos, blockSize);
s1Pos += blockSize;
}
}
catch (Exception ex)
{
}
pos += blockSize;
}
// skip checkum bytes for now
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;
}
public class UDIv1Track : Track
{
/// <summary>
/// Parse the UDI TrackData byte[] array into sector objects
/// </summary>
public override Sector[] Sectors
{
get
{
List<UDIv1Sector> secs = new List<UDIv1Sector>();
var datas = TrackData.Skip(3).Take(TLEN).ToArray();
var clocks = new BitArray(TrackData.Skip(3 + TLEN).Take(CLEN).ToArray());
return secs.ToArray();
}
}
}
public class UDIv1Sector : Sector
{
}
/// <summary>
/// State serlialization
/// </summary>
/// <param name="ser"></param>
public override void SyncState(Serializer ser)
{
ser.BeginSection("Plus3FloppyDisk");
ser.Sync("CylinderCount", ref CylinderCount);
ser.Sync("SideCount", ref SideCount);
ser.Sync("BytesPerTrack", ref BytesPerTrack);
ser.Sync("WriteProtected", ref WriteProtected);
ser.SyncEnum("Protection", ref Protection);
ser.Sync("DirtyData", ref DirtyData);
if (DirtyData)
{
}
// sync deterministic track and sector counters
ser.Sync(" _randomCounter", ref _randomCounter);
RandomCounter = _randomCounter;
ser.EndSection();
}
}
}

View File

@ -2,6 +2,7 @@
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Linq;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
@ -95,6 +96,53 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
return buf[offsetIndex] | buf[offsetIndex + 1] << 8 | buf[offsetIndex + 2] << 16 | buf[offsetIndex + 3] << 24;
}
/// <summary>
/// Returns an int32 from a byte array based on offset (in BIG ENDIAN format)
/// </summary>
/// <param name="buf"></param>
/// <param name="offsetIndex"></param>
/// <returns></returns>
public static int GetBEInt32(byte[] buf, int offsetIndex)
{
byte[] b = new byte[4];
Array.Copy(buf, offsetIndex, b, 0, 4);
byte[] buffer = b.Reverse().ToArray();
int pos = 0;
return buffer[pos++] | buffer[pos++] << 8 | buffer[pos++] << 16 | buffer[pos++] << 24;
}
/// <summary>
/// Returns an int32 from a byte array based on the length of the byte array (in BIG ENDIAN format)
/// </summary>
/// <param name="buf"></param>
/// <returns></returns>
public static int GetBEInt32FromByteArray(byte[] buf)
{
byte[] b = buf.Reverse().ToArray();
if (b.Length == 0)
return 0;
int res = b[0];
int pos = 1;
switch (b.Length)
{
case 1:
default:
return res;
case 2:
return res | b[pos] << (8 * pos++);
case 3:
return res | b[pos] << (8 * pos++) | b[pos] << (8 * pos++);
case 4:
return res | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++);
case 5:
return res | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++);
case 6:
return res | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++);
case 7:
return res | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++) | b[pos] << (8 * pos++);
}
}
/// <summary>
/// Returns an int32 from a byte array based on offset
/// </summary>