ZXHawk: Experimental PZX tape image support
This commit is contained in:
parent
5b0a41e31c
commit
50123bf8e2
|
@ -66,7 +66,7 @@ namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
RomData = FileData;
|
RomData = FileData;
|
||||||
}
|
}
|
||||||
else if (file.Extension == ".DSK" || file.Extension == ".TAP" || file.Extension == ".TZX")
|
else if (file.Extension == ".DSK" || file.Extension == ".TAP" || file.Extension == ".TZX" || file.Extension == ".PZX")
|
||||||
{
|
{
|
||||||
// these are not roms. unforunately if treated as such there are certain edge-cases
|
// these are not roms. unforunately 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
|
// where a header offset is detected. This should mitigate this issue until a cleaner solution is found
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF",
|
".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF",
|
||||||
".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX"
|
".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS", ".TZX", ".PZX"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2081,7 +2081,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
if (VersionInfo.DeveloperBuild)
|
if (VersionInfo.DeveloperBuild)
|
||||||
{
|
{
|
||||||
return FormatFilter(
|
return FormatFilter(
|
||||||
"Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;*.tzx;%ARCH%",
|
"Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;*.tzx;*.pzx;%ARCH%",
|
||||||
"Music Files", "*.psf;*.minipsf;*.sid;*.nsf",
|
"Music Files", "*.psf;*.minipsf;*.sid;*.nsf",
|
||||||
"Disc Images", "*.cue;*.ccd;*.mds;*.m3u",
|
"Disc Images", "*.cue;*.ccd;*.mds;*.m3u",
|
||||||
"NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%",
|
"NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%",
|
||||||
|
@ -2109,7 +2109,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
"Apple II", "*.dsk;*.do;*.po;%ARCH%",
|
"Apple II", "*.dsk;*.do;*.po;%ARCH%",
|
||||||
"Virtual Boy", "*.vb;%ARCH%",
|
"Virtual Boy", "*.vb;%ARCH%",
|
||||||
"Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%",
|
"Neo Geo Pocket", "*.ngp;*.ngc;%ARCH%",
|
||||||
"Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;%ARCH%",
|
"Sinclair ZX Spectrum", "*.tzx;*.tap;*.dsk;*.pzx;%ARCH%",
|
||||||
"All Files", "*.*");
|
"All Files", "*.*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -304,6 +304,7 @@ namespace BizHawk.Emulation.Common
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ".TZX":
|
case ".TZX":
|
||||||
|
case ".PZX":
|
||||||
game.System = "ZXSpectrum";
|
game.System = "ZXSpectrum";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -293,10 +293,11 @@
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\Disk\DiskType.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\Disk\DiskType.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\MediaConverter.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\MediaConverter.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\MediaConverterType.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\MediaConverterType.cs" />
|
||||||
|
<Compile Include="Computers\SinclairSpectrum\Media\Tape\PZX\PzxConverter.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapeCommand.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapeCommand.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapeDataBlock.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapeDataBlock.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TapConverter.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TAP\TapConverter.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TzxConverter.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Media\Tape\TZX\TzxConverter.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\SoundProviderMixer.cs" />
|
<Compile Include="Computers\SinclairSpectrum\SoundProviderMixer.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Machine\MachineType.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Machine\MachineType.cs" />
|
||||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.cs" />
|
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.cs" />
|
||||||
|
|
|
@ -320,8 +320,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
/// <param name="tapeData"></param>
|
/// <param name="tapeData"></param>
|
||||||
public void LoadTape(byte[] tapeData)
|
public void LoadTape(byte[] tapeData)
|
||||||
{
|
{
|
||||||
// check TZX first
|
// instantiate converters
|
||||||
TzxConverter tzxSer = new TzxConverter(this);
|
TzxConverter tzxSer = new TzxConverter(this);
|
||||||
|
TapConverter tapSer = new TapConverter(this);
|
||||||
|
PzxConverter pzxSer = new PzxConverter(this);
|
||||||
|
|
||||||
|
// TZX
|
||||||
if (tzxSer.CheckType(tapeData))
|
if (tzxSer.CheckType(tapeData))
|
||||||
{
|
{
|
||||||
// this file has a tzx header - attempt serialization
|
// this file has a tzx header - attempt serialization
|
||||||
|
@ -340,9 +344,30 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
"\n\nTape image file has a valid TZX header, but threw an exception whilst data was being parsed.\n\n" + e.ToString());
|
"\n\nTape image file has a valid TZX header, but threw an exception whilst data was being parsed.\n\n" + e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PZX
|
||||||
|
else if (pzxSer.CheckType(tapeData))
|
||||||
|
{
|
||||||
|
// this file has a pzx header - attempt serialization
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pzxSer.Read(tapeData);
|
||||||
|
// reset block index
|
||||||
|
CurrentDataBlockIndex = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// exception during operation
|
||||||
|
var e = ex;
|
||||||
|
throw new Exception(this.GetType().ToString() +
|
||||||
|
"\n\nTape image file has a valid PZX header, but threw an exception whilst data was being parsed.\n\n" + e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume TAP
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TapConverter tapSer = new TapConverter(this);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tapSer.Read(tapeData);
|
tapSer.Read(tapeData);
|
||||||
|
@ -383,7 +408,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
{
|
{
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if (counter > 50)
|
if (counter > 30)
|
||||||
{
|
{
|
||||||
counter = 0;
|
counter = 0;
|
||||||
bool state = GetEarBit(_machine.CPU.TotalExecutedCycles);
|
bool state = GetEarBit(_machine.CPU.TotalExecutedCycles);
|
||||||
|
@ -421,7 +446,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
}
|
}
|
||||||
|
|
||||||
// process the cycles based on the waitEdge
|
// process the cycles based on the waitEdge
|
||||||
while (cycles >= _waitEdge)
|
while (cycles >= _waitEdge)
|
||||||
{
|
{
|
||||||
// decrement cycles
|
// decrement cycles
|
||||||
cycles -= _waitEdge;
|
cycles -= _waitEdge;
|
||||||
|
@ -433,6 +458,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
{
|
{
|
||||||
// start of block
|
// start of block
|
||||||
|
|
||||||
|
//if (!_dataBlocks[_currentDataBlockIndex].InitialPulseLevel[_position])
|
||||||
|
//currentState = !currentState;
|
||||||
|
|
||||||
// notify about the current block
|
// notify about the current block
|
||||||
var bl = _dataBlocks[_currentDataBlockIndex];
|
var bl = _dataBlocks[_currentDataBlockIndex];
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
// spectrum .tzx tape file
|
// spectrum .tzx tape file
|
||||||
return SpectrumMediaType.Tape;
|
return SpectrumMediaType.Tape;
|
||||||
}
|
}
|
||||||
|
if (hdr.ToUpper().StartsWith("PZXT"))
|
||||||
|
{
|
||||||
|
// spectrum .tzx tape file
|
||||||
|
return SpectrumMediaType.Tape;
|
||||||
|
}
|
||||||
|
|
||||||
// if we get this far, assume a .tap file
|
// if we get this far, assume a .tap file
|
||||||
return SpectrumMediaType.Tape;
|
return SpectrumMediaType.Tape;
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
NONE,
|
NONE,
|
||||||
TZX,
|
TZX,
|
||||||
TAP,
|
TAP,
|
||||||
|
PZX,
|
||||||
DSK
|
DSK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,403 @@
|
||||||
|
using BizHawk.Common.NumberExtensions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reponsible for PZX format serializaton
|
||||||
|
/// Based on the information here: http://zxds.raxoft.cz/docs/pzx.txt
|
||||||
|
/// </summary>
|
||||||
|
public class PzxConverter : MediaConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of serializer
|
||||||
|
/// </summary>
|
||||||
|
private MediaConverterType _formatType = MediaConverterType.PZX;
|
||||||
|
public override MediaConverterType FormatType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _formatType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signs whether this class can be used to read the data format
|
||||||
|
/// </summary>
|
||||||
|
public override bool IsReader { get { return true; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signs whether this class can be used to write the data format
|
||||||
|
/// </summary>
|
||||||
|
public override bool IsWriter { get { return false; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Working list of generated tape data blocks
|
||||||
|
/// </summary>
|
||||||
|
private List<TapeDataBlock> _blocks = new List<TapeDataBlock>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Position counter
|
||||||
|
/// </summary>
|
||||||
|
private int _position = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Object to keep track of loops - this assumes there is only one loop at a time
|
||||||
|
/// </summary>
|
||||||
|
private List<KeyValuePair<int, int>> _loopCounter = new List<KeyValuePair<int, int>>();
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
|
||||||
|
private DatacorderDevice _datacorder;
|
||||||
|
|
||||||
|
public PzxConverter(DatacorderDevice _tapeDevice)
|
||||||
|
{
|
||||||
|
_datacorder = _tapeDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns TRUE if tzx header is detected
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
public override bool CheckType(byte[] data)
|
||||||
|
{
|
||||||
|
// PZX Header
|
||||||
|
|
||||||
|
// check whether this is a valid pzx format file by looking at the identifier in the header
|
||||||
|
// (first 4 bytes of the file)
|
||||||
|
string ident = Encoding.ASCII.GetString(data, 0, 4);
|
||||||
|
|
||||||
|
// version info
|
||||||
|
int majorVer = data[8];
|
||||||
|
int minorVer = data[9];
|
||||||
|
|
||||||
|
if (ident.ToUpper() != "PZXT")
|
||||||
|
{
|
||||||
|
// this is not a valid PZX format file
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DeSerialization method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
public override void Read(byte[] data)
|
||||||
|
{
|
||||||
|
// clear existing tape blocks
|
||||||
|
_datacorder.DataBlocks.Clear();
|
||||||
|
|
||||||
|
/*
|
||||||
|
// PZX uniform block layout
|
||||||
|
offset type name meaning
|
||||||
|
------ ---- ---- -------
|
||||||
|
0 u32 tag unique identifier for the block type.
|
||||||
|
4 u32 size size of the block in bytes, excluding the tag and size fields themselves.
|
||||||
|
8 u8[size] data arbitrary amount of block data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// check whether this is a valid pzx format file by looking at the identifier in the header block
|
||||||
|
string ident = Encoding.ASCII.GetString(data, 0, 4);
|
||||||
|
|
||||||
|
if (ident.ToUpper() != "PZXT")
|
||||||
|
{
|
||||||
|
// this is not a valid TZX format file
|
||||||
|
throw new Exception(this.GetType().ToString() +
|
||||||
|
"This is not a valid PZX format file");
|
||||||
|
}
|
||||||
|
|
||||||
|
_position = 0;
|
||||||
|
|
||||||
|
// parse all blocks out into seperate byte arrays first
|
||||||
|
List<byte[]> bDatas = new List<byte[]>();
|
||||||
|
|
||||||
|
while (_position < data.Length)
|
||||||
|
{
|
||||||
|
int startPos = _position;
|
||||||
|
|
||||||
|
// data size
|
||||||
|
_position += 4;
|
||||||
|
int blockSize = GetInt32(data, _position);
|
||||||
|
_position += 4;
|
||||||
|
|
||||||
|
// block data
|
||||||
|
byte[] bd = new byte[8 + blockSize];
|
||||||
|
Array.Copy(data, startPos, bd, 0, bd.Length);
|
||||||
|
bDatas.Add(bd);
|
||||||
|
|
||||||
|
_position += blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the blocks
|
||||||
|
foreach (var b in bDatas)
|
||||||
|
{
|
||||||
|
int pos = 8;
|
||||||
|
string blockId = Encoding.ASCII.GetString(b, 0, 4);
|
||||||
|
int blockSize = GetInt32(b, 4);
|
||||||
|
|
||||||
|
TapeDataBlock t = new TapeDataBlock();
|
||||||
|
|
||||||
|
switch (blockId)
|
||||||
|
{
|
||||||
|
// PZXT - PZX header block
|
||||||
|
/*
|
||||||
|
offset type name meaning
|
||||||
|
0 u8 major major version number (currently 1).
|
||||||
|
1 u8 minor minor version number (currently 0).
|
||||||
|
2 u8[?] info tape info, see below.
|
||||||
|
*/
|
||||||
|
case "PZXT":
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// PULS - Pulse sequence
|
||||||
|
/*
|
||||||
|
offset type name meaning
|
||||||
|
0 u16 count bits 0-14 optional repeat count (see bit 15), always greater than zero
|
||||||
|
bit 15 repeat count present: 0 not present 1 present
|
||||||
|
2 u16 duration1 bits 0-14 low/high (see bit 15) pulse duration bits
|
||||||
|
bit 15 duration encoding: 0 duration1 1 ((duration1<<16)+duration2)
|
||||||
|
4 u16 duration2 optional low bits of pulse duration (see bit 15 of duration1)
|
||||||
|
6 ... ... ditto repeated until the end of the block
|
||||||
|
*/
|
||||||
|
case "PULS":
|
||||||
|
|
||||||
|
t.BlockID = GetInt32(b, 0);
|
||||||
|
t.DataPeriods = new List<int>();
|
||||||
|
|
||||||
|
List<ushort[]> pulses = new List<ushort[]>();
|
||||||
|
|
||||||
|
while (pos < blockSize + 8)
|
||||||
|
{
|
||||||
|
ushort[] p = new ushort[2];
|
||||||
|
p[0] = 1;
|
||||||
|
p[1] = GetWordValue(b, pos);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
if (p[1] > 0x8000)
|
||||||
|
{
|
||||||
|
p[0] = (ushort)(p[1] & 0x7fff);
|
||||||
|
p[1] = GetWordValue(b, pos);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p[1] >= 0x8000)
|
||||||
|
{
|
||||||
|
p[1] &= 0x7fff;
|
||||||
|
p[1] <<= 16;
|
||||||
|
p[1] |= GetWordValue(b, pos);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pulses.Add(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to tape block
|
||||||
|
t.BlockDescription = BlockType.PULS;
|
||||||
|
t.PauseInMS = 0;
|
||||||
|
|
||||||
|
foreach (var x in pulses)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < x[0]; i++)
|
||||||
|
{
|
||||||
|
t.DataPeriods.Add(x[1]);
|
||||||
|
t.InitialPulseLevel.Add(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_datacorder.DataBlocks.Add(t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// DATA - Data block
|
||||||
|
/*
|
||||||
|
offset type name meaning
|
||||||
|
0 u32 count bits 0-30 number of bits in the data stream
|
||||||
|
bit 31 initial pulse level: 0 low 1 high
|
||||||
|
4 u16 tail duration of extra pulse after last bit of the block
|
||||||
|
6 u8 p0 number of pulses encoding bit equal to 0.
|
||||||
|
7 u8 p1 number of pulses encoding bit equal to 1.
|
||||||
|
8 u16[p0] s0 sequence of pulse durations encoding bit equal to 0.
|
||||||
|
8+2*p0 u16[p1] s1 sequence of pulse durations encoding bit equal to 1.
|
||||||
|
8+2*(p0+p1) u8[ceil(bits/8)] data data stream, see below.
|
||||||
|
*/
|
||||||
|
case "DATA":
|
||||||
|
|
||||||
|
t.BlockID = GetInt32(b, 0);
|
||||||
|
t.DataPeriods = new List<int>();
|
||||||
|
|
||||||
|
List<ushort> s0 = new List<ushort>();
|
||||||
|
List<ushort> s1 = new List<ushort>();
|
||||||
|
List<byte> dData = new List<byte>();
|
||||||
|
|
||||||
|
uint initPulseLevel = 1;
|
||||||
|
int dCount = 1;
|
||||||
|
ushort tail = 0;
|
||||||
|
|
||||||
|
while (pos < blockSize + 8)
|
||||||
|
{
|
||||||
|
dCount = GetInt32(b, pos);
|
||||||
|
initPulseLevel = (uint)((dCount & 0x80000000) == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
dCount = (int)(dCount & 0x7FFFFFFF);
|
||||||
|
pos += 4;
|
||||||
|
|
||||||
|
tail = GetWordValue(b, pos);
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
var p0 = b[pos++];
|
||||||
|
var p1 = b[pos++];
|
||||||
|
|
||||||
|
for (int i = 0; i < p1; i++)
|
||||||
|
{
|
||||||
|
var s = GetWordValue(b, pos);
|
||||||
|
pos += 2;
|
||||||
|
s0.Add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < p1; i++)
|
||||||
|
{
|
||||||
|
var s = GetWordValue(b, pos);
|
||||||
|
pos += 2;
|
||||||
|
s1.Add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Math.Ceiling((decimal)dCount / 8); i++)
|
||||||
|
{
|
||||||
|
var buff = b[pos++];
|
||||||
|
dData.Add(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initPulse = initPulseLevel == 1 ? true : false;
|
||||||
|
|
||||||
|
foreach (var by in dData)
|
||||||
|
{
|
||||||
|
for (int i = 7; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (by.Bit(i) == true)
|
||||||
|
{
|
||||||
|
foreach (var pu in s1)
|
||||||
|
{
|
||||||
|
t.DataPeriods.Add((int)pu);
|
||||||
|
t.InitialPulseLevel.Add(initPulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var pu in s0)
|
||||||
|
{
|
||||||
|
t.DataPeriods.Add((int)pu);
|
||||||
|
t.InitialPulseLevel.Add(initPulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dData.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to tape block
|
||||||
|
t.BlockDescription = BlockType.DATA;
|
||||||
|
t.PauseInMS = 0;
|
||||||
|
|
||||||
|
// tail
|
||||||
|
t.DataPeriods.Add(tail);
|
||||||
|
|
||||||
|
_datacorder.DataBlocks.Add(t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// PAUS - Pause
|
||||||
|
/*
|
||||||
|
offset type name meaning
|
||||||
|
0 u32 duration bits 0-30 duration of the pause
|
||||||
|
bit 31 initial pulse level: 0 low 1 high
|
||||||
|
*/
|
||||||
|
case "PAUS":
|
||||||
|
|
||||||
|
t.BlockID = GetInt32(b, 0);
|
||||||
|
t.DataPeriods = new List<int>();
|
||||||
|
|
||||||
|
int iniPulseLevel = 1;
|
||||||
|
int pCount = 0;
|
||||||
|
|
||||||
|
var d = GetInt32(b, pos);
|
||||||
|
iniPulseLevel = ((d & 0x80000000) == 0 ? 0 : 1);
|
||||||
|
pCount = (d & 0x7FFFFFFF);
|
||||||
|
|
||||||
|
// convert to tape block
|
||||||
|
t.BlockDescription = BlockType.PAUS;
|
||||||
|
t.DataPeriods.Add(pCount);
|
||||||
|
|
||||||
|
if (iniPulseLevel == 1)
|
||||||
|
t.InitialPulseLevel.Add(true);
|
||||||
|
else
|
||||||
|
t.InitialPulseLevel.Add(false);
|
||||||
|
|
||||||
|
_datacorder.DataBlocks.Add(t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// BRWS - Browse point
|
||||||
|
/*
|
||||||
|
offset type name meaning
|
||||||
|
0 u8[?] text text describing this browse point
|
||||||
|
*/
|
||||||
|
case "BRWS":
|
||||||
|
|
||||||
|
t.BlockID = GetInt32(b, 0);
|
||||||
|
t.DataPeriods = new List<int>();
|
||||||
|
|
||||||
|
string info = Encoding.ASCII.GetString(b, 8, blockSize);
|
||||||
|
|
||||||
|
// convert to tape block
|
||||||
|
t.BlockDescription = BlockType.BRWS;
|
||||||
|
t.MetaData.Add(BlockDescriptorTitle.Comments, info);
|
||||||
|
t.PauseInMS = 0;
|
||||||
|
|
||||||
|
_datacorder.DataBlocks.Add(t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// STOP - Stop tape command
|
||||||
|
/*
|
||||||
|
offset type name meaning
|
||||||
|
0 u16 flags when exactly to stop the tape (1 48k only, other always).
|
||||||
|
*/
|
||||||
|
case "STOP":
|
||||||
|
|
||||||
|
|
||||||
|
t.BlockID = GetInt32(b, 0);
|
||||||
|
t.DataPeriods = new List<int>();
|
||||||
|
|
||||||
|
var flags = GetWordValue(b, pos);
|
||||||
|
if (flags == 1)
|
||||||
|
{
|
||||||
|
t.BlockDescription = BlockType.Stop_the_Tape_48K;
|
||||||
|
t.Command = TapeCommand.STOP_THE_TAPE_48K;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t.BlockDescription = BlockType.Pause_or_Stop_the_Tape;
|
||||||
|
t.Command = TapeCommand.STOP_THE_TAPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_datacorder.DataBlocks.Add(t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -113,6 +113,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<int> DataPeriods = new List<int>();
|
public List<int> DataPeriods = new List<int>();
|
||||||
|
|
||||||
|
public List<bool> InitialPulseLevel = new List<bool>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command that is raised by this data block
|
/// Command that is raised by this data block
|
||||||
/// (that may or may not need to be acted on)
|
/// (that may or may not need to be acted on)
|
||||||
|
@ -229,8 +231,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||||
Snapshot_Block = 0x40,
|
Snapshot_Block = 0x40,
|
||||||
|
|
||||||
// unsupported / undetected
|
// unsupported / undetected
|
||||||
Unsupported
|
Unsupported,
|
||||||
|
|
||||||
|
// PZX blocks
|
||||||
|
PZXT,
|
||||||
|
PULS,
|
||||||
|
DATA,
|
||||||
|
BRWS,
|
||||||
|
PAUS
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Different title possibilities
|
/// Different title possibilities
|
||||||
|
|
Loading…
Reference in New Issue