Started new port contention methods and increased the auto-tape monitor timeout (to eliminate false-positive stops)

This commit is contained in:
Asnivor 2018-03-12 10:19:42 +00:00
parent 8708e987f7
commit ae8b030e57
4 changed files with 121 additions and 107 deletions

View File

@ -144,74 +144,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// Primary purpose is to detect tape traps and manage auto play (if/when this is ever implemented)
/// </summary>
public void EndFrame()
{/*
if (TapeIsPlaying)
{
// check whether we need to auto-stop the tape
if (IsMachineAtErrorAddress())
{
_machine.Spectrum.OSD_TapeStoppedAuto();
Stop();
}
}
else
{
// the tape is not playing - check to see if we need to autostart the tape
if (IsMachineInLoadMode())
{
_machine.Spectrum.OSD_TapePlayingAuto();
Play();
//sw.Start();
}
}
/*
if (TapeIsPlaying && sw.IsRunning)
{
if (!IsMachineInLoadMode() && sw.ElapsedMilliseconds == 2000)
{
sw.Stop();
sw.Reset();
_machine.Spectrum.OSD_TapeStoppedAuto();
Stop();
}
}
*/
{
MonitorFrame();
}
/// <summary>
/// Checks whether the machine is in a state that is waiting to load tape content
/// </summary>
/// <returns></returns>
public bool IsMachineInLoadMode()
{
if (!_machine.Spectrum.Settings.AutoLoadTape)
return false;
if (_cpu.RegPC == 1523)
return true;
return false;
}
/// <summary>
/// Checks whether the machine has reached the error rom address (and the tape needs to be stopped)
/// </summary>
/// <returns></returns>
private bool IsMachineAtErrorAddress()
{
//if (!_machine.Spectrum.Settings.AutoLoadTape)
//return false;
if (_cpu.RegPC == 64464) // 40620) // ERROR_ROM_ADDRESS)
return true;
else
return false;
}
#endregion
#region Tape Controls
@ -656,7 +592,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
_machine.Spectrum.OSD_TapePlayingAuto();
}
_monitorTimeOut = 50;
_monitorTimeOut = 500;
}
}
else
@ -676,6 +612,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
_monitorTimeOut--;
if (_monitorTimeOut < 2)
{
}
if (_monitorTimeOut < 0)
{
Stop();
@ -688,8 +629,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
#region State Serialization
private int _tempBlockCount;
/// <summary>
/// Bizhawk state serialization
/// </summary>

View File

@ -39,6 +39,82 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
CPU.TotalExecutedCycles += tStates;
}
/// <summary>
/// Simulates IO port contention based on the supplied address
/// This method is for 48k machines and should be overridden for other models
/// </summary>
/// <param name="addr"></param>
public virtual void ContendPortAddress(ushort addr)
{
/*
It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port. As is the case with memory access,
this can be lengthened by the ULA. There are two effects which occur here:
If the port address being accessed has its low bit reset, the ULA is required to supply the result, which leads to a delay if it is
currently busy handling the screen.
The address of the port being accessed is placed on the data bus. If this is in the range 0x4000 to 0x7fff, the ULA treats this as an
attempted access to contended memory and therefore introduces a delay. If the port being accessed is between 0xc000 and 0xffff,
this effect does not apply, even on a 128K machine if a contended memory bank is paged into the range 0xc000 to 0xffff.
These two effects combine to lead to the following contention patterns:
High byte | |
in 40 - 7F? | Low bit | Contention pattern
------------+---------+-------------------
No | Reset | N:1, C:3
No | Set | N:4
Yes | Reset | C:1, C:3
Yes | Set | C:1, C:1, C:1, C:1
The 'Contention pattern' column should be interpreted from left to right. An "N:n" entry means that no delay is applied at this cycle, and the Z80 continues uninterrupted for 'n' T states. A "C:n" entry means that the ULA halts the Z80; the delay is exactly the same as would occur for a contended memory access at this cycle (eg 6 T states at cycle 14335, 5 at 14336, etc on the 48K machine). After this delay, the Z80 then continues for 'n' cycles.
*/
// is the low bit reset (i.e. is this addressing the ULA)?
bool lowBit = (addr & 0x0001) != 0;
if ((addr & 0xc000) == 0x4000 || (addr & 0xc000) == 0xC000)
{
// high byte is in 40 - 7F
if (lowBit)
{
// lowbit is set
// C:1, C:1, C:1, C:1
for (int i = 0; i < 4; i++)
{
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
CPU.TotalExecutedCycles++;
}
}
else
{
// low bit is reset
// C:1, C:3
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
CPU.TotalExecutedCycles++;
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
CPU.TotalExecutedCycles += 3;
}
}
else
{
// high byte is NOT in 40 - 7F
if (lowBit)
{
// lowbit is set
// C:1, C:1, C:1, C:1
CPU.TotalExecutedCycles += 4;
}
else
{
// lowbit is reset
// N:1, C:3
CPU.TotalExecutedCycles++;
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
CPU.TotalExecutedCycles += 3;
}
}
}
}
}

