ZXHawk: new ULA implementation
This commit is contained in:
parent
20f10b9311
commit
9a15cbf4d4
|
@ -261,6 +261,8 @@
|
|||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IFDDHost.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\SoundOuput\AY38912.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\SoundOuput\Beeper.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\CPUMonitor.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Media\Disk\FloppyDisk.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IJoystick.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Abstraction\IPortIODevice.cs" />
|
||||
|
@ -1434,6 +1436,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\StandardKeyboard.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.Port.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.Screen.cs" />
|
||||
<None Include="Computers\SinclairSpectrum\readme.md" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Media.cs" />
|
||||
<None Include="Consoles\Atari\docs\stella.pdf" />
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
public class CPUMonitor
|
||||
{
|
||||
private SpectrumBase _machine;
|
||||
private Z80A _cpu;
|
||||
public MachineType machineType = MachineType.ZXSpectrum48;
|
||||
|
||||
public CPUMonitor(SpectrumBase machine)
|
||||
{
|
||||
_machine = machine;
|
||||
_cpu = _machine.CPU;
|
||||
}
|
||||
|
||||
public ushort[] cur_instr => _cpu.cur_instr;
|
||||
public int instr_pntr => _cpu.instr_pntr;
|
||||
public ushort RegPC => _cpu.RegPC;
|
||||
public long TotalExecutedCycles => _cpu.TotalExecutedCycles;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the first byte of an instruction is fetched
|
||||
/// </summary>
|
||||
/// <param name="firstByte"></param>
|
||||
public void OnExecFetch(ushort firstByte)
|
||||
{
|
||||
// fetch instruction without incrementing pc
|
||||
//_cpu.FetchInstruction(_cpu.FetchMemory(firstByte));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A CPU monitor cycle
|
||||
/// </summary>
|
||||
public void Cycle()
|
||||
{
|
||||
if (portContending)
|
||||
{
|
||||
RunPortContention();
|
||||
}
|
||||
}
|
||||
|
||||
#region Port Contention
|
||||
|
||||
public int portContCounter = 0;
|
||||
public bool portContending = false;
|
||||
public ushort lastPortAddr;
|
||||
|
||||
/// <summary>
|
||||
/// Perfors the actual port contention (if necessary)
|
||||
/// </summary>
|
||||
private void RunPortContention()
|
||||
{
|
||||
//return;
|
||||
bool lowBitSet = false;
|
||||
bool highByte407f = false;
|
||||
|
||||
int offset = 0; // _machine.ULADevice.contentionOffset; // -5;// 57;// - 10;
|
||||
var c = _machine.CurrentFrameCycle;
|
||||
var t = _machine.ULADevice.FrameLength;
|
||||
int f = (int)c + offset;
|
||||
if (f >= t)
|
||||
f = f - t;
|
||||
else if (f < 0)
|
||||
f = t + f;
|
||||
|
||||
if ((lastPortAddr & 0x0001) != 0)
|
||||
lowBitSet = true;
|
||||
|
||||
portContCounter--;
|
||||
|
||||
switch (machineType)
|
||||
{
|
||||
case MachineType.ZXSpectrum16:
|
||||
case MachineType.ZXSpectrum48:
|
||||
|
||||
if ((lastPortAddr & 0xc000) == 0x4000)
|
||||
highByte407f = true;
|
||||
|
||||
if (highByte407f)
|
||||
{
|
||||
// high byte 40-7f
|
||||
if (lowBitSet)
|
||||
{
|
||||
// high byte 40-7f
|
||||
// low bit set
|
||||
// C:1, C:1, C:1, C:1
|
||||
switch (portContCounter)
|
||||
{
|
||||
case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
case 1: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
case 0: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
default:
|
||||
portContCounter = 0;
|
||||
portContending = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// high byte 40-7f
|
||||
// low bit reset
|
||||
// C:1, C:3
|
||||
switch (portContCounter)
|
||||
{
|
||||
case 3: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
case 1: break;
|
||||
case 0: break;
|
||||
default:
|
||||
portContCounter = 0;
|
||||
portContending = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// high byte not 40-7f
|
||||
if (lowBitSet)
|
||||
{
|
||||
// high byte not 40-7f
|
||||
// low bit set
|
||||
// N:4
|
||||
switch (portContCounter)
|
||||
{
|
||||
case 3: break;
|
||||
case 2: break;
|
||||
case 1: break;
|
||||
case 0: break;
|
||||
default:
|
||||
portContCounter = 0;
|
||||
portContending = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// high byte not 40-7f
|
||||
// low bit reset
|
||||
// N:1, C:3
|
||||
switch (portContCounter)
|
||||
{
|
||||
case 3: break;
|
||||
case 2: _cpu.TotalExecutedCycles += _machine.ULADevice.GetContentionValue(f); break;
|
||||
case 1: break;
|
||||
case 0: break;
|
||||
default:
|
||||
portContCounter = 0;
|
||||
portContending = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MachineType.ZXSpectrum128:
|
||||
case MachineType.ZXSpectrum128Plus2:
|
||||
break;
|
||||
|
||||
case MachineType.ZXSpectrum128Plus2a:
|
||||
case MachineType.ZXSpectrum128Plus3:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the port contention process
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
public void ContendPort(ushort port)
|
||||
{
|
||||
portContending = true;
|
||||
portContCounter = 4;
|
||||
lastPortAddr = port;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -89,8 +89,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Memory Related Methods
|
||||
|
||||
/// <summary>
|
||||
|
@ -153,9 +151,21 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public virtual byte FetchScreenMemory(ushort addr)
|
||||
{
|
||||
var value = ReadBus((ushort)((addr & 0x3FFF) + 0x4000));
|
||||
//var value = ReadBus(addr);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contends memory if necessary
|
||||
/// </summary>
|
||||
public abstract void ContendMemory(ushort addr);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether supplied address is in a potentially contended bank
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public abstract bool IsContended(ushort addr);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
|
|
@ -40,88 +40,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// Increments the CPU totalCycles counter by the tStates value specified
|
||||
/// </summary>
|
||||
/// <param name="tStates"></param>
|
||||
public virtual void PortContention(int tStates)
|
||||
{
|
||||
CPU.TotalExecutedCycles += tStates;
|
||||
}
|
||||
//public virtual void PortContention(int tStates)
|
||||
//{
|
||||
// CPU.TotalExecutedCycles += tStates;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates IO port contention based on the supplied address
|
||||
/// This method is for 48k and 128k/+2 machines only and should be overridden for other models
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public virtual void ContendPortAddress(ushort addr)
|
||||
{
|
||||
return;
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract void ContendPort(ushort addr);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <summary>
|
||||
/// The emulated ULA device
|
||||
/// </summary>
|
||||
public ULABase ULADevice { get; set; }
|
||||
//public ULABase ULADevice { get; set; }
|
||||
public ULA ULADevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Monitors CPU cycles
|
||||
/// </summary>
|
||||
public CPUMonitor CPUMon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The spectrum buzzer/beeper
|
||||
|
@ -152,9 +158,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
if (_renderSound)
|
||||
{
|
||||
//BuzzerDevice.StartFrame();
|
||||
//TapeBuzzer.StartFrame();
|
||||
|
||||
if (AYDevice != null)
|
||||
AYDevice.StartFrame();
|
||||
}
|
||||
|
@ -169,23 +172,23 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
// run a single CPU instruction
|
||||
CPU.ExecuteOne();
|
||||
|
||||
CPUMon.Cycle();
|
||||
|
||||
// cycle the tape device
|
||||
if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded)
|
||||
TapeDevice.TapeCycle();
|
||||
}
|
||||
|
||||
OverFlow = (int)CurrentFrameCycle - ULADevice.FrameLength;
|
||||
|
||||
// we have reached the end of a frame
|
||||
LastFrameStartCPUTick = CPU.TotalExecutedCycles - OverFlow;
|
||||
|
||||
// paint the buffer if needed
|
||||
if (ULADevice.needsPaint && _render)
|
||||
ULADevice.UpdateScreenBuffer(ULADevice.FrameLength);
|
||||
// paint the buffer at end of frame
|
||||
if (_render)
|
||||
ULADevice.RenderScreen(ULADevice.FrameLength);
|
||||
|
||||
if (_renderSound)
|
||||
{
|
||||
//BuzzerDevice.EndFrame();
|
||||
//TapeBuzzer.EndFrame();
|
||||
}
|
||||
ULADevice.LastTState = 0;
|
||||
|
||||
if (AYDevice != null)
|
||||
AYDevice.EndFrame();
|
||||
|
@ -194,7 +197,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
// setup for next frame
|
||||
ULADevice.ResetInterrupt();
|
||||
|
||||
|
||||
if (UPDDiskDevice == null || !UPDDiskDevice.FDD_IsDiskLoaded)
|
||||
TapeDevice.EndFrame();
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,7 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/*
|
||||
/// <summary>
|
||||
/// ULA (Uncommitted Logic Array) implementation
|
||||
/// </summary>
|
||||
|
@ -78,6 +79,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// </summary>
|
||||
public byte[] contentionTable;
|
||||
|
||||
/// <summary>
|
||||
/// Contention offset (used for testing)
|
||||
/// </summary>
|
||||
public int contentionOffset = 0; // -5;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Screen Rendering
|
||||
|
@ -86,6 +92,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// Video output buffer
|
||||
/// </summary>
|
||||
public int[] ScreenBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Screen rendering T-State info
|
||||
/// </summary>
|
||||
public RenderCycle[] RenderTable;
|
||||
|
||||
/// <summary>
|
||||
/// Display memory
|
||||
/// </summary>
|
||||
|
@ -246,14 +258,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
#region Interrupt
|
||||
|
||||
/// <summary>
|
||||
/// The number of T-States that the INT pin is simulated to be held low
|
||||
/// The t-state within the frame that an interrupt is raised
|
||||
/// </summary>
|
||||
public int InterruptPeriod;
|
||||
public int InterruptStart;
|
||||
|
||||
/// <summary>
|
||||
/// The longest instruction cycle count
|
||||
/// The number of T-States that the INT pin is simulated to be held low
|
||||
/// </summary>
|
||||
protected int LongestOperationCycles = 23;
|
||||
public int InterruptDuration = 32;
|
||||
|
||||
/// <summary>
|
||||
/// Signs that an interrupt has been raised in this frame.
|
||||
|
@ -287,13 +299,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
return;
|
||||
}
|
||||
|
||||
if (currentCycle < LongestOperationCycles)// InterruptPeriod)
|
||||
if (currentCycle < InterruptStart)
|
||||
{
|
||||
// interrupt does not need to be raised yet
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentCycle >= InterruptPeriod + LongestOperationCycles)
|
||||
if (currentCycle > InterruptStart + InterruptDuration)
|
||||
{
|
||||
// interrupt should have already been raised and the cpu may or
|
||||
// may not have caught it. The time has passed so revoke the signal
|
||||
|
@ -350,31 +362,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool IsContended(int addr);
|
||||
|
||||
/// <summary>
|
||||
/// Contends the machine for a given address
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public virtual void Contend(ushort addr)
|
||||
{
|
||||
if (IsContended(addr) && !(_machine is ZX128Plus3))
|
||||
{
|
||||
_machine.CPU.TotalExecutedCycles += contentionTable[CurrentTStateInFrame];
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Contend(int addr, int time, int count)
|
||||
{
|
||||
if (IsContended(addr) && !(_machine is ZX128Plus3))
|
||||
{
|
||||
for (int f = 0; f < count; f++)
|
||||
{
|
||||
_machine.CPU.TotalExecutedCycles += contentionTable[CurrentTStateInFrame] + time;
|
||||
}
|
||||
}
|
||||
else
|
||||
_machine.CPU.TotalExecutedCycles += count * time;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets render state once interrupt is generated
|
||||
|
@ -401,6 +389,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builds the T-State to attribute map used with the floating bus
|
||||
/// </summary>
|
||||
|
@ -426,6 +415,32 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the floating bus value
|
||||
/// </summary>
|
||||
public virtual void ReadFloatingBus(ref int result)
|
||||
{
|
||||
// Floating bus is read on the previous cycle
|
||||
long _tStates = _machine.CurrentFrameCycle - 1;
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < contentionStartPeriod) || (_tStates > contentionEndPeriod))
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (floatingBusTable[_tStates] < 0)
|
||||
{
|
||||
result = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _machine.ReadBus((ushort)floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the screen buffer based on the number of T-States supplied
|
||||
/// </summary>
|
||||
|
@ -444,7 +459,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
|
||||
//the additional 1 tstate is required to get correct number of bytes to output in ircontention.sna
|
||||
elapsedTStates = (_tstates + 1 - lastTState) - 1;
|
||||
elapsedTStates = (_tstates + 1 - lastTState);
|
||||
|
||||
//It takes 4 tstates to write 1 byte. Or, 2 pixels per t-state.
|
||||
|
||||
|
@ -755,6 +770,27 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
/*
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// T-State display mapping
|
||||
/// </summary>
|
||||
public class RenderCycle
|
||||
{
|
||||
public RenderType Type { get; set; }
|
||||
public short DisplayAddress { get; set; }
|
||||
public short AttributeAddress { get; set; }
|
||||
public int ContentionValue { get; set; }
|
||||
public short FloatingBusAddress { get; set; }
|
||||
}
|
||||
|
||||
public enum RenderType
|
||||
{
|
||||
None,
|
||||
Border,
|
||||
Display
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -175,10 +175,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -189,9 +185,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
ContendMemory(addr);
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
@ -204,13 +199,56 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
// update ULA screen buffer if necessary BEFORE T1 write
|
||||
if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
|
||||
ContendMemory(addr);
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contends memory if necessary
|
||||
/// </summary>
|
||||
public override void ContendMemory(ushort addr)
|
||||
{
|
||||
if (IsContended(addr))
|
||||
{
|
||||
var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle);
|
||||
CPU.TotalExecutedCycles += delay;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether supplied address is in a potentially contended bank
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override bool IsContended(ushort addr)
|
||||
{
|
||||
var a = addr & 0xc000;
|
||||
|
||||
if (a == 0x4000)
|
||||
{
|
||||
// low port contention
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == 0xc000)
|
||||
{
|
||||
// high port contention - check for contended bank paged in
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
bool deviceAddressed = true;
|
||||
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
|
@ -56,6 +56,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
ULADevice.ReadFloatingBus((int)_tStates, ref result);
|
||||
|
||||
/*
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
|
@ -72,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
|
@ -85,7 +89,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
// get a BitArray of the port
|
||||
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
|
||||
|
@ -142,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
{
|
||||
// store the last OUT byte
|
||||
LastULAOutByte = value;
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
CPU.TotalExecutedCycles += ULADevice.GetContentionValue();
|
||||
|
||||
/*
|
||||
Bit 7 6 5 4 3 2 1 0
|
||||
|
@ -152,10 +156,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
if (ULADevice.BorderColor != (value & BORDER_BIT))
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
ULADevice.BorderColor = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0);
|
||||
|
@ -165,5 +169,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contend port if necessary
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override void ContendPort(ushort addr)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/*
|
||||
class ULA128 : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
@ -8,8 +9,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public ULA128(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 36;
|
||||
LongestOperationCycles = 64 + 2;
|
||||
InterruptStart = 0;
|
||||
//LongestOperationCycles = 64 + 2;
|
||||
FrameLength = 70908;
|
||||
ClockSpeed = 3546900;
|
||||
|
||||
|
@ -189,4 +190,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -21,12 +21,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
CPUMon = new CPUMonitor(this);
|
||||
CPUMon.machineType = MachineType.ZXSpectrum128;
|
||||
|
||||
ROMPaged = 0;
|
||||
SHADOWPaged = false;
|
||||
RAMPaged = 0;
|
||||
PagingDisabled = false;
|
||||
|
||||
ULADevice = new ULA128(this);
|
||||
//ULADevice = new ULA128(this);
|
||||
ULADevice = new Screen48(this); // still todo
|
||||
|
||||
BuzzerDevice = new Beeper(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
|
|
@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -355,9 +355,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
ContendMemory(addr);
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
@ -370,13 +369,74 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
// update ULA screen buffer if necessary BEFORE T1 write
|
||||
if (!SpecialPagingMode)
|
||||
{
|
||||
if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
if ((addr & 49152) == 16384)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
break;
|
||||
case 1:
|
||||
if ((addr & 49152) == 16384 || addr >= 0xc000)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ContendMemory(addr);
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contends memory if necessary
|
||||
/// </summary>
|
||||
public override void ContendMemory(ushort addr)
|
||||
{
|
||||
if (IsContended(addr))
|
||||
{
|
||||
var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle);
|
||||
CPU.TotalExecutedCycles += delay;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether supplied address is in a potentially contended bank
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override bool IsContended(ushort addr)
|
||||
{
|
||||
var a = addr & 0xc000;
|
||||
|
||||
if (a == 0x4000)
|
||||
{
|
||||
// low port contention
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == 0xc000)
|
||||
{
|
||||
// high port contention - check for contended bank paged in
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
bool deviceAddressed = true;
|
||||
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
|
@ -56,6 +56,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
ULADevice.ReadFloatingBus((int)_tStates, ref result);
|
||||
/*
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
|
@ -72,6 +74,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
// Check whether the low bit is reset
|
||||
|
@ -158,7 +161,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
// get a BitArray of the port
|
||||
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
|
||||
|
@ -241,10 +244,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
if (ULADevice.BorderColor != (value & BORDER_BIT))
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
ULADevice.BorderColor = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0);
|
||||
|
@ -281,13 +284,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override port contention
|
||||
/// +3/2a does not have the same ULA IO contention
|
||||
/// Contend port if necessary
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override void ContendPortAddress(ushort addr)
|
||||
public override void ContendPort(ushort addr)
|
||||
{
|
||||
//CPU.TotalExecutedCycles += 4;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/*
|
||||
class ULAPlus2a : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
@ -8,8 +9,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public ULAPlus2a(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 36;
|
||||
LongestOperationCycles = 64 + 2;
|
||||
InterruptStart = 0;
|
||||
//LongestOperationCycles = 64 + 2;
|
||||
FrameLength = 70908;
|
||||
ClockSpeed = 3546900;
|
||||
|
||||
|
@ -193,4 +194,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -21,12 +21,16 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
CPUMon = new CPUMonitor(this);
|
||||
CPUMon.machineType = MachineType.ZXSpectrum128Plus2a;
|
||||
|
||||
ROMPaged = 0;
|
||||
SHADOWPaged = false;
|
||||
RAMPaged = 0;
|
||||
PagingDisabled = false;
|
||||
|
||||
ULADevice = new ULAPlus2a(this);
|
||||
//ULADevice = new ULAPlus2a(this);
|
||||
ULADevice = new Screen48(this); // still todo
|
||||
|
||||
BuzzerDevice = new Beeper(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
|
|
@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -355,9 +355,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
ContendMemory(addr);
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
@ -370,13 +369,74 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
// update ULA screen buffer if necessary BEFORE T1 write
|
||||
if (!SpecialPagingMode)
|
||||
{
|
||||
if (((addr & 49152) == 16384 || ((addr & 0xc000) == 0xc000) && (RAMPaged == 5 || RAMPaged == 7)) && _render)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (PagingConfiguration)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
if ((addr & 49152) == 16384)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
break;
|
||||
case 1:
|
||||
if ((addr & 49152) == 16384 || addr >= 0xc000)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ContendMemory(addr);
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contends memory if necessary
|
||||
/// </summary>
|
||||
public override void ContendMemory(ushort addr)
|
||||
{
|
||||
if (IsContended(addr))
|
||||
{
|
||||
var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle);
|
||||
CPU.TotalExecutedCycles += delay;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether supplied address is in a potentially contended bank
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override bool IsContended(ushort addr)
|
||||
{
|
||||
var a = addr & 0xc000;
|
||||
|
||||
if (a == 0x4000)
|
||||
{
|
||||
// low port contention
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == 0xc000)
|
||||
{
|
||||
// high port contention - check for contended bank paged in
|
||||
switch (RAMPaged)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
bool deviceAddressed = true;
|
||||
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
|
@ -60,6 +60,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
ULADevice.ReadFloatingBus((int)_tStates, ref result);
|
||||
|
||||
/*
|
||||
|
||||
// if we are on the top or bottom border return 0xff
|
||||
if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
|
||||
{
|
||||
|
@ -76,6 +80,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
|
@ -89,7 +94,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
// get a BitArray of the port
|
||||
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
|
||||
|
@ -174,10 +179,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
if (ULADevice.BorderColor != (value & BORDER_BIT))
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
ULADevice.BorderColor = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0);
|
||||
|
@ -214,13 +219,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override port contention
|
||||
/// +3/2a does not have the same ULA IO contention
|
||||
/// Contend port if necessary
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override void ContendPortAddress(ushort addr)
|
||||
public override void ContendPort(ushort addr)
|
||||
{
|
||||
//CPU.TotalExecutedCycles += 4;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/*
|
||||
class ULAPlus3 : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
@ -8,8 +9,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public ULAPlus3(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 36;
|
||||
LongestOperationCycles = 64 + 2;
|
||||
InterruptStart = 0;
|
||||
//LongestOperationCycles = 64 + 2;
|
||||
FrameLength = 70908;
|
||||
ClockSpeed = 3546900;
|
||||
|
||||
|
@ -193,4 +194,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -20,13 +20,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
{
|
||||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
CPUMon.machineType = MachineType.ZXSpectrum128Plus3;
|
||||
|
||||
CPUMon = new CPUMonitor(this);
|
||||
|
||||
ROMPaged = 0;
|
||||
SHADOWPaged = false;
|
||||
RAMPaged = 0;
|
||||
PagingDisabled = false;
|
||||
|
||||
ULADevice = new ULAPlus3(this);
|
||||
// ULADevice = new ULAPlus3(this);
|
||||
ULADevice = new Screen48(this); // still todo
|
||||
|
||||
BuzzerDevice = new Beeper(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Memory
|
||||
|
||||
/* 48K Spectrum has NO memory paging
|
||||
|
@ -88,11 +87,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
case 1:
|
||||
RAM0[index] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -103,8 +98,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
if (IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle);
|
||||
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
|
@ -119,8 +114,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
if (IsContended(addr))
|
||||
{
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
CPU.TotalExecutedCycles += ULADevice.GetContentionValue((int)CurrentFrameCycle);
|
||||
}
|
||||
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
|
|
@ -86,10 +86,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
RAM2[index] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
// update ULA screen buffer if necessary
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -100,9 +96,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <returns></returns>
|
||||
public override byte ReadMemory(ushort addr)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
ContendMemory(addr);
|
||||
var data = ReadBus(addr);
|
||||
return data;
|
||||
}
|
||||
|
@ -115,13 +109,41 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// <param name="value"></param>
|
||||
public override void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
// apply contention if necessary
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
// update ULA screen buffer if necessary BEFORE T1 write
|
||||
if ((addr & 49152) == 16384 && _render)
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
|
||||
ContendMemory(addr);
|
||||
WriteBus(addr, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contends memory if necessary
|
||||
/// </summary>
|
||||
public override void ContendMemory(ushort addr)
|
||||
{
|
||||
if (IsContended(addr))
|
||||
{
|
||||
var delay = ULADevice.GetContentionValue((int)CurrentFrameCycle);
|
||||
if (delay > 0)
|
||||
{
|
||||
|
||||
}
|
||||
CPU.TotalExecutedCycles += delay;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether supplied address is in a potentially contended bank
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override bool IsContended(ushort addr)
|
||||
{
|
||||
if ((addr & 49152) == 16384)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public override byte ReadPort(ushort port)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
int result = 0xFF;
|
||||
|
||||
|
@ -56,6 +56,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
|
||||
// If this is an unused port the floating memory bus should be returned
|
||||
ULADevice.ReadFloatingBus((int)CurrentFrameCycle, ref result);
|
||||
|
||||
/*
|
||||
// Floating bus is read on the previous cycle
|
||||
long _tStates = CurrentFrameCycle - 1;
|
||||
|
||||
|
@ -75,6 +78,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
|
@ -88,7 +92,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public override void WritePort(ushort port, byte value)
|
||||
{
|
||||
// process IO contention
|
||||
ContendPortAddress(port);
|
||||
ContendPort(port);
|
||||
|
||||
// Check whether the low bit is reset
|
||||
// Technically the ULA should respond to every even I/O address
|
||||
|
@ -106,13 +110,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
*/
|
||||
|
||||
// Border - LSB 3 bits hold the border colour
|
||||
if (ULADevice.borderColour != (value & BORDER_BIT))
|
||||
{
|
||||
// border value has changed - update the screen buffer
|
||||
ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
ULADevice.borderColour = value & BORDER_BIT;
|
||||
ULADevice.RenderScreen((int)CurrentFrameCycle);
|
||||
ULADevice.BorderColor = value & BORDER_BIT;
|
||||
|
||||
// Buzzer
|
||||
BuzzerDevice.ProcessPulseValue((value & EAR_BIT) != 0);
|
||||
|
@ -124,6 +123,40 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
//TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Simulates IO port contention based on the supplied address
|
||||
/// This method is for 48k and 128k/+2 machines only and should be overridden for other models
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
public override void ContendPort(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.
|
||||
*/
|
||||
|
||||
CPUMon.ContendPort(addr);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
class Screen48 : ULA
|
||||
{
|
||||
#region Construction
|
||||
|
||||
public Screen48(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
// timing
|
||||
ClockSpeed = 3500000;
|
||||
FrameCycleLength = 69888;
|
||||
InterruptStartTime = 32;
|
||||
InterruptLength = 32;
|
||||
ScanlineTime = 224;
|
||||
|
||||
BorderLeftTime = 24;
|
||||
BorderRightTime = 24;
|
||||
|
||||
FirstPaperLine = 64;
|
||||
FirstPaperTState = 64;
|
||||
|
||||
Border4T = true;
|
||||
Border4TStage = 0;
|
||||
|
||||
// screen layout
|
||||
ScreenWidth = 256;
|
||||
ScreenHeight = 192;
|
||||
BorderTopHeight = 48;
|
||||
BorderBottomHeight = 56;
|
||||
BorderLeftWidth = 48;
|
||||
BorderRightWidth = 48;
|
||||
ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
|
||||
|
||||
RenderingTable = new RenderTable(this,
|
||||
MachineType.ZXSpectrum48);
|
||||
|
||||
SetupScreenSize();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
||||
{
|
||||
/*
|
||||
class ULA48 : ULABase
|
||||
{
|
||||
#region Construction
|
||||
|
@ -8,8 +11,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
public ULA48(SpectrumBase machine)
|
||||
: base(machine)
|
||||
{
|
||||
InterruptPeriod = 32;
|
||||
LongestOperationCycles = 64;
|
||||
InterruptStart = 0;// 5; // 0; // 3; // 0;// 32;
|
||||
//LongestOperationCycles = 32;
|
||||
FrameLength = 69888;
|
||||
ClockSpeed = 3500000;
|
||||
|
||||
|
@ -55,7 +58,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
public override void Reset()
|
||||
{
|
||||
contentionStartPeriod = 14335; // + LateTiming;
|
||||
contentionOffset = 0;
|
||||
InterruptStart = 0;
|
||||
|
||||
contentionStartPeriod = 14335;// + contentionOffset; // + LateTiming;
|
||||
contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
|
||||
screen = _machine.RAM0;
|
||||
screenByteCtr = DisplayStart;
|
||||
|
@ -160,6 +166,30 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
h += TstatesPerScanline - 128;
|
||||
}
|
||||
|
||||
// offset floating bus table
|
||||
var offset = 0;
|
||||
|
||||
if (offset != 0)
|
||||
{
|
||||
var fbt = floatingBusTable.ToArray();
|
||||
for (int i = 0; i < FrameLength; i++)
|
||||
{
|
||||
var off = i + offset;
|
||||
if (off < 0)
|
||||
{
|
||||
off = FrameLength - 1 + off;
|
||||
}
|
||||
else if (off >= FrameLength)
|
||||
{
|
||||
off = off - FrameLength;
|
||||
}
|
||||
|
||||
fbt[off] = floatingBusTable[i];
|
||||
}
|
||||
|
||||
floatingBusTable = fbt.ToArray();
|
||||
}
|
||||
|
||||
//build bottom border
|
||||
while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
|
||||
{
|
||||
|
@ -177,4 +207,5 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -21,7 +21,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
Spectrum = spectrum;
|
||||
CPU = cpu;
|
||||
|
||||
ULADevice = new ULA48(this);
|
||||
CPUMon = new CPUMonitor(this);
|
||||
|
||||
//ULADevice = new ULA48(this);
|
||||
ULADevice = new Screen48(this);
|
||||
|
||||
BuzzerDevice = new Beeper(this);
|
||||
BuzzerDevice.Init(44100, ULADevice.FrameLength);
|
||||
|
|
|
@ -91,6 +91,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
_cpu.ReadHardware = _machine.ReadPort;
|
||||
_cpu.WriteHardware = _machine.WritePort;
|
||||
_cpu.FetchDB = _machine.PushBus;
|
||||
_cpu.OnExecFetch = _machine.CPUMon.OnExecFetch;
|
||||
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
ser.Register<IDisassemblable>(_cpu);
|
||||
|
|
Loading…
Reference in New Issue