diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs
index 0d750bc64c..6ddbccedbc 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs
@@ -87,7 +87,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// Sets up the ROM
///
///
- ///
public abstract void InitROM(RomData romData);
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
index 67f26496c0..9544610a3a 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
@@ -12,26 +12,53 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
public abstract partial class SpectrumBase
{
- // 128 and up only
- //protected int ROMPaged = 0;
-
+ ///
+ /// Index of the currently paged ROM
+ ///
protected int ROMPaged;
-
- public int _ROMpaged
+ public virtual int _ROMpaged
{
get { return ROMPaged; }
set { ROMPaged = value; }
}
-
+ ///
+ /// Signs that the shadow screen has been paged in
+ ///
protected bool SHADOWPaged;
+
+ ///
+ /// Index of the current RAM page
+ ///
public int RAMPaged;
+
+ ///
+ /// Signs that all paging is disabled
+ ///
protected bool PagingDisabled;
// +3/+2A only
+
+ protected bool ROMhigh = false;
+ protected bool ROMlow = false;
+
+ ///
+ /// Signs that the +2a/+3 special paging mode is activated
+ ///
protected bool SpecialPagingMode;
+
+ ///
+ /// Index of the current special paging config
+ ///
protected int PagingConfiguration;
+ ///
+ /// Signs whether the disk motor is on or off
+ ///
+ protected bool DiskMotorState;
+
+ protected bool PrinterPortStrobe;
+
///
/// The calling ZXSpectrum class (piped in via constructor)
///
@@ -156,7 +183,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
if (AYDevice != null)
AYDevice.UpdateSound(CurrentFrameCycle);
- }
+ }
+
+ if (SHADOWPaged)
+ {
+
+ }
}
// we have reached the end of a frame
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs
index bb3f42ac31..c86a1e6ca4 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Memory.cs
@@ -257,6 +257,33 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
Memory.Add(9, RAM7);
}
+ ///
+ /// ULA reads the memory at the specified address
+ /// (No memory contention)
+ /// Will read RAM5 (screen0) by default, unless RAM7 (screen1) is selected as output
+ ///
+ ///
+ ///
+ public override byte FetchScreenMemory(ushort addr)
+ {
+ byte value = new byte();
+
+ if (SHADOWPaged && !PagingDisabled)
+ {
+ // shadow screen should be outputted
+ // this lives in RAM7
+ value = RAM7[addr & 0x3FFF];
+ }
+ else
+ {
+ // shadow screen is not set to display or paging is disabled (probably in 48k mode)
+ // (use screen0 at RAM5)
+ value = RAM5[addr & 0x3FFF];
+ }
+
+ return value;
+ }
+
///
/// Sets up the ROM
///
@@ -270,7 +297,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
for (int i = 0; i < 0x4000; i++)
{
ROM0[i] = RomData.RomBytes[i];
- ROM1[i] = RomData.RomBytes[i + 0x4000];
+ if (RomData.RomBytes.Length > 0x4000)
+ ROM1[i] = RomData.RomBytes[i + 0x4000];
}
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs
index 4b9cb123c7..434f4c7cfa 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -17,6 +18,11 @@ 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);
+
int result = 0xFF;
// Check whether the low bit is reset
@@ -24,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
bool lowBitReset = (port & 0x0001) == 0;
ULADevice.Contend(port);
- CPU.TotalExecutedCycles++;
+ //CPU.TotalExecutedCycles++;
// Kempston Joystick
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
@@ -143,7 +149,27 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// Kempston Mouse
- // if unused port the floating memory bus should be returned (still todo)
+ // if unused port the floating memory bus should be returned
+
+ // Floating bus is read on the previous cycle
+ int _tStates = CurrentFrameCycle - 1;
+
+ // if we are on the top or bottom border return 0xff
+ if ((_tStates < ULADevice.contentionStartPeriod) || (_tStates > ULADevice.contentionEndPeriod))
+ {
+ result = 0xff;
+ }
+ else
+ {
+ if (ULADevice.floatingBusTable[_tStates] < 0)
+ {
+ result = 0xff;
+ }
+ else
+ {
+ result = ReadBus((ushort)ULADevice.floatingBusTable[_tStates]);
+ }
+ }
}
return (byte)result;
@@ -156,38 +182,47 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
public override void WritePort(ushort port, byte value)
{
+ // get a BitArray of the port
+ BitArray portBits = new BitArray(BitConverter.GetBytes(port));
+ // get a BitArray of the value byte
+ BitArray bits = new BitArray(new byte[] { value });
+
int currT = CPU.TotalExecutedCycles;
// paging
if (port == 0x7ffd)
{
+ if (PagingDisabled)
+ return;
+
// Bits 0, 1, 2 select the RAM page
var rp = value & 0x07;
if (rp < 8)
RAMPaged = rp;
+ // bit 3 controls shadow screen
+ SHADOWPaged = bits[3];
+
// ROM page
- if ((value & 0x10) != 0)
+ if (bits[4])
{
- // 48k ROM
+ // 48k basic rom
ROMPaged = 1;
}
else
{
+ // 128k editor and menu system
ROMPaged = 0;
}
- // Bit 5 signifies that paging is disabled until next reboot
- if ((value & 0x20) != 0)
- PagingDisabled = true;
-
-
+ // Bit 5 set signifies that paging is disabled until next reboot
+ PagingDisabled = bits[5];
return;
}
// Check whether the low bit is reset
// Technically the ULA should respond to every even I/O address
- bool lowBitReset = (port & 0x01) == 0;
+ bool lowBitReset = !portBits[0]; // (port & 0x01) == 0;
ULADevice.Contend(port);
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs
index a7044ca032..15a091fccd 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs
@@ -133,7 +133,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
// ROM 0x000
case 0:
- result = Memory[ROMPaged][addr % 0x4000];
+ result = Memory[_ROMpaged][addr % 0x4000];
break;
// RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7)
@@ -407,6 +407,33 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
Memory.Add(11, RAM7);
}
+ ///
+ /// ULA reads the memory at the specified address
+ /// (No memory contention)
+ /// Will read RAM5 (screen0) by default, unless RAM7 (screen1) is selected as output
+ ///
+ ///
+ ///
+ public override byte FetchScreenMemory(ushort addr)
+ {
+ byte value = new byte();
+
+ if (SHADOWPaged && !PagingDisabled)
+ {
+ // shadow screen should be outputted
+ // this lives in RAM7
+ value = RAM7[addr & 0x3FFF];
+ }
+ else
+ {
+ // shadow screen is not set to display or paging is disabled (probably in 48k mode)
+ // (use screen0 at RAM5)
+ value = RAM5[addr & 0x3FFF];
+ }
+
+ return value;
+ }
+
///
/// Sets up the ROM
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
index 8218ce54df..199dda6515 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -158,12 +159,145 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
public override void WritePort(ushort port, byte value)
{
+ // get a BitArray of the port
+ BitArray portBits = new BitArray(BitConverter.GetBytes(port));
+ // get a BitArray of the value byte
+ BitArray bits = new BitArray(new byte[] { value });
+
// Check whether the low bit is reset
- // Technically the ULA should respond to every even I/O address
- bool lowBitReset = (port & 0x01) == 0;
+ bool lowBitReset = !portBits[0]; // (port & 0x01) == 0;
ULADevice.Contend(port);
+ // port 0x7ffd - hardware should only respond when bits 1 & 15 are reset and bit 14 is set
+ if (port == 0x7ffd)
+ {
+ if (!PagingDisabled)
+ {
+ // bits 0, 1, 2 select the RAM page
+ var rp = value & 0x07;
+ if (rp < 8)
+ RAMPaged = rp;
+
+ // bit 3 controls shadow screen
+ SHADOWPaged = bits[3];
+
+ // Bit 5 set signifies that paging is disabled until next reboot
+ PagingDisabled = bits[5];
+
+ // portbit 4 is the LOW BIT of the ROM selection
+ ROMlow = bits[4];
+ }
+ }
+ // port 0x1ffd - hardware should only respond when bits 1, 13, 14 & 15 are reset and bit 12 is set
+ else if (port == 0x1ffd)
+ {
+ if (!PagingDisabled)
+ {
+ if (bits[0])
+ {
+ // special paging is not enabled - get the ROMpage high byte
+ ROMhigh = bits[2];
+
+ // set the special paging mode flag
+ SpecialPagingMode = false;
+ }
+ else
+ {
+ // special paging is enabled
+ // this is decided based on combinations of bits 1 & 2
+ // Config 0 = Bit1-0 Bit2-0
+ // Config 1 = Bit1-1 Bit2-0
+ // Config 2 = Bit1-0 Bit2-1
+ // Config 3 = Bit1-1 Bit2-1
+ BitArray confHalfNibble = new BitArray(2);
+ confHalfNibble[0] = bits[1];
+ confHalfNibble[1] = bits[2];
+
+ // set special paging configuration
+ PagingConfiguration = ZXSpectrum.GetIntFromBitArray(confHalfNibble);
+
+ // set the special paging mode flag
+ SpecialPagingMode = true;
+ }
+ }
+
+ // bit 3 controls the disk motor (1=on, 0=off)
+ DiskMotorState = bits[3];
+
+ // bit 4 is the printer port strobe
+ PrinterPortStrobe = bits[4];
+ }
+ /*
+ // port 0x7ffd - hardware should only respond when bits 1 & 15 are reset and bit 14 is set
+ if (!portBits[1] && !portBits[15] && portBits[14])
+ {
+ // paging (skip if paging has been disabled - paging can then only happen after a machine hard reset)
+ if (!PagingDisabled)
+ {
+ // bit 0 specifies the paging mode
+ SpecialPagingMode = bits[0];
+
+ if (!SpecialPagingMode)
+ {
+ // we are in normal mode
+ // portbit 4 is the LOW BIT of the ROM selection
+ BitArray romHalfNibble = new BitArray(2);
+ romHalfNibble[0] = portBits[4];
+
+ // value bit 2 is the high bit of the ROM selection
+ romHalfNibble[1] = bits[2];
+
+ // value bit 1 is ignored in normal paging mode
+
+ // set the ROMPage
+ ROMPaged = ZXSpectrum.GetIntFromBitArray(romHalfNibble);
+
+
+
+
+ // bit 3 controls shadow screen
+ SHADOWPaged = bits[3];
+
+ // Bit 5 set signifies that paging is disabled until next reboot
+ PagingDisabled = bits[5];
+ }
+ }
+ }
+
+ // port 0x1ffd - special paging mode
+ // hardware should only respond when bits 1, 13, 14 & 15 are reset and bit 12 is set
+ if (!portBits[1] && portBits[12] && !portBits[13] && !portBits[14] && !portBits[15])
+ {
+ if (!PagingDisabled && SpecialPagingMode)
+ {
+ // process special paging
+ // this is decided based on combinations of bits 1 & 2
+ // Config 0 = Bit1-0 Bit2-0
+ // Config 1 = Bit1-1 Bit2-0
+ // Config 2 = Bit1-0 Bit2-1
+ // Config 3 = Bit1-1 Bit2-1
+ BitArray confHalfNibble = new BitArray(2);
+ confHalfNibble[0] = bits[1];
+ confHalfNibble[1] = bits[2];
+
+ // set special paging configuration
+ PagingConfiguration = ZXSpectrum.GetIntFromBitArray(confHalfNibble);
+
+ // last value should be saved at 0x5b67 (23399) - not sure if this is actually needed
+ WriteBus(0x5b67, value);
+ }
+
+ // bit 3 controls the disk motor (1=on, 0=off)
+ DiskMotorState = bits[3];
+
+ // bit 4 is the printer port strobe
+ PrinterPortStrobe = bits[4];
+ }
+
+ */
+
+
// Only even addresses address the ULA
if (lowBitReset)
{
@@ -206,6 +340,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
AYDevice.PortWrite(value);
CPU.TotalExecutedCycles += 3;
}
+
+ /*
+
else
{
if ((port & 0xC002) == 0x4000) //Are bits 1 and 15 reset and bit 14 set?
@@ -272,48 +409,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
}
}
}
+ */
}
}
+ LastULAOutByte = value;
- // paging
- if (port == 0x7ffd)
- {
- if (PagingDisabled)
- return;
-
- LastULAOutByte = value;
-
-
-
-
-
-
- // Bits 0, 1, 2 select the RAM page
- var rp = value & 0x07;
- if (rp < 8)
- RAMPaged = rp;
-
- // ROM page
- if ((value & 0x10) != 0)
- {
- // 48k ROM
- ROMPaged = 1;
- }
- else
- {
- ROMPaged = 0;
- }
-
- // Bit 5 signifies that paging is disabled until next reboot
- if ((value & 0x20) != 0)
- PagingDisabled = true;
-
-
- return;
- }
+
+ }
+
+ ///
+ /// +3 and 2a overidden method
+ ///
+ public override int _ROMpaged
+ {
+ get
+ {
+ // calculate the ROMpage from the high and low bits
+ return ZXSpectrum.GetIntFromBitArray(new BitArray(new bool[] { ROMlow, ROMhigh }));
+ }
+ set { ROMPaged = value; }
}
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs
index 893edbae8a..4cb9656858 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -248,5 +249,20 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
R3R5 = R3 | R5
}
+
+ ///
+ /// Helper method that returns a single INT32 from a BitArray
+ ///
+ ///
+ ///
+ public static int GetIntFromBitArray(BitArray bitArray)
+ {
+ if (bitArray.Length > 32)
+ throw new ArgumentException("Argument length shall be at most 32 bits.");
+
+ int[] array = new int[1];
+ bitArray.CopyTo(array, 0);
+ return array[0];
+ }
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
index 2af8fbe390..c97a3c48d2 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
@@ -77,6 +77,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
default:
throw new InvalidOperationException("Machine not yet emulated");
}
+
+
_cpu.MemoryCallbacks = MemoryCallbacks;
@@ -125,13 +127,20 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
//private byte[] _file;
private readonly List _files;
- public bool DiagRom = false;
+ public bool DiagRom = true;
+
+ private List diagRoms = new List
+ {
+ @"\DiagROM.v28",
+ @"\zx-diagnostics\testrom.bin"
+ };
+ private int diagIndex = 1;
private byte[] GetFirmware(int length, params string[] names)
{
- if (DiagRom & File.Exists(Directory.GetCurrentDirectory() + @"\DiagROM.v28"))
+ if (DiagRom & File.Exists(Directory.GetCurrentDirectory() + diagRoms[diagIndex]))
{
- var rom = File.ReadAllBytes(Directory.GetCurrentDirectory() + @"\DiagROM.v28");
+ var rom = File.ReadAllBytes(Directory.GetCurrentDirectory() + diagRoms[diagIndex]);
return rom;
}
@@ -205,7 +214,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
var _systemRomP3 = GetFirmware(0x10000, "PLUS3ROM");
var romDataP3 = RomData.InitROM(machineType, _systemRomP3);
_machine.InitROM(romDataP3);
- System.Windows.Forms.MessageBox.Show("+3 is not working at all yet :/");
+ //System.Windows.Forms.MessageBox.Show("+3 is not working at all yet :/");
break;
}
}