template for plus3 (but not implemented yet)

This commit is contained in:
Asnivor 2017-12-05 10:38:51 +00:00
parent 27ba7e0008
commit 85d38a3379
5 changed files with 532 additions and 0 deletions

View File

@ -54,6 +54,7 @@ namespace BizHawk.Emulation.Common
FirmwareAndOption("5EA7C2B824672E914525D1D5C419D71B84A426A2", 16384, "ZXSpectrum", "48ROM", "48.ROM", "Spectrum 48K ROM");
FirmwareAndOption("16375D42EA109B47EDDED7A16028DE7FDB3013A1", 32768, "ZXSpectrum", "128ROM", "128.ROM", "Spectrum 128K ROM");
FirmwareAndOption("8CAFB292AF58617907B9E6B9093D3588A75849B8", 32768, "ZXSpectrum", "PLUS2ROM", "PLUS2.ROM", "Spectrum 128K +2 ROM");
FirmwareAndOption("929BF1A5E5687EBD8D7245F9B513A596C0EC21A4", 65563, "ZXSpectrum", "PLUS3ROM", "PLUS3.ROM", "Spectrum 128K +3 ROM");
// for saturn, we think any bios region can pretty much run any iso
// so, we're going to lay this out carefully so that we choose things in a sensible order, but prefer the correct region

View File

@ -277,6 +277,9 @@
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Memory.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\SpectrumBase.Sound.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2\ZX128Plus2.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.Memory.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.Port.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.Memory.cs" />
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.Port.cs" />

View File

@ -0,0 +1,284 @@
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 ZX128Plus3 : SpectrumBase
{
/* 128k paging controlled by writes to port 0x7ffd
*
*
#7FFD (32765) - decoded as A15=0, A1=0 and /IORQ=0. Bits 0..5 are latched. Bits 0..2 select RAM bank in secton D. Bit 3 selects RAM bank to dispay screen (0 - RAM5, 1 - RAM7). Bit 4 selects ROM bank (0 - ROM0, 1 - ROM1). Bit 5, when set locks future writing to #7FFD port until reset. Reading #7FFD port is the same as writing #FF into it.
#BFFD (49149) - write data byte into AY-3-8912 chip.
#FFFD (65533) - select AY-3-8912 addres (D4..D7 ignored) and reading data byte.
* 0xffff +--------+--------+--------+--------+--------+--------+--------+--------+
| Bank 0 | Bank 1 | Bank 2 | Bank 3 | Bank 4 | Bank 5 | Bank 6 | Bank 7 |
| | |(also at| | |(also at| | |
| | | 0x8000)| | | 0x4000)| | |
| | | | | | screen | | screen |
0xc000 +--------+--------+--------+--------+--------+--------+--------+--------+
| Bank 2 | Any one of these pages may be switched in.
| |
| |
| |
0x8000 +--------+
| Bank 5 |
| |
| |
| screen |
0x4000 +--------+--------+
| ROM 0 | ROM 1 | Either ROM may be switched in.
| | |
| | |
| | |
0x0000 +--------+--------+
*/
/// <summary>
/// Simulates reading from the bus (no contention)
/// Paging should be handled here
/// </summary>
/// <param name="addr"></param>
/// <returns></returns>
public override byte ReadBus(ushort addr)
{
int divisor = addr / 0x4000;
byte result = 0xff;
switch (divisor)
{
// ROM 0x000
case 0:
if (!ROMPaged)
result = Memory[0][addr % 0x4000];
else
result = Memory[1][addr % 0x4000];
break;
// RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7)
case 1:
result = Memory[7][addr % 0x4000];
break;
// RAM 0x8000 (RAM2 - Bank2)
case 2:
result = Memory[4][addr % 0x4000];
break;
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
case 3:
switch (RAMPaged)
{
case 0:
result = Memory[2][addr % 0x4000];
break;
case 1:
result = Memory[3][addr % 0x4000];
break;
case 2:
result = Memory[4][addr % 0x4000];
break;
case 3:
result = Memory[5][addr % 0x4000];
break;
case 4:
result = Memory[6][addr % 0x4000];
break;
case 5:
result = Memory[7][addr % 0x4000];
break;
case 6:
result = Memory[8][addr % 0x4000];
break;
case 7:
result = Memory[9][addr % 0x4000];
break;
}
break;
default:
break;
}
return result;
}
/// <summary>
/// Simulates writing to the bus (no contention)
/// Paging should be handled here
/// </summary>
/// <param name="addr"></param>
/// <param name="value"></param>
public override void WriteBus(ushort addr, byte value)
{
int divisor = addr / 0x4000;
switch (divisor)
{
// ROM 0x000
case 0:
if (!ROMPaged)
Memory[0][addr % 0x4000] = value;
else
Memory[1][addr % 0x4000] = value;
break;
// RAM 0x4000 (RAM5 - Bank5 or shadow bank RAM7)
case 1:
Memory[7][addr % 0x4000] = value;
break;
// RAM 0x8000 (RAM2 - Bank2)
case 2:
Memory[4][addr % 0x4000] = value;
break;
// RAM 0xc000 (any ram bank 0 - 7 may be paged in - default bank0)
case 3:
switch (RAMPaged)
{
case 0:
Memory[2][addr % 0x4000] = value;
break;
case 1:
Memory[3][addr % 0x4000] = value;
break;
case 2:
Memory[4][addr % 0x4000] = value;
break;
case 3:
Memory[5][addr % 0x4000] = value;
break;
case 4:
Memory[6][addr % 0x4000] = value;
break;
case 5:
Memory[7][addr % 0x4000] = value;
break;
case 6:
Memory[8][addr % 0x4000] = value;
break;
case 7:
Memory[9][addr % 0x4000] = value;
break;
}
break;
default:
break;
}
}
/// <summary>
/// Reads a byte of data from a specified memory address
/// (with memory contention if appropriate)
/// </summary>
/// <param name="addr"></param>
/// <returns></returns>
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
var delay = GetContentionValue(CurrentFrameCycle);
CPU.TotalExecutedCycles += delay;
}
return data;
}
/// <summary>
/// Writes a byte of data to a specified memory address
/// (with memory contention if appropriate)
/// </summary>
/// <param name="addr"></param>
/// <param name="value"></param>
public override void WriteMemory(ushort addr, byte value)
{
if (addr < 0x4000)
{
// Do nothing - we cannot write to ROM
return;
}
else if (addr < 0xC000)
{
// 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] = ROM1;
else
Memory.Add(1, ROM1);
if (Memory.ContainsKey(2))
Memory[2] = RAM0;
else
Memory.Add(2, RAM0);
if (Memory.ContainsKey(3))
Memory[3] = RAM1;
else
Memory.Add(3, RAM1);
if (Memory.ContainsKey(4))
Memory[4] = RAM2;
else
Memory.Add(4, RAM2);
if (Memory.ContainsKey(5))
Memory[5] = RAM3;
else
Memory.Add(5, RAM3);
if (Memory.ContainsKey(6))
Memory[6] = RAM4;
else
Memory.Add(6, RAM4);
if (Memory.ContainsKey(7))
Memory[7] = RAM5;
else
Memory.Add(7, RAM5);
if (Memory.ContainsKey(8))
Memory[8] = RAM6;
else
Memory.Add(8, RAM6);
if (Memory.ContainsKey(9))
Memory[9] = RAM7;
else
Memory.Add(9, RAM7);
}
/// <summary>
/// Sets up the ROM
/// </summary>
/// <param name="buffer"></param>
/// <param name="startAddress"></param>
public override void InitROM(RomData romData)
{
RomData = romData;
// 128k uses ROM0 and ROM1
// 128k loader is in ROM0, and fallback 48k rom is in ROM1
for (int i = 0; i < 0x4000; i++)
{
ROM0[i] = RomData.RomBytes[i];
ROM1[i] = RomData.RomBytes[i + 0x4000];
}
}
}
}

