ZXHawk: Overhaul datacorder and cassette loading code. This should now be more accurate and fixes a number of loading isues with particular games and loading schemes. There be desync dragons here!! Fixes #1446
This commit is contained in:
parent
160217ef74
commit
51a67a947a
|
@ -122,14 +122,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
MonitorFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No longer in use
|
||||
/// </summary>
|
||||
public void StartFrame()
|
||||
{
|
||||
//_buzzer.ProcessPulseValue(currentState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the tape playing from the beginning of the current block
|
||||
/// </summary>
|
||||
|
@ -466,27 +458,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
cycles -= _waitEdge;
|
||||
|
||||
if (_position == 0 && _tapeIsPlaying)
|
||||
{
|
||||
// start of block - take care of initial pulse level for PZX
|
||||
switch (_dataBlocks[_currentDataBlockIndex].BlockDescription)
|
||||
{
|
||||
case BlockType.PULS:
|
||||
// initial pulse level is always low
|
||||
if (currentState)
|
||||
FlipTapeState();
|
||||
break;
|
||||
case BlockType.DATA:
|
||||
// initial pulse level is stored in block
|
||||
if (currentState != _dataBlocks[_currentDataBlockIndex].InitialPulseLevel)
|
||||
FlipTapeState();
|
||||
break;
|
||||
case BlockType.PAUS:
|
||||
// initial pulse level is stored in block
|
||||
if (currentState != _dataBlocks[_currentDataBlockIndex].InitialPulseLevel)
|
||||
FlipTapeState();
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
// notify about the current block
|
||||
var bl = _dataBlocks[_currentDataBlockIndex];
|
||||
|
||||
|
@ -595,7 +567,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
_waitEdge = _dataBlocks[_currentDataBlockIndex].DataPeriods.Count > 0 ? _dataBlocks[_currentDataBlockIndex].DataPeriods[_position] : 0;
|
||||
|
||||
// flip the current state
|
||||
FlipTapeState();
|
||||
//FlipTapeState();
|
||||
currentState = _dataBlocks[_currentDataBlockIndex].DataLevels[_position];
|
||||
}
|
||||
|
||||
// update lastCycle and return currentstate
|
||||
|
|
|
@ -208,17 +208,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
CPU.RegPC = 0;
|
||||
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IY", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IX", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IY", 0);
|
||||
Spectrum.SetCpuRegister("IX", 0);
|
||||
Spectrum.SetCpuRegister("AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("HL", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("BC", 0);
|
||||
Spectrum.SetCpuRegister("DE", 0);
|
||||
Spectrum.SetCpuRegister("HL", 0);
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow HL", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow BC", 0);
|
||||
Spectrum.SetCpuRegister("Shadow DE", 0);
|
||||
Spectrum.SetCpuRegister("Shadow HL", 0);
|
||||
|
||||
CPU.Regs[CPU.I] = 0;
|
||||
CPU.Regs[CPU.R] = 0;
|
||||
|
@ -260,17 +260,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
CPU.RegPC = 0;
|
||||
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IY", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("IX", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("IY", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("IX", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("HL", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("SP", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("BC", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("DE", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("HL", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow AF", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow BC", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow DE", 0xFFFF);
|
||||
Spectrum.SetCpuRegister("Shadow HL", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("Shadow BC", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("Shadow DE", 0xFFFF);
|
||||
//Spectrum.SetCpuRegister("Shadow HL", 0xFFFF);
|
||||
|
||||
CPU.Regs[CPU.I] = 0;
|
||||
CPU.Regs[CPU.R] = 0;
|
||||
|
|
|
@ -145,15 +145,35 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// Takes a PauseInMilliseconds value and returns the value in T-States
|
||||
/// </summary>
|
||||
public static int TranslatePause(int pauseInMS)
|
||||
{
|
||||
// t-states per millisecond
|
||||
var tspms = (69888 * 50) / 1000;
|
||||
// get value
|
||||
int res = pauseInMS * tspms;
|
||||
{
|
||||
var tspms = (double)(69888 * 50) / (double)1000;
|
||||
int res = (int)(pauseInMS * tspms);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caluclate a data block XOR checksum
|
||||
/// </summary>
|
||||
/// <param name="buf"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CheckChecksum(byte[] buf, int len)
|
||||
{
|
||||
byte c = 0;
|
||||
for (int n = 0; n < len - 1; n++)
|
||||
{
|
||||
c ^= buf[n];
|
||||
}
|
||||
|
||||
if (c == buf[len - 1])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompresses a byte array that is Z-RLE compressed
|
||||
/// </summary>
|
||||
|
|
|
@ -197,12 +197,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
t.BlockDescription = BlockType.CSW_Recording;
|
||||
t.BlockID = 0x18;
|
||||
t.DataPeriods = new List<int>();
|
||||
t.DataLevels = new List<bool>();
|
||||
|
||||
if (flags.Bit(0))
|
||||
t.InitialPulseLevel = true;
|
||||
else
|
||||
t.InitialPulseLevel = false;
|
||||
|
||||
bool currLevel = !t.InitialPulseLevel;
|
||||
|
||||
var rate = (69888 * 50) / sampleRate;
|
||||
|
||||
for (int i = 0; i < cswDataUncompressed.Length;)
|
||||
|
@ -215,10 +218,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
|
||||
t.DataPeriods.Add(length);
|
||||
|
||||
currLevel = !currLevel;
|
||||
t.DataLevels.Add(currLevel);
|
||||
}
|
||||
|
||||
// add closing period
|
||||
t.DataPeriods.Add((69888 * 50) / 10);
|
||||
currLevel = !currLevel;
|
||||
t.DataLevels.Add(currLevel);
|
||||
|
||||
// add to datacorder
|
||||
_datacorder.DataBlocks.Add(t);
|
||||
|
|
|
@ -158,8 +158,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
t.BlockID = GetInt32(b, 0);
|
||||
t.DataPeriods = new List<int>();
|
||||
t.DataLevels = new List<bool>();
|
||||
|
||||
t.InitialPulseLevel = false;
|
||||
bool pLevel = !t.InitialPulseLevel;
|
||||
|
||||
List<ushort[]> pulses = new List<ushort[]>();
|
||||
|
||||
|
@ -197,6 +199,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
for (int i = 0; i < x[0]; i++)
|
||||
{
|
||||
t.DataPeriods.Add(x[1]);
|
||||
pLevel = !pLevel;
|
||||
t.DataLevels.Add(pLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +224,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
t.BlockID = GetInt32(b, 0);
|
||||
t.DataPeriods = new List<int>();
|
||||
t.DataLevels = new List<bool>();
|
||||
|
||||
List<ushort> s0 = new List<ushort>();
|
||||
List<ushort> s1 = new List<ushort>();
|
||||
|
@ -235,6 +240,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
initPulseLevel = (uint)((dCount & 0x80000000) == 0 ? 0 : 1);
|
||||
|
||||
t.InitialPulseLevel = initPulseLevel == 1;
|
||||
bool bLevel = !t.InitialPulseLevel;
|
||||
|
||||
dCount = (int)(dCount & 0x7FFFFFFF);
|
||||
pos += 4;
|
||||
|
@ -274,6 +280,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
foreach (var pu in s1)
|
||||
{
|
||||
t.DataPeriods.Add((int)pu);
|
||||
bLevel = !bLevel;
|
||||
t.DataLevels.Add(bLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -282,13 +290,20 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
foreach (var pu in s0)
|
||||
{
|
||||
t.DataPeriods.Add((int)pu);
|
||||
bLevel = !bLevel;
|
||||
t.DataLevels.Add(bLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tail > 0)
|
||||
{
|
||||
t.DataPeriods.Add(tail);
|
||||
bLevel = !bLevel;
|
||||
t.DataLevels.Add(bLevel);
|
||||
}
|
||||
|
||||
dData.Clear();
|
||||
}
|
||||
|
||||
|
@ -320,12 +335,21 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
var d = GetInt32(b, pos);
|
||||
iniPulseLevel = ((d & 0x80000000) == 0 ? 0 : 1);
|
||||
t.InitialPulseLevel = iniPulseLevel == 1;
|
||||
bool paLevel = !t.InitialPulseLevel;
|
||||
pCount = (d & 0x7FFFFFFF);
|
||||
|
||||
// convert to tape block
|
||||
t.BlockDescription = BlockType.PAUS;
|
||||
paLevel = !paLevel;
|
||||
t.DataLevels.Add(paLevel);
|
||||
t.DataPeriods.Add(0);
|
||||
|
||||
paLevel = !paLevel;
|
||||
t.DataLevels.Add(paLevel);
|
||||
t.DataPeriods.Add(pCount);
|
||||
|
||||
paLevel = !paLevel;
|
||||
t.DataLevels.Add(paLevel);
|
||||
t.DataPeriods.Add(0);
|
||||
|
||||
_datacorder.DataBlocks.Add(t);
|
||||
|
|
|
@ -277,16 +277,25 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
// create a list to hold the data periods
|
||||
List<int> dataPeriods = new List<int>();
|
||||
List<bool> dataLevels = new List<bool>();
|
||||
|
||||
bool currLevel = false;
|
||||
|
||||
// generate pilot pulses
|
||||
for (int i = 0; i < pilotLength; i++)
|
||||
{
|
||||
dataPeriods.Add(PILOT_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
|
||||
// add syncro pulses
|
||||
dataPeriods.Add(SYNC_1_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
dataPeriods.Add(SYNC_2_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
|
||||
int pos = 0;
|
||||
|
||||
|
@ -296,13 +305,33 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
for (byte b = 0x80; b != 0; b >>= 1)
|
||||
{
|
||||
if ((blockdata[i] & b) != 0)
|
||||
{
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
|
||||
if ((blockdata[i] & b) != 0)
|
||||
{
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,13 +339,29 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
for (byte c = 0x80; c != (byte)(0x80 >> BIT_COUNT_IN_LAST); c >>= 1)
|
||||
{
|
||||
if ((blockdata[pos] & c) != 0)
|
||||
{
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
if ((blockdata[pos] & c) != 0)
|
||||
{
|
||||
dataPeriods.Add(BIT_1_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPeriods.Add(BIT_0_PL);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
}
|
||||
}
|
||||
|
||||
// add block pause
|
||||
|
@ -325,14 +370,27 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
// default pause for tap files
|
||||
tdb.PauseInMS = 1000;
|
||||
tdb.PauseInTStates = TranslatePause(tdb.PauseInMS);
|
||||
|
||||
// small inversion
|
||||
dataPeriods.Add(3476);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
|
||||
// actual pause
|
||||
dataPeriods.Add(tdb.PauseInTStates - 3476);
|
||||
currLevel = !currLevel;
|
||||
dataLevels.Add(currLevel);
|
||||
|
||||
// add to the tapedatablock object
|
||||
tdb.DataPeriods = dataPeriods;
|
||||
tdb.DataLevels = dataLevels;
|
||||
|
||||
// add the raw data
|
||||
tdb.BlockData = blockdata;
|
||||
|
||||
// generate separate PAUS block
|
||||
/*
|
||||
TapeDataBlock tdbPause = new TapeDataBlock();
|
||||
tdbPause.DataPeriods = new List<int>();
|
||||
tdbPause.BlockDescription = BlockType.PAUSE_BLOCK;
|
||||
|
@ -341,10 +399,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
//if (pauseInTStates > 0)
|
||||
//tdbPause.DataPeriods.Add(pauseInTStates);
|
||||
tdb.PauseInMS = 0;
|
||||
tdb.PauseInTStates = pauseInTStates;
|
||||
*/
|
||||
|
||||
// add block to the tape
|
||||
_datacorder.DataBlocks.Add(tdb);
|
||||
|
||||
/*
|
||||
// PAUS block if neccessary
|
||||
if (pauseInTStates > 0)
|
||||
{
|
||||
|
@ -366,6 +427,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
_datacorder.DataBlocks.Add(tdbPause);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// </summary>
|
||||
public class TapeDataBlock
|
||||
{
|
||||
public TapeDataBlock()
|
||||
{
|
||||
DataPeriods = new List<int>();
|
||||
DataLevels = new List<bool>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Either the TZX block ID, or -1 in the case of non-tzx blocks
|
||||
/// </summary>
|
||||
|
@ -77,6 +83,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// </summary>
|
||||
public List<int> DataPeriods = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// List containing the pulse levels (in relation to the pulse timing values)
|
||||
/// </summary>
|
||||
public List<bool> DataLevels = new List<bool>();
|
||||
|
||||
public List<string> PulseDescription = new List<string>();
|
||||
|
||||
public bool InitialPulseLevel;
|
||||
|
||||
/// <summary>
|
||||
|
@ -91,7 +104,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// The defined post-block pause
|
||||
/// The defined post-block pause in MS
|
||||
/// </summary>
|
||||
private int _pauseInMS;
|
||||
public int PauseInMS
|
||||
|
@ -100,6 +113,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
set => _pauseInMS = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The defined post-block pause in T-States
|
||||
/// </summary>
|
||||
private int _pauseInTStates;
|
||||
public int PauseInTStates
|
||||
{
|
||||
get { return _pauseInTStates; }
|
||||
set { _pauseInTStates = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data periods as an array
|
||||
|
@ -226,6 +248,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
Pulse_Length,
|
||||
Pulse_Count,
|
||||
|
||||
TStatesPerSample,
|
||||
|
||||
Archive_Info,
|
||||
Custom_Info,
|
||||
Text_Description,
|
||||
Title,
|
||||
Publisher,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
|
@ -85,7 +86,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
WavStreamReader reader = new WavStreamReader(stream);
|
||||
|
||||
int rate = (69888 * 50) / reader.Header.sampleRate;
|
||||
//int rate = (int)(((double)69888 * (double)50) / (double)reader.Header.sampleRate);
|
||||
int rate = (int)((double)(3500000) / (double)reader.Header.sampleRate);
|
||||
int smpCounter = 0;
|
||||
int state = reader.ReadNext();
|
||||
|
||||
|
@ -94,6 +96,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
t.BlockDescription = BlockType.WAV_Recording;
|
||||
t.BlockID = 0;
|
||||
t.DataPeriods = new List<int>();
|
||||
t.DataLevels = new List<bool>();
|
||||
|
||||
bool currLevel = false;
|
||||
|
||||
for (int i = 0; i < reader.Count; i++)
|
||||
{
|
||||
|
@ -101,16 +106,33 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
smpCounter++;
|
||||
if ((state < 0 && sample < 0) || (state >= 0 && sample >= 0))
|
||||
continue;
|
||||
t.DataPeriods.Add(smpCounter * rate);
|
||||
t.DataPeriods.Add((int)(((double)smpCounter * (double)rate) / (double)0.9838560885608856));
|
||||
currLevel = !currLevel;
|
||||
t.DataLevels.Add(currLevel);
|
||||
smpCounter = 0;
|
||||
state = sample;
|
||||
}
|
||||
|
||||
// add closing period
|
||||
t.DataPeriods.Add((69888 * 50) / 10);
|
||||
currLevel = false;
|
||||
t.DataLevels.Add(currLevel);
|
||||
|
||||
// add to datacorder
|
||||
_datacorder.DataBlocks.Add(t);
|
||||
|
||||
StringBuilder export = new StringBuilder();
|
||||
foreach (var b in _datacorder.DataBlocks)
|
||||
{
|
||||
for (int i = 0; i < b.DataPeriods.Count(); i++)
|
||||
{
|
||||
export.Append(b.DataPeriods[i].ToString());
|
||||
export.Append("\t\t");
|
||||
export.AppendLine(b.DataLevels[i].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
string o = export.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue