diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 10d5eb3aab..c0fbe511fc 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -268,6 +268,11 @@
+
+
+
+
+
@@ -1397,8 +1402,12 @@
-
+
+
+
+
+
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs
index 478b821a1a..cee9f524da 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs
@@ -28,6 +28,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
ZXSpectrum128Plus2,
+ ///
+ /// Sinclair Spectrum 128 +2a model (same as the +3 just without disk drive)
+ ///
+ ZXSpectrum128Plus2a,
+
///
/// Sinclair Spectrum 128 +3 model
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
index 9544610a3a..553872b295 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs
@@ -183,11 +183,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
if (AYDevice != null)
AYDevice.UpdateSound(CurrentFrameCycle);
- }
-
- if (SHADOWPaged)
- {
-
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs
index 1ac1ccf326..6da4c3738f 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.ULA.cs
@@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
contentionStartPeriod = 14361; // + LateTiming;
contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
- screen = _machine.Memory[1];
+ screen = _machine.Memory[7];
screenByteCtr = DisplayStart;
ULAByteCtr = 0;
actualULAStart = 14366 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs
new file mode 100644
index 0000000000..6505a5f81f
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Memory.cs
@@ -0,0 +1,459 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ public partial class ZX128Plus2a : SpectrumBase
+ {
+ /* http://www.worldofspectrum.org/faq/reference/128kreference.htm
+ *
+ * Port 0x7ffd behaves in the almost exactly the same way as on the 128K/+2, with two exceptions:
+
+ Bit 4 is now the low bit of the ROM selection.
+ The partial decoding used is now slightly different: the hardware will respond only to those port addresses with bit 1 reset, bit 14 set and bit 15 reset (as opposed to just bits 1 and 15 reset on the 128K/+2).
+ The extra paging features of the +2A/+3 are controlled by port 0x1ffd (again, partial decoding applies here: the hardware will respond to all port addresses with bit 1 reset, bit 12 set and bits 13, 14 and 15 reset). This port is also write-only, and its last value should be saved at 0x5b67 (23399).
+
+ Port 0x1ffd responds as follows:
+
+ Bit 0: Paging mode. 0=normal, 1=special
+ Bit 1: In normal mode, ignored.
+ Bit 2: In normal mode, high bit of ROM selection. The four ROMs are:
+ ROM 0: 128k editor, menu system and self-test program
+ ROM 1: 128k syntax checker
+ ROM 2: +3DOS
+ ROM 3: 48 BASIC
+ Bit 3: Disk motor; 1=on, 0=off
+ Bit 4: Printer port strobe.
+ When special mode is selected, the memory map changes to one of four configurations specified in bits 1 and 2 of port 0x1ffd:
+ Bit 2 =0 Bit 2 =0 Bit 2 =1 Bit 2 =1
+ Bit 1 =0 Bit 1 =1 Bit 1 =0 Bit 1 =1
+ 0xffff +--------+ +--------+ +--------+ +--------+
+ | Bank 3 | | Bank 7 | | Bank 3 | | Bank 3 |
+ | | | | | | | |
+ | | | | | | | |
+ | | | screen | | | | |
+ 0xc000 +--------+ +--------+ +--------+ +--------+
+ | Bank 2 | | Bank 6 | | Bank 6 | | Bank 6 |
+ | | | | | | | |
+ | | | | | | | |
+ | | | | | | | |
+ 0x8000 +--------+ +--------+ +--------+ +--------+
+ | Bank 1 | | Bank 5 | | Bank 5 | | Bank 7 |
+ | | | | | | | |
+ | | | | | | | |
+ | | | screen | | screen | | screen |
+ 0x4000 +--------+ +--------+ +--------+ +--------+
+ | Bank 0 | | Bank 4 | | Bank 4 | | Bank 4 |
+ | | | | | | | |
+ | | | | | | | |
+ | | | | | | | |
+ 0x0000 +--------+ +--------+ +--------+ +--------+
+ RAM banks 1,3,4 and 6 are used for the disc cache and RAMdisc, while Bank 7 contains editor scratchpads and +3DOS workspace.
+ */
+
+ ///
+ /// Simulates reading from the bus (no contention)
+ /// Paging should be handled here
+ ///
+ ///
+ ///
+ public override byte ReadBus(ushort addr)
+ {
+ int divisor = addr / 0x4000;
+ byte result = 0xff;
+
+ // special paging
+ if (SpecialPagingMode)
+ {
+ switch (divisor)
+ {
+ case 0:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ result = Memory[4][addr % 0x4000];
+ break;
+ case 1:
+ case 2:
+ case 3:
+ result = Memory[8][addr % 0x4000];
+ break;
+ }
+ break;
+ case 1:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ result = Memory[5][addr % 0x4000];
+ break;
+ case 1:
+ case 2:
+ result = Memory[9][addr % 0x4000];
+ break;
+ case 3:
+ result = Memory[11][addr % 0x4000];
+ break;
+ }
+ break;
+ case 2:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ result = Memory[6][addr % 0x4000];
+ break;
+ case 1:
+ case 2:
+ case 3:
+ result = Memory[10][addr % 0x4000];
+ break;
+ }
+ break;
+ case 3:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ case 2:
+ case 3:
+ result = Memory[7][addr % 0x4000];
+ break;
+ case 1:
+ result = Memory[11][addr % 0x4000];
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (divisor)
+ {
+ // ROM 0x000
+ case 0:
+ result = Memory[_ROMpaged][addr % 0x4000];
+ break;
+
+ // RAM 0x4000 (RAM5 - Bank5 always)
+ case 1:
+ result = Memory[9][addr % 0x4000];
+ break;
+
+ // RAM 0x8000 (RAM2 - Bank2)
+ case 2:
+ result = Memory[6][addr % 0x4000];
+ break;
+
+ // RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
+ case 3:
+ switch (RAMPaged)
+ {
+ case 0:
+ result = Memory[4][addr % 0x4000];
+ break;
+ case 1:
+ result = Memory[5][addr % 0x4000];
+ break;
+ case 2:
+ result = Memory[6][addr % 0x4000];
+ break;
+ case 3:
+ result = Memory[7][addr % 0x4000];
+ break;
+ case 4:
+ result = Memory[8][addr % 0x4000];
+ break;
+ case 5:
+ result = Memory[9][addr % 0x4000];
+ break;
+ case 6:
+ result = Memory[10][addr % 0x4000];
+ break;
+ case 7:
+ result = Memory[11][addr % 0x4000];
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Simulates writing to the bus (no contention)
+ /// Paging should be handled here
+ ///
+ ///
+ ///
+ public override void WriteBus(ushort addr, byte value)
+ {
+ int divisor = addr / 0x4000;
+
+ // special paging
+ if (SpecialPagingMode)
+ {
+ switch (divisor)
+ {
+ case 0:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ Memory[4][addr % 0x4000] = value;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ Memory[8][addr % 0x4000] = value;
+ break;
+ }
+ break;
+ case 1:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ Memory[5][addr % 0x4000] = value;
+ break;
+ case 1:
+ case 2:
+ Memory[9][addr % 0x4000] = value;
+ break;
+ case 3:
+ Memory[11][addr % 0x4000] = value;
+ break;
+ }
+ break;
+ case 2:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ Memory[6][addr % 0x4000] = value;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ Memory[10][addr % 0x4000] = value;
+ break;
+ }
+ break;
+ case 3:
+ switch (PagingConfiguration)
+ {
+ case 0:
+ case 2:
+ case 3:
+ Memory[7][addr % 0x4000] = value;
+ break;
+ case 1:
+ Memory[11][addr % 0x4000] = value;
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (divisor)
+ {
+ // ROM 0x000
+ case 0:
+ Memory[_ROMpaged][addr % 0x4000] = value;
+ break;
+
+ // RAM 0x4000 (RAM5 - Bank5 only)
+ case 1:
+ Memory[9][addr % 0x4000] = value;
+ break;
+
+ // RAM 0x8000 (RAM2 - Bank2)
+ case 2:
+ Memory[6][addr % 0x4000] = value;
+ break;
+
+ // RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
+ case 3:
+ switch (RAMPaged)
+ {
+ case 0:
+ Memory[4][addr % 0x4000] = value;
+ break;
+ case 1:
+ Memory[5][addr % 0x4000] = value;
+ break;
+ case 2:
+ Memory[6][addr % 0x4000] = value;
+ break;
+ case 3:
+ Memory[7][addr % 0x4000] = value;
+ break;
+ case 4:
+ Memory[8][addr % 0x4000] = value;
+ break;
+ case 5:
+ Memory[9][addr % 0x4000] = value;
+ break;
+ case 6:
+ Memory[10][addr % 0x4000] = value;
+ break;
+ case 7:
+ Memory[11][addr % 0x4000] = value;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // update ULA screen buffer if necessary
+ if ((addr & 49152) == 16384 && _render)
+ ULADevice.UpdateScreenBuffer(CurrentFrameCycle);
+ }
+
+ ///
+ /// Reads a byte of data from a specified memory address
+ /// (with memory contention if appropriate)
+ ///
+ ///
+ ///
+ public override byte ReadMemory(ushort addr)
+ {
+ if (ULADevice.IsContended(addr))
+ CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
+
+ var data = ReadBus(addr);
+ return data;
+ }
+
+ ///
+ /// Writes a byte of data to a specified memory address
+ /// (with memory contention if appropriate)
+ ///
+ ///
+ ///
+ public override void WriteMemory(ushort addr, byte value)
+ {
+ // apply contention if necessary
+ if (ULADevice.IsContended(addr))
+ CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
+
+ WriteBus(addr, value);
+ }
+
+ public override void ReInitMemory()
+ {
+ if (Memory.ContainsKey(0))
+ Memory[0] = ROM0;
+ else
+ Memory.Add(0, ROM0);
+
+ if (Memory.ContainsKey(1))
+ Memory[1] = ROM1;
+ else
+ Memory.Add(1, ROM1);
+
+ if (Memory.ContainsKey(2))
+ Memory[2] = ROM2;
+ else
+ Memory.Add(2, ROM2);
+
+ if (Memory.ContainsKey(3))
+ Memory[3] = ROM3;
+ else
+ Memory.Add(3, ROM3);
+
+ if (Memory.ContainsKey(4))
+ Memory[4] = RAM0;
+ else
+ Memory.Add(4, RAM0);
+
+ if (Memory.ContainsKey(5))
+ Memory[5] = RAM1;
+ else
+ Memory.Add(5, RAM1);
+
+ if (Memory.ContainsKey(6))
+ Memory[6] = RAM2;
+ else
+ Memory.Add(6, RAM2);
+
+ if (Memory.ContainsKey(7))
+ Memory[7] = RAM3;
+ else
+ Memory.Add(7, RAM3);
+
+ if (Memory.ContainsKey(8))
+ Memory[8] = RAM4;
+ else
+ Memory.Add(8, RAM4);
+
+ if (Memory.ContainsKey(9))
+ Memory[9] = RAM5;
+ else
+ Memory.Add(9, RAM5);
+
+ if (Memory.ContainsKey(10))
+ Memory[10] = RAM6;
+ else
+ Memory.Add(10, RAM6);
+
+ if (Memory.ContainsKey(11))
+ Memory[11] = RAM7;
+ else
+ 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
+ ///
+ ///
+ ///
+ public override void InitROM(RomData romData)
+ {
+ RomData = romData;
+ // +3 uses ROM0, ROM1, ROM2 & ROM3
+ /* ROM 0: 128k editor, menu system and self-test program
+ ROM 1: 128k syntax checker
+ ROM 2: +3DOS
+ ROM 3: 48 BASIC
+ */
+ Stream stream = new MemoryStream(RomData.RomBytes);
+ stream.Read(ROM0, 0, 16384);
+ stream.Read(ROM1, 0, 16384);
+ stream.Read(ROM2, 0, 16384);
+ stream.Read(ROM3, 0, 16384);
+ stream.Dispose();
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs
new file mode 100644
index 0000000000..07e22b4203
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs
@@ -0,0 +1,448 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ public partial class ZX128Plus2a : SpectrumBase
+ {
+ ///
+ /// Reads a byte of data from a specified port address
+ ///
+ ///
+ ///
+ public override byte ReadPort(ushort port)
+ {
+ InputRead = true;
+
+ int result = 0xFF;
+
+ // Check whether the low bit is reset
+ // 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)
+ {
+ if (LocateUniqueJoystick(JoystickType.Kempston) != null)
+ return (byte)((KempstonJoystick)LocateUniqueJoystick(JoystickType.Kempston) as KempstonJoystick).JoyLine;
+
+ InputRead = true;
+ }
+ else if (lowBitReset)
+ {
+ // Even I/O address so get input
+ // The high byte indicates which half-row of keys is being polled
+ /*
+ IN: Reads keys (bit 0 to bit 4 inclusive)
+ 0xfefe SHIFT, Z, X, C, V 0xeffe 0, 9, 8, 7, 6
+ 0xfdfe A, S, D, F, G 0xdffe P, O, I, U, Y
+ 0xfbfe Q, W, E, R, T 0xbffe ENTER, L, K, J, H
+ 0xf7fe 1, 2, 3, 4, 5 0x7ffe SPACE, SYM SHFT, M, N, B
+ */
+
+ if ((port & 0x8000) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[7];
+ }
+
+ if ((port & 0x4000) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[6];
+ }
+
+ if ((port & 0x2000) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[5];
+ }
+
+ if ((port & 0x1000) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[4];
+ }
+
+ if ((port & 0x800) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[3];
+ }
+
+ if ((port & 0x400) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[2];
+ }
+
+ if ((port & 0x200) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[1];
+ }
+
+ if ((port & 0x100) == 0)
+ {
+ result &= KeyboardDevice.KeyLine[0];
+ }
+
+ result = result & 0x1f; //mask out lower 4 bits
+ result = result | 0xa0; //set bit 5 & 7 to 1
+
+
+ if (TapeDevice.TapeIsPlaying)//.CurrentMode == TapeOperationMode.Load)
+ {
+ if (!TapeDevice.GetEarBit(CPU.TotalExecutedCycles))
+ {
+ result &= ~(TAPE_BIT); // reset is EAR ON
+ }
+ else
+ {
+ result |= (TAPE_BIT); // set is EAR Off
+ }
+ }
+ else if ((LastULAOutByte & 0x10) == 0)
+ {
+ result &= ~(0x40);
+ }
+ else
+ {
+ result |= 0x40;
+ }
+
+ }
+ else
+ {
+ // devices other than the ULA will respond here
+ // (e.g. the AY sound chip in a 128k spectrum
+
+ // AY register activate - on +3/2a both FFFD and BFFD active AY
+ if ((port & 0xc002) == 0xc000)
+ {
+ result = (int)AYDevice.PortRead();
+ }
+ else if ((port & 0xc002) == 0x8000)
+ {
+ result = (int)AYDevice.PortRead();
+ }
+
+ // Kempston Mouse
+
+ /*
+ else if ((port & 0xF002) == 0x2000) //Is bit 12 set and bits 13,14,15 and 1 reset?
+ {
+ //result = udpDrive.DiskStatusRead();
+
+ // disk drive is not yet implemented - return a max status byte for the menu to load
+ result = 255;
+ }
+ else if ((port & 0xF002) == 0x3000)
+ {
+ //result = udpDrive.DiskReadByte();
+ result = 0;
+ }
+
+ else if ((port & 0xF002) == 0x0)
+ {
+ if (PagingDisabled)
+ result = 0x1;
+ else
+ result = 0xff;
+ }
+ */
+
+ // if unused port the floating memory bus should be returned (still todo)
+ }
+
+ return (byte)result;
+ }
+
+ ///
+ /// Writes a byte of data to a specified port address
+ ///
+ ///
+ ///
+ 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
+ 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)
+ {
+ // store the last OUT byte
+ LastULAOutByte = value;
+
+ /*
+ 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);
+
+ ULADevice.borderColour = value & BORDER_BIT;
+
+ // Buzzer
+ BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
+
+ // Tape
+ //TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
+ }
+
+ else
+ {
+ // AY Register activation
+ if ((port & 0xc002) == 0xc000)
+ {
+ var reg = value & 0x0f;
+ AYDevice.SelectedRegister = reg;
+ CPU.TotalExecutedCycles += 3;
+ }
+ else
+ {
+ if ((port & 0xC002) == 0x8000)
+ {
+ AYDevice.PortWrite(value);
+ CPU.TotalExecutedCycles += 3;
+ }
+
+ /*
+
+ else
+ {
+ if ((port & 0xC002) == 0x4000) //Are bits 1 and 15 reset and bit 14 set?
+ {
+ // memory paging activate
+ if (PagingDisabled)
+ return;
+
+ // bit 5 handles paging disable (48k mode, persistent until next reboot)
+ if ((value & 0x20) != 0)
+ {
+ PagingDisabled = true;
+ }
+
+ // shadow screen
+ if ((value & 0x08) != 0)
+ {
+ SHADOWPaged = true;
+ }
+ else
+ {
+ SHADOWPaged = false;
+ }
+ }
+ else
+ {
+ //Extra Memory Paging feature activate
+ if ((port & 0xF002) == 0x1000) //Is bit 12 set and bits 13,14,15 and 1 reset?
+ {
+ if (PagingDisabled)
+ return;
+
+ // set disk motor state
+ //todo
+
+ if ((value & 0x08) != 0)
+ {
+ //diskDriveState |= (1 << 4);
+ }
+ else
+ {
+ //diskDriveState &= ~(1 << 4);
+ }
+
+ if ((value & 0x1) != 0)
+ {
+ // activate special paging mode
+ SpecialPagingMode = true;
+ PagingConfiguration = (value & 0x6 >> 1);
+ }
+ else
+ {
+ // normal paging mode
+ SpecialPagingMode = false;
+ }
+ }
+ else
+ {
+ // disk write port
+ if ((port & 0xF002) == 0x3000) //Is bit 12 set and bits 13,14,15 and 1 reset?
+ {
+ //udpDrive.DiskWriteByte((byte)(val & 0xff));
+ }
+ }
+ }
+ }
+ */
+ }
+ }
+
+ LastULAOutByte = value;
+
+
+
+
+ }
+
+ ///
+ /// +3 and 2a overidden method
+ ///
+ public override int _ROMpaged
+ {
+ get
+ {
+ // calculate the ROMpage from the high and low bits
+ var rp = ZXSpectrum.GetIntFromBitArray(new BitArray(new bool[] { ROMlow, ROMhigh }));
+
+ if (rp != 0)
+ {
+
+ }
+
+ return rp;
+ }
+ set { ROMPaged = value; }
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs
new file mode 100644
index 0000000000..35547ab931
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.ULA.cs
@@ -0,0 +1,196 @@
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ class ULAPlus2a : ULABase
+ {
+ #region Construction
+
+ public ULAPlus2a(SpectrumBase machine)
+ : base(machine)
+ {
+ InterruptPeriod = 36;
+ LongestOperationCycles = 64 + 2;
+ FrameLength = 70908;
+ ClockSpeed = 3546900;
+
+ contentionTable = new byte[70930];
+ floatingBusTable = new short[70930];
+ for (int f = 0; f < 70930; f++)
+ floatingBusTable[f] = -1;
+
+ CharRows = 24;
+ CharCols = 32;
+ ScreenWidth = 256;
+ ScreenHeight = 192;
+ BorderTopHeight = 48;
+ BorderBottomHeight = 56;
+ BorderLeftWidth = 48;
+ BorderRightWidth = 48;
+ DisplayStart = 16384;
+ DisplayLength = 6144;
+ AttributeStart = 22528;
+ AttributeLength = 768;
+ borderColour = 7;
+ ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
+
+ TstatesPerScanline = 228;
+ TstateAtTop = BorderTopHeight * TstatesPerScanline;
+ TstateAtBottom = BorderBottomHeight * TstatesPerScanline;
+ tstateToDisp = new short[FrameLength];
+
+ ScreenBuffer = new int[ScanLineWidth * BorderTopHeight //48 lines of border
+ + ScanLineWidth * ScreenHeight //border + main + border of 192 lines
+ + ScanLineWidth * BorderBottomHeight]; //56 lines of border
+
+ attr = new short[DisplayLength]; //6144 bytes of display memory will be mapped
+
+ SetupScreenSize();
+
+ Reset();
+ }
+
+ #endregion
+
+ #region Misc Operations
+
+ public override void Reset()
+ {
+ contentionStartPeriod = 14361; // + LateTiming;
+ contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
+ screen = _machine.Memory[9];
+ screenByteCtr = DisplayStart;
+ ULAByteCtr = 0;
+ actualULAStart = 14365 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
+ lastTState = actualULAStart;
+ BuildAttributeMap();
+ BuildContentionTable();
+ }
+
+ #endregion
+
+ #region Contention Methods
+
+ public override bool IsContended(int addr)
+ {
+ addr = addr & 0xc000;
+
+ if (addr == 0x4000)
+ {
+ // low port contention
+ return true;
+ }
+
+ if (addr == 0xc000)
+ {
+ // high port contention - check for contended bank paged in
+ switch (_machine.RAMPaged)
+ {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override void BuildContentionTable()
+ {
+ int t = contentionStartPeriod;
+ while (t < contentionEndPeriod)
+ {
+ contentionTable[t++] = 1;
+ contentionTable[t++] = 0;
+
+ //for 128 t-states
+ for (int i = 0; i < 128; i += 8)
+ {
+ contentionTable[t++] = 7;
+ contentionTable[t++] = 6;
+ contentionTable[t++] = 5;
+ contentionTable[t++] = 4;
+ contentionTable[t++] = 3;
+ contentionTable[t++] = 2;
+ contentionTable[t++] = 1;
+ contentionTable[t++] = 0;
+ }
+ t += (TstatesPerScanline - 128) - 2;
+ }
+
+ //build top half of tstateToDisp table
+ //vertical retrace period
+ for (t = 0; t < actualULAStart; t++)
+ tstateToDisp[t] = 0;
+
+ //next 48 are actual border
+ while (t < actualULAStart + (TstateAtTop))
+ {
+ for (int g = 0; g < 176; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 176; g < TstatesPerScanline; g++)
+ tstateToDisp[t++] = 0;
+ }
+
+ //build middle half
+ int _x = 0;
+ int _y = 0;
+ int scrval = 2;
+ while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline))
+ {
+ for (int g = 0; g < 24; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 24; g < 24 + 128; g++)
+ {
+ //Map screenaddr to tstate
+ if (g % 4 == 0)
+ {
+ scrval = (((((_y & 0xc0) >> 3) | (_y & 0x07) | (0x40)) << 8)) | (((_x >> 3) & 0x1f) | ((_y & 0x38) << 2));
+ _x += 8;
+ }
+ tstateToDisp[t++] = (short)scrval;
+ }
+
+ _y++;
+
+ for (int g = 24 + 128; g < 24 + 128 + 24; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 24 + 128 + 24; g < 24 + 128 + 24 + 52; g++)
+ tstateToDisp[t++] = 0;
+ }
+
+ int h = contentionStartPeriod + 3;
+ while (h < contentionEndPeriod + 3)
+ {
+ for (int j = 0; j < 128; j += 8)
+ {
+ floatingBusTable[h] = tstateToDisp[h + 2];
+ floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)];
+ floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4];
+ floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)];
+ h += 8;
+ }
+ h += TstatesPerScanline - 128;
+ }
+
+ //build bottom half
+ while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
+ {
+ for (int g = 0; g < 176; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 176; g < TstatesPerScanline; g++)
+ tstateToDisp[t++] = 0;
+ }
+ }
+
+
+ #endregion
+
+
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs
new file mode 100644
index 0000000000..5cdfb1bbbf
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.cs
@@ -0,0 +1,52 @@
+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 partial class ZX128Plus2a : SpectrumBase
+ {
+ #region Construction
+
+ ///
+ /// Main constructor
+ ///
+ ///
+ ///
+ public ZX128Plus2a(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List files, List joysticks)
+ {
+ Spectrum = spectrum;
+ CPU = cpu;
+
+ ROMPaged = 0;
+ SHADOWPaged = false;
+ RAMPaged = 0;
+ PagingDisabled = false;
+
+ // init addressable memory from ROM and RAM banks
+ ReInitMemory();
+
+ ULADevice = new ULAPlus2a(this);
+
+ BuzzerDevice = new Buzzer(this);
+ BuzzerDevice.Init(44100, ULADevice.FrameLength);
+
+ AYDevice = new AY38912();
+ AYDevice.Init(44100, ULADevice.FrameLength);
+
+ KeyboardDevice = new StandardKeyboard(this);
+
+ InitJoysticks(joysticks);
+
+ TapeDevice = new DatacorderDevice();
+ TapeDevice.Init(this);
+
+ InitializeMedia(files);
+ }
+
+ #endregion
+ }
+}
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 15a091fccd..188581fd72 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Memory.cs
@@ -136,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
result = Memory[_ROMpaged][addr % 0x4000];
break;
- // RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7)
+ // RAM 0x4000 (RAM5 - Bank5 always)
case 1:
result = Memory[9][addr % 0x4000];
break;
@@ -261,10 +261,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
// ROM 0x000
case 0:
- Memory[ROMPaged][addr % 0x4000] = value;
+ Memory[_ROMpaged][addr % 0x4000] = value;
break;
- // RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7)
+ // RAM 0x4000 (RAM5 - Bank5 only)
case 1:
Memory[9][addr % 0x4000] = value;
break;
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 199dda6515..ea53156118 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
@@ -132,10 +132,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
else if ((port & 0xF002) == 0x2000) //Is bit 12 set and bits 13,14,15 and 1 reset?
{
//result = udpDrive.DiskStatusRead();
+
+ // disk drive is not yet implemented - return a max status byte for the menu to load
+ result = 255;
}
else if ((port & 0xF002) == 0x3000)
{
//result = udpDrive.DiskReadByte();
+ result = 0;
}
else if ((port & 0xF002) == 0x0)
@@ -194,7 +198,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
if (!PagingDisabled)
{
- if (bits[0])
+ if (!bits[0])
{
// special paging is not enabled - get the ROMpage high byte
ROMhigh = bits[2];
@@ -428,7 +432,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
get
{
// calculate the ROMpage from the high and low bits
- return ZXSpectrum.GetIntFromBitArray(new BitArray(new bool[] { ROMlow, ROMhigh }));
+ var rp = ZXSpectrum.GetIntFromBitArray(new BitArray(new bool[] { ROMlow, ROMhigh }));
+
+ if (rp != 0)
+ {
+
+ }
+
+ return rp;
}
set { ROMPaged = value; }
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs
new file mode 100644
index 0000000000..e6d82474dc
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.ULA.cs
@@ -0,0 +1,196 @@
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ class ULAPlus3 : ULABase
+ {
+ #region Construction
+
+ public ULAPlus3(SpectrumBase machine)
+ : base(machine)
+ {
+ InterruptPeriod = 36;
+ LongestOperationCycles = 64 + 2;
+ FrameLength = 70908;
+ ClockSpeed = 3546900;
+
+ contentionTable = new byte[70930];
+ floatingBusTable = new short[70930];
+ for (int f = 0; f < 70930; f++)
+ floatingBusTable[f] = -1;
+
+ CharRows = 24;
+ CharCols = 32;
+ ScreenWidth = 256;
+ ScreenHeight = 192;
+ BorderTopHeight = 48;
+ BorderBottomHeight = 56;
+ BorderLeftWidth = 48;
+ BorderRightWidth = 48;
+ DisplayStart = 16384;
+ DisplayLength = 6144;
+ AttributeStart = 22528;
+ AttributeLength = 768;
+ borderColour = 7;
+ ScanLineWidth = BorderLeftWidth + ScreenWidth + BorderRightWidth;
+
+ TstatesPerScanline = 228;
+ TstateAtTop = BorderTopHeight * TstatesPerScanline;
+ TstateAtBottom = BorderBottomHeight * TstatesPerScanline;
+ tstateToDisp = new short[FrameLength];
+
+ ScreenBuffer = new int[ScanLineWidth * BorderTopHeight //48 lines of border
+ + ScanLineWidth * ScreenHeight //border + main + border of 192 lines
+ + ScanLineWidth * BorderBottomHeight]; //56 lines of border
+
+ attr = new short[DisplayLength]; //6144 bytes of display memory will be mapped
+
+ SetupScreenSize();
+
+ Reset();
+ }
+
+ #endregion
+
+ #region Misc Operations
+
+ public override void Reset()
+ {
+ contentionStartPeriod = 14361; // + LateTiming;
+ contentionEndPeriod = contentionStartPeriod + (ScreenHeight * TstatesPerScanline);
+ screen = _machine.Memory[9];
+ screenByteCtr = DisplayStart;
+ ULAByteCtr = 0;
+ actualULAStart = 14365 - 24 - (TstatesPerScanline * BorderTopHeight);// + LateTiming;
+ lastTState = actualULAStart;
+ BuildAttributeMap();
+ BuildContentionTable();
+ }
+
+ #endregion
+
+ #region Contention Methods
+
+ public override bool IsContended(int addr)
+ {
+ addr = addr & 0xc000;
+
+ if (addr == 0x4000)
+ {
+ // low port contention
+ return true;
+ }
+
+ if (addr == 0xc000)
+ {
+ // high port contention - check for contended bank paged in
+ switch (_machine.RAMPaged)
+ {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override void BuildContentionTable()
+ {
+ int t = contentionStartPeriod;
+ while (t < contentionEndPeriod)
+ {
+ contentionTable[t++] = 1;
+ contentionTable[t++] = 0;
+
+ //for 128 t-states
+ for (int i = 0; i < 128; i += 8)
+ {
+ contentionTable[t++] = 7;
+ contentionTable[t++] = 6;
+ contentionTable[t++] = 5;
+ contentionTable[t++] = 4;
+ contentionTable[t++] = 3;
+ contentionTable[t++] = 2;
+ contentionTable[t++] = 1;
+ contentionTable[t++] = 0;
+ }
+ t += (TstatesPerScanline - 128) - 2;
+ }
+
+ //build top half of tstateToDisp table
+ //vertical retrace period
+ for (t = 0; t < actualULAStart; t++)
+ tstateToDisp[t] = 0;
+
+ //next 48 are actual border
+ while (t < actualULAStart + (TstateAtTop))
+ {
+ for (int g = 0; g < 176; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 176; g < TstatesPerScanline; g++)
+ tstateToDisp[t++] = 0;
+ }
+
+ //build middle half
+ int _x = 0;
+ int _y = 0;
+ int scrval = 2;
+ while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline))
+ {
+ for (int g = 0; g < 24; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 24; g < 24 + 128; g++)
+ {
+ //Map screenaddr to tstate
+ if (g % 4 == 0)
+ {
+ scrval = (((((_y & 0xc0) >> 3) | (_y & 0x07) | (0x40)) << 8)) | (((_x >> 3) & 0x1f) | ((_y & 0x38) << 2));
+ _x += 8;
+ }
+ tstateToDisp[t++] = (short)scrval;
+ }
+
+ _y++;
+
+ for (int g = 24 + 128; g < 24 + 128 + 24; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 24 + 128 + 24; g < 24 + 128 + 24 + 52; g++)
+ tstateToDisp[t++] = 0;
+ }
+
+ int h = contentionStartPeriod + 3;
+ while (h < contentionEndPeriod + 3)
+ {
+ for (int j = 0; j < 128; j += 8)
+ {
+ floatingBusTable[h] = tstateToDisp[h + 2];
+ floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)];
+ floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4];
+ floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)];
+ h += 8;
+ }
+ h += TstatesPerScanline - 128;
+ }
+
+ //build bottom half
+ while (t < actualULAStart + (TstateAtTop) + (ScreenHeight * TstatesPerScanline) + (TstateAtBottom))
+ {
+ for (int g = 0; g < 176; g++)
+ tstateToDisp[t++] = 1;
+
+ for (int g = 176; g < TstatesPerScanline; g++)
+ tstateToDisp[t++] = 0;
+ }
+ }
+
+
+ #endregion
+
+
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs
index 9fb6b4db95..4be628ba75 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.cs
@@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// init addressable memory from ROM and RAM banks
ReInitMemory();
- ULADevice = new ULA128(this);
+ ULADevice = new ULAPlus3(this);
BuzzerDevice = new Buzzer(this);
BuzzerDevice.Init(44100, ULADevice.FrameLength);
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs
index 61c22499ea..4c70608d7a 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.ULA.cs
@@ -151,10 +151,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
for (int j = 0; j < 128; j += 8)
{
- floatingBusTable[h] = tstateToDisp[h + 2]; //screen address
- floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)]; //attr address
- floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4]; //screen address + 1
- floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)]; //attr address + 1
+ floatingBusTable[h] = tstateToDisp[h + 2]; //screen address
+ floatingBusTable[h + 1] = attr[(tstateToDisp[h + 2] - 16384)]; //attr address
+ floatingBusTable[h + 2] = tstateToDisp[h + 2 + 4]; //screen address + 1
+ floatingBusTable[h + 3] = attr[(tstateToDisp[h + 2 + 4] - 16384)]; //attr address + 1
h += 8;
}
h += TstatesPerScanline - 128;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
index b07dfd6b9e..6381049957 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
@@ -70,6 +70,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
ControllerDefinition = ZXSpectrumControllerDefinition;
Init(MachineType.ZXSpectrum128Plus2, SyncSettings.BorderType, SyncSettings.TapeLoadSpeed, _files, joysticks);
break;
+ case MachineType.ZXSpectrum128Plus2a:
+ ControllerDefinition = ZXSpectrumControllerDefinition;
+ Init(MachineType.ZXSpectrum128Plus2a, SyncSettings.BorderType, SyncSettings.TapeLoadSpeed, _files, joysticks);
+ break;
case MachineType.ZXSpectrum128Plus3:
ControllerDefinition = ZXSpectrumControllerDefinition;
Init(MachineType.ZXSpectrum128Plus3, SyncSettings.BorderType, SyncSettings.TapeLoadSpeed, _files, joysticks);
@@ -158,8 +162,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
case "PLUS2ROM":
embeddedRom = Util.DecompressGzipFile(new MemoryStream(Resources.ZX_plus2_rom));
break;
+ case "PLUS2AROM":
+ embeddedRom = Util.DecompressGzipFile(new MemoryStream(Resources.ZX_plus2a_rom));
+ break;
case "PLUS3ROM":
- embeddedRom = Util.DecompressGzipFile(new MemoryStream(Resources.ZX_plus3_rom));
+ byte[] r0 = Util.DecompressGzipFile(new MemoryStream(Resources.Spectrum3_V4_0_ROM0_bin));
+ byte[] r1 = Util.DecompressGzipFile(new MemoryStream(Resources.Spectrum3_V4_0_ROM1_bin));
+ byte[] r2 = Util.DecompressGzipFile(new MemoryStream(Resources.Spectrum3_V4_0_ROM2_bin));
+ byte[] r3 = Util.DecompressGzipFile(new MemoryStream(Resources.Spectrum3_V4_0_ROM3_bin));
+ embeddedRom = r0.Concat(r1).Concat(r2).Concat(r3).ToArray();
break;
default:
embeddedFound = false;
@@ -209,6 +220,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
var romDataP2 = RomData.InitROM(machineType, _systemRomP2);
_machine.InitROM(romDataP2);
break;
+ case MachineType.ZXSpectrum128Plus2a:
+ _machine = new ZX128Plus2a(this, _cpu, borderType, files, joys);
+ var _systemRomP4 = GetFirmware(0x10000, "PLUS2AROM");
+ var romDataP4 = RomData.InitROM(machineType, _systemRomP4);
+ _machine.InitROM(romDataP4);
+ break;
case MachineType.ZXSpectrum128Plus3:
_machine = new ZX128Plus3(this, _cpu, borderType, files, joys);
var _systemRomP3 = GetFirmware(0x10000, "PLUS3ROM");
diff --git a/BizHawk.Emulation.Cores/Properties/Resources.Designer.cs b/BizHawk.Emulation.Cores/Properties/Resources.Designer.cs
index 312ea05d92..73259a9985 100644
--- a/BizHawk.Emulation.Cores/Properties/Resources.Designer.cs
+++ b/BizHawk.Emulation.Cores/Properties/Resources.Designer.cs
@@ -90,6 +90,46 @@ namespace BizHawk.Emulation.Cores.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Spectrum3_V4_0_ROM0_bin {
+ get {
+ object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM0_bin", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Spectrum3_V4_0_ROM1_bin {
+ get {
+ object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM1_bin", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Spectrum3_V4_0_ROM2_bin {
+ get {
+ object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM2_bin", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Spectrum3_V4_0_ROM3_bin {
+ get {
+ object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM3_bin", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
@@ -123,9 +163,9 @@ namespace BizHawk.Emulation.Cores.Properties {
///
/// Looks up a localized resource of type System.Byte[].
///
- internal static byte[] ZX_plus3_rom {
+ internal static byte[] ZX_plus2a_rom {
get {
- object obj = ResourceManager.GetObject("ZX_plus3_rom", resourceCulture);
+ object obj = ResourceManager.GetObject("ZX_plus2a_rom", resourceCulture);
return ((byte[])(obj));
}
}
diff --git a/BizHawk.Emulation.Cores/Properties/Resources.resx b/BizHawk.Emulation.Cores/Properties/Resources.resx
index 4699ab819d..b5e12deeae 100644
--- a/BizHawk.Emulation.Cores/Properties/Resources.resx
+++ b/BizHawk.Emulation.Cores/Properties/Resources.resx
@@ -127,16 +127,28 @@
..\Resources\sgb-cart-present.spc.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\resources\spectrum3_v4-0_rom0.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\resources\spectrum3_v4-0_rom1.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\resources\spectrum3_v4-0_rom2.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\resources\spectrum3_v4-0_rom3.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
..\Resources\128.ROM.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
..\Resources\48.ROM.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\resources\plus2a.rom.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
..\Resources\plus2.rom.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- ..\Resources\plus3.rom.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
\ No newline at end of file
diff --git a/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM0.bin.gz b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM0.bin.gz
new file mode 100644
index 0000000000..d70d805d62
Binary files /dev/null and b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM0.bin.gz differ
diff --git a/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM1.bin.gz b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM1.bin.gz
new file mode 100644
index 0000000000..f813586462
Binary files /dev/null and b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM1.bin.gz differ
diff --git a/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM2.bin.gz b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM2.bin.gz
new file mode 100644
index 0000000000..df586562a5
Binary files /dev/null and b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM2.bin.gz differ
diff --git a/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM3.bin.gz b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM3.bin.gz
new file mode 100644
index 0000000000..3062bc7fb1
Binary files /dev/null and b/BizHawk.Emulation.Cores/Resources/Spectrum3_V4-0_ROM3.bin.gz differ
diff --git a/BizHawk.Emulation.Cores/Resources/plus3.rom.gz b/BizHawk.Emulation.Cores/Resources/plus2a.rom.gz
similarity index 100%
rename from BizHawk.Emulation.Cores/Resources/plus3.rom.gz
rename to BizHawk.Emulation.Cores/Resources/plus2a.rom.gz