View File

@ -0,0 +1,188 @@
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 ZX128Plus3 : SpectrumBase
{
/// <summary>
/// Reads a byte of data from a specified port address
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public override byte ReadPort(ushort port)
{
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;
ContendPort((ushort)port);
// Kempston Joystick
if ((port & 0xe0) == 0 || (port & 0x20) == 0)
{
return (byte)KempstonDevice.JoyLine;
}
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.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 (KeyboardDevice.IsIssue2Keyboard)
{
if ((LastULAOutByte & (EAR_BIT + MIC_BIT)) == 0)
{
result &= ~(TAPE_BIT);
}
else
{
result |= TAPE_BIT;
}
}
else
{
if ((LastULAOutByte & EAR_BIT) == 0)
{
result &= ~(TAPE_BIT);
}
else
{
result |= TAPE_BIT;
}
}
}
}
else
{
// devices other than the ULA will respond here
// (e.g. the AY sound chip in a 128k spectrum
// AY register activate
// Kemptson Mouse
// if unused port the floating memory bus should be returned (still todo)
}
return (byte)result;
}
/// <summary>
/// Writes a byte of data to a specified port address
/// </summary>
/// <param name="port"></param>
/// <param name="value"></param>
public override void WritePort(ushort port, byte value)
{
// paging
if (port == 0x7ffd)
{
// 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 = true;
}
else
{
ROMPaged = false;
}
// Bit 5 signifies that paging is disabled until next reboot
if ((value & 0x20) != 0)
PagingDisabled = true;
return;
}
// Check whether the low bit is reset
// Technically the ULA should respond to every even I/O address
bool lowBitReset = (port & 0x01) == 0;
ContendPort(port);
// 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
BorderColour = value & BORDER_BIT;
// Buzzer
BuzzerDevice.ProcessPulseValue(false, (value & EAR_BIT) != 0);
// Tape
TapeDevice.ProcessMicBit((value & MIC_BIT) != 0);
}
}
}
}

View File

@ -0,0 +1,56 @@
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 ZX128Plus3 : SpectrumBase
{
#region Construction
/// <summary>
/// Main constructor
/// </summary>
/// <param name="spectrum"></param>
/// <param name="cpu"></param>
public ZX128Plus3(ZXSpectrum spectrum, Z80A cpu, byte[] file)
{
Spectrum = spectrum;
CPU = cpu;
ROMPaged = false;
SHADOWPaged = false;
RAMPaged = 0;
PagingDisabled = false;
// init addressable memory from ROM and RAM banks
ReInitMemory();
//RAM = new byte[0x4000 + 0xC000];
//DisplayLineTime = 132;
VsyncNumerator = 3546900;
InitScreenConfig();
InitScreen();
ResetULACycle();
BuzzerDevice = new Buzzer(this);
BuzzerDevice.Init(44100, UlaFrameCycleCount);
KeyboardDevice = new Keyboard48(this);
KempstonDevice = new KempstonJoystick(this);
TapeProvider = new DefaultTapeProvider(file);
TapeDevice = new Tape(TapeProvider);
TapeDevice.Init(this);
}
#endregion
}
}