View File

@ -17,10 +17,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
InputRead = true;
// It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port
// (not including added ULA contention)
// The Bizhawk Z80A implementation appears to not consume any T-States for this operation
PortContention(4);
// process IO contention
ContendPortAddress(port);
int result = 0xFF;
@ -28,8 +26,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// Technically the ULA should respond to every even I/O address
bool lowBitReset = (port & 0x0001) == 0;
ULADevice.Contend(port);
// Kempston Joystick
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
{
@ -90,12 +86,22 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
if ((port & 0x100) == 0)
{
result &= KeyboardDevice.KeyLine[0];
}
}
TapeDevice.MonitorRead();
var earBit = TapeDevice.GetEarBit(CPU.TotalExecutedCycles);
if (!earBit)
{
result &= 0xbf;
}
/*
result = result & 0x1f; //mask out lower 4 bits
result = result | 0xa0; //set bit 5 & 7 to 1
TapeDevice.MonitorRead();
if (TapeDevice.TapeIsPlaying)//.CurrentMode == TapeOperationMode.Load)
{
@ -133,7 +139,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
}
}
}
*/
}
else
{
@ -177,45 +183,37 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// <param name="value"></param>
public override void WritePort(ushort port, byte value)
{
// It takes four T states for the Z80 to read a value from an I/O port, or write a value to a port
// (not including added ULA contention)
// The Bizhawk Z80A implementation appears to not consume any T-States for this operation
PortContention(4);
// process IO contention
ContendPortAddress(port);
// Check whether the low bit is reset
// Technically the ULA should respond to every even I/O address
bool lowBitReset = (port & 0x01) == 0;
if ((port & 0x0001) != 0)
return;
ULADevice.Contend(port);
// store the last OUT byte
LastULAOutByte = value;
// Only even addresses address the ULA
if (lowBitReset)
{
// store the last OUT byte
LastULAOutByte = value;
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
/*
Bit 7 6 5 4 3 2 1 0
+-------------------------------+
| | | | E | M | Border |
+-------------------------------+
*/
/*
Bit 7 6 5 4 3 2 1 0
+-------------------------------+
| | | | E | M | Border |
+-------------------------------+
*/
// Border - LSB 3 bits hold the border colour
if (ULADevice.borderColour != (value & BORDER_BIT))
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
// Border - LSB 3 bits hold the border colour
if (ULADevice.borderColour != (value & BORDER_BIT))
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
ULADevice.borderColour = value & BORDER_BIT;
ULADevice.borderColour = value & BORDER_BIT;
// Buzzer
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
// Buzzer
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
// Tape
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
// Tape
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
}
}
}
}

View File

@ -268,6 +268,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
t.DataPeriods = new List<int>();
int pauseLen = GetWordValue(data, _position);
int blockLen = GetWordValue(data, _position + 2);
_position += 4;