diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 70231ad7e7..244c3ae233 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -271,6 +271,7 @@
+
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs
index cb895cf171..478b821a1a 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/MachineType.cs
@@ -8,6 +8,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
public enum MachineType
{
+ ///
+ /// Original Sinclair Spectrum 16K model
+ ///
+ ZXSpectrum16,
+
///
/// Sinclair Spectrum 48K model
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs
new file mode 100644
index 0000000000..d810cf7255
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs
@@ -0,0 +1,169 @@
+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 ZX16 : ZX48
+ {
+ #region Construction
+
+ ///
+ /// Main constructor
+ ///
+ ///
+ ///
+ public ZX16(ZXSpectrum spectrum, Z80A cpu, byte[] file)
+ : base(spectrum, cpu, file)
+ {
+
+ }
+
+ #endregion
+
+
+ #region Memory
+
+ /* 48K Spectrum has NO memory paging
+ *
+ *
+ | Bank 0 |
+ | |
+ | |
+ | screen |
+ 0x4000 +--------+
+ | ROM 0 |
+ | |
+ | |
+ | |
+ 0x0000 +--------+
+ */
+
+ ///
+ /// Simulates reading from the bus (no contention)
+ /// Paging should be handled here
+ ///
+ ///
+ ///
+ public override byte ReadBus(ushort addr)
+ {
+ int divisor = addr / 0x4000;
+ // paging logic goes here
+
+ if (divisor > 1)
+ {
+ // memory does not exist
+ return 0xff;
+ }
+
+ var bank = Memory[divisor];
+ var index = addr % 0x4000;
+ return bank[index];
+ }
+
+ ///
+ /// Simulates writing to the bus (no contention)
+ /// Paging should be handled here
+ ///
+ ///
+ ///
+ public override void WriteBus(ushort addr, byte value)
+ {
+ int divisor = addr / 0x4000;
+ // paging logic goes here
+
+ if (divisor > 1)
+ {
+ // memory does not exist
+ return;
+ }
+
+ var bank = Memory[divisor];
+ var index = addr % 0x4000;
+ bank[index] = value;
+ }
+
+ ///
+ /// Reads a byte of data from a specified memory address
+ /// (with memory contention if appropriate)
+ ///
+ ///
+ ///
+ public override byte ReadMemory(ushort addr)
+ {
+ var data = ReadBus(addr);
+ if ((addr & 0xC000) == 0x4000)
+ {
+ // addr is in RAM not ROM - apply memory contention if neccessary
+ if (addr >= 0x8000)
+ {
+ data = 0xFF;
+ }
+ else
+ {
+ var delay = GetContentionValue(CurrentFrameCycle);
+ CPU.TotalExecutedCycles += delay;
+ }
+ }
+ 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)
+ {
+ if (addr < 0x4000)
+ {
+ // Do nothing - we cannot write to ROM
+ return;
+ }
+ else if (addr >= 0x8000)
+ {
+ // memory does not exist
+ return;
+ }
+ else if (addr < 0x8000)
+ {
+ // possible contended RAM
+ var delay = GetContentionValue(CurrentFrameCycle);
+ CPU.TotalExecutedCycles += delay;
+ }
+
+ 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] = RAM1;
+ else
+ Memory.Add(1, RAM1);
+ }
+
+ ///
+ /// Sets up the ROM
+ ///
+ ///
+ ///
+ public override void InitROM(RomData romData)
+ {
+ RomData = romData;
+ // for 16/48k machines only ROM0 is used (no paging)
+ RomData.RomBytes?.CopyTo(ROM0, 0);
+ }
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
index ac08f1bd3a..036247f341 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
@@ -36,6 +36,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
switch (SyncSettings.MachineType)
{
+ case MachineType.ZXSpectrum16:
+ ControllerDefinition = ZXSpectrumControllerDefinition;
+ Init(MachineType.ZXSpectrum16, SyncSettings.BorderType, SyncSettings.TapeLoadSpeed, _file);
+ break;
case MachineType.ZXSpectrum48:
ControllerDefinition = ZXSpectrumControllerDefinition;
Init(MachineType.ZXSpectrum48, SyncSettings.BorderType, SyncSettings.TapeLoadSpeed, _file);
@@ -132,6 +136,12 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// setup the emulated model based on the MachineType
switch (machineType)
{
+ case MachineType.ZXSpectrum16:
+ _machine = new ZX16(this, _cpu, file);
+ var _systemRom16 = GetFirmware(0x4000, "48ROM");
+ var romData16 = RomData.InitROM(machineType, _systemRom16);
+ _machine.InitROM(romData16);
+ break;
case MachineType.ZXSpectrum48:
_machine = new ZX48(this, _cpu, file);
var _systemRom = GetFirmware(0x4000, "48ROM");