ZXHawk: New interrupt implementation

This commit is contained in:
Asnivor 2018-06-11 14:35:12 +01:00
parent c47860fad7
commit fbba7c25ae
6 changed files with 104 additions and 127 deletions

View File

@ -61,6 +61,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// </summary>
public void ExecuteCycle()
{
// simulate the ULA clock cycle before the CPU cycle
_machine.ULADevice.CycleClock(TotalExecutedCycles);
// is the next CPU cycle causing a BUSRQ or IORQ?
if (BUSRQ > 0)
{

View File

@ -147,6 +147,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// </summary>
public virtual void ExecuteFrame(bool render, bool renderSound)
{
ULADevice.FrameEnd = false;
ULADevice.ULACycleCounter = CurrentFrameCycle;
InputRead = false;
_render = render;
_renderSound = renderSound;
@ -164,15 +167,18 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
PollInput();
while (CurrentFrameCycle < ULADevice.FrameLength)
for (;;)
{
ULADevice.CheckForInterrupt(CurrentFrameCycle);
// run the CPU Monitor cycle
CPUMon.ExecuteCycle();
// cycle the tape device
if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded)
TapeDevice.TapeCycle();
// has frame end been reached?
if (ULADevice.FrameEnd)
break;
}
OverFlow = (int)CurrentFrameCycle - ULADevice.FrameLength;
@ -190,9 +196,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
AYDevice.EndFrame();
FrameCount++;
// setup for next frame
ULADevice.ResetInterrupt();
if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded)
TapeDevice.EndFrame();
@ -202,8 +205,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// is this a lag frame?
Spectrum.IsLagFrame = !InputRead;
// FDC debug
// FDC debug
if (UPDDiskDevice != null && UPDDiskDevice.writeDebug)
{
// only write UPD log every second
@ -222,7 +224,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// </summary>
public virtual void HardReset()
{
ULADevice.ResetInterrupt();
//ULADevice.ResetInterrupt();
ROMPaged = 0;
SpecialPagingMode = false;
RAMPaged = 0;
@ -274,7 +276,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// </summary>
public virtual void SoftReset()
{
ULADevice.ResetInterrupt();
//ULADevice.ResetInterrupt();
ROMPaged = 0;
SpecialPagingMode = false;
RAMPaged = 0;

View File

@ -89,14 +89,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
public int InterruptLength;
/// <summary>
/// Arbitrary offset into the contention array (for memory ops)
/// </summary>
public int MemoryContentionOffset;
/// <summary>
/// Arbitrary offset into the contention array (for port ops)
/// </summary>
public int PortContentionOffset;
/// Contention offset
/// </summary>
public int ContentionOffset;
/// <summary>
/// Arbitrary offset for render table generation
@ -137,60 +132,58 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// </summary>
protected bool InterruptRaised;
/// <summary>
/// Signs that the interrupt signal has been revoked
/// </summary>
protected bool InterruptRevoked;
public long ULACycleCounter;
public long LastULATick;
public bool FrameEnd;
/// <summary>
/// Resets the interrupt - this should happen every frame in order to raise
/// the VBLANK interrupt in the proceding frame
/// </summary>
public virtual void ResetInterrupt()
{
InterruptRaised = false;
InterruptRevoked = false;
}
/// <summary>
/// Generates an interrupt in the current phase if needed
/// Cycles the ULA clock
/// Handles interrupt generation
/// </summary>
/// <param name="currentCycle"></param>
public virtual void CheckForInterrupt(long currentCycle)
public virtual void CycleClock(long totalCycles)
{
if (InterruptRevoked)
// has more than one cycle past since this last ran
// (this can be true if contention has taken place)
var ticksToProcess = totalCycles - LastULATick;
// store the current cycle
LastULATick = totalCycles;
// process the cycles past as well as the upcoming one
for (int i = 0; i < ticksToProcess; i++)
{
// interrupt has already been handled
return;
}
ULACycleCounter++;
if (currentCycle <= InterruptStartTime)
{
// interrupt does not need to be raised yet
return;
}
if (currentCycle > InterruptStartTime + InterruptLength)
{
// interrupt should have already been raised and the cpu may or
// may not have caught it. The time has passed so revoke the signal
InterruptRevoked = true;
_machine.CPU.FlagI = false;
return;
}
if (InterruptRaised)
{
// INT is raised but not yet revoked
// CPU has NOT handled it yet
return;
}
// Raise the interrupt
InterruptRaised = true;
_machine.CPU.FlagI = true;
CalcFlashCounter();
if (InterruptRaised)
{
// /INT pin is currently being held low
if (ULACycleCounter < InterruptLength + InterruptStartTime)
{
// ULA should still hold the /INT pin low
_machine.CPU.FlagI = true;
}
else
{
// its time (or past time) to stop holding the /INT pin low
_machine.CPU.FlagI = false;
InterruptRaised = false;
}
}
else
{
// interrupt is currently not raised
if (ULACycleCounter == FrameLength + InterruptStartTime)
{
// time to raise the interrupt
InterruptRaised = true;
_machine.CPU.FlagI = true;
FrameEnd = true;
ULACycleCounter = InterruptStartTime;
CalcFlashCounter();
}
}
}
}
/// <summary>
@ -329,7 +322,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
for (var t = 0; t < _ula.FrameCycleLength; t++)
{
var tStateScreen = t + _ula.RenderTableOffset + _ula.InterruptStartTime;
var tStateScreen = t + _ula.RenderTableOffset;// + _ula.InterruptStartTime;
if (tStateScreen < 0)
tStateScreen += _ula.FrameCycleLength;
@ -460,7 +453,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// calculate contention values
for (int t = 0; t < _ula.FrameCycleLength; t++)
{
int shifted = t + _ula.RenderTableOffset + _ula.InterruptStartTime;
int shifted = t + _ula.RenderTableOffset + _ula.ContentionOffset; // _ula.InterruptStartTime;
if (shifted < 0)
shifted += _ula.FrameCycleLength;
shifted %= _ula.FrameCycleLength;
@ -747,7 +740,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// <returns></returns>
public int GetContentionValue(int tstate)
{
tstate += MemoryContentionOffset;
//tstate += MemoryContentionOffset;
if (tstate >= FrameCycleLength)
tstate -= FrameCycleLength;
@ -763,7 +756,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// <returns></returns>
public int GetPortContentionValue(int tstate)
{
tstate += PortContentionOffset;
//tstate += PortContentionOffset;
if (tstate >= FrameCycleLength)
tstate -= FrameCycleLength;
@ -994,8 +987,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
ser.BeginSection("ULA");
if (ScreenBuffer != null)
ser.Sync("ScreenBuffer", ref ScreenBuffer, false);
ser.Sync("FrameLength", ref FrameCycleLength);
ser.Sync("ClockSpeed", ref ClockSpeed);
ser.Sync("BorderColor", ref BorderColor);
ser.Sync("LastTState", ref LastTState);
ser.Sync("flashOn", ref flashOn);
@ -1010,6 +1001,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
ser.Sync("flash", ref flash);
ser.Sync("palPaper", ref palPaper);
ser.Sync("palInk", ref palInk);
ser.Sync("LastULATick", ref LastULATick);
ser.Sync("ULACycleCounter", ref ULACycleCounter);
ser.Sync("FrameEnd", ref FrameEnd);
ser.EndSection();
}

View File

@ -13,32 +13,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
public Screen128(SpectrumBase machine)
: base(machine)
{
// interrupt
InterruptStartTime = 3;
InterruptLength = 36;
// offsets
RenderTableOffset = 58;
ContentionOffset = 6;
FloatingBusOffset = 1;
// timing
ClockSpeed = 3546900;
FrameCycleLength = 70908;
InterruptStartTime = 34;
InterruptLength = 36;
ScanlineTime = 228;
MemoryContentionOffset = 6;
PortContentionOffset = 6;
RenderTableOffset = -4;
FloatingBusOffset = 1;
BorderLeftTime = 24;
BorderRightTime = 24;
FirstPaperLine = 63;
FirstPaperTState = 64;
Border4T = true;
Border4TStage = 2;
// screen layout
Border4T = true;
Border4TStage = 2;
ScreenWidth = 256;
ScreenHeight = 192;
BorderTopHeight = 55; // 48;
BorderBottomHeight = 56;
BorderTopHeight = 48; // 55; // 48;
BorderBottomHeight = 48; // 56;
BorderLeftWidth = 48;
BorderRightWidth = 48;
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;

View File

@ -13,43 +13,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
public Screen128Plus2a(SpectrumBase machine)
: base(machine)
{
// interrupt
InterruptStartTime = 0;
InterruptLength = 32;
// offsets
RenderTableOffset = 58;
ContentionOffset = 9;
FloatingBusOffset = 1;
// timing
ClockSpeed = 3546900;
FrameCycleLength = 70908;
/*
InterruptStartTime = 31;
InterruptLength = 32;
ScanlineTime = 228;
MemoryContentionOffset = 7;
PortContentionOffset = 7;
RenderTableOffset = 1;
FloatingBusOffset = 1;
*/
InterruptStartTime = 33;
InterruptLength = 32;
ScanlineTime = 228;
MemoryContentionOffset = 6;
PortContentionOffset = 6;
RenderTableOffset = -2;
FloatingBusOffset = 1;
BorderLeftTime = 24;
BorderRightTime = 24;
FirstPaperLine = 63;
FirstPaperTState = 64;
// screen layout
Border4T = true;
Border4TStage = 2;
// screen layout
ScreenWidth = 256;
ScreenHeight = 192;
BorderTopHeight = 55;
BorderBottomHeight = 56;
BorderTopHeight = 48;// 55;
BorderBottomHeight = 48; // 56;
BorderLeftWidth = 48;
BorderRightWidth = 48;
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;

View File

@ -13,32 +13,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
public Screen48(SpectrumBase machine)
: base(machine)
{
// timing
ClockSpeed = 3500000;
FrameCycleLength = 69888;
InterruptStartTime = 33;
// interrupt
InterruptStartTime = 3;
InterruptLength = 32;
// offsets
RenderTableOffset = 56;
ContentionOffset = 6;
FloatingBusOffset = 1;
// timing
ClockSpeed = 3500000;
FrameCycleLength = 69888;
ScanlineTime = 224;
MemoryContentionOffset = 6;
PortContentionOffset = 6;
RenderTableOffset = -9; // 2;
FloatingBusOffset = 1;
BorderLeftTime = 24;
BorderRightTime = 24;
FirstPaperLine = 64;
FirstPaperTState = 64;
// screen layout
Border4T = true;
Border4TStage = 0;
// screen layout
ScreenWidth = 256;
ScreenHeight = 192;
BorderTopHeight = 55;// 48;
BorderBottomHeight = 56;
BorderTopHeight = 48;// 55;// 48;
BorderBottomHeight = 48;// 56;
BorderLeftWidth = 48;
BorderRightWidth = 48;
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;