Implemented +2a and +3 is now working (although disk drive not yet implemented so it just shows as +2a)
This commit is contained in:
parent
cf8b632381
commit
e6d43fa5d2
|
@ -268,6 +268,11 @@
|
|||
<Compile Include="Computers\SinclairSpectrum\Hardware\Input\KempstonJoystick.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Hardware\SoundOuput\IBeeperDevice.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ULABase.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.Memory.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.Port.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus2a\ZX128Plus2a.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128KPlus3\ZX128Plus3.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum128K\ZX128.ULA.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum16K\ZX16.cs" />
|
||||
<Compile Include="Computers\SinclairSpectrum\Machine\ZXSpectrum48K\ZX48.ULA.cs" />
|
||||
|
@ -1397,8 +1402,12 @@
|
|||
<None Include="Resources\cgb_boot.bin.gz" />
|
||||
<None Include="Resources\dmg_boot.bin.gz" />
|
||||
<None Include="Resources\plus2.rom.gz" />
|
||||
<None Include="Resources\plus3.rom.gz" />
|
||||
<None Include="Resources\plus2a.rom.gz" />
|
||||
<None Include="Resources\sgb-cart-present.spc.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM0.bin.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM1.bin.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM2.bin.gz" />
|
||||
<None Include="Resources\Spectrum3_V4-0_ROM3.bin.gz" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
|
|
|
@ -28,6 +28,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
/// </summary>
|
||||
ZXSpectrum128Plus2,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 128 +2a model (same as the +3 just without disk drive)
|
||||
/// </summary>
|
||||
ZXSpectrum128Plus2a,
|
||||
|
||||
/// <summary>
|
||||
/// Sinclair Spectrum 128 +3 model
|
||||
/// </summary>
|
||||
|
|
|
@ -183,11 +183,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
|
|||
{
|
||||
if (AYDevice != null)
|
||||
AYDevice.UpdateSound(CurrentFrameCycle);
|
||||
}
|
||||
|
||||
if (SHADOWPaged)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/// <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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
if (ULADevice.IsContended(addr))
|
||||
CPU.TotalExecutedCycles += ULADevice.contentionTable[CurrentFrameCycle];
|
||||
|
||||
var data = ReadBus(addr);
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ULA reads the memory at the specified address
|
||||
/// (No memory contention)
|
||||
/// Will read RAM5 (screen0) by default, unless RAM7 (screen1) is selected as output
|
||||
/// </summary>
|
||||
/// <param name="addr"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the ROM
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="startAddress"></param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads a byte of data from a specified port address
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// 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;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// +3 and 2a overidden method
|
||||
/// </summary>
|
||||
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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Main constructor
|
||||
/// </summary>
|
||||
/// <param name="spectrum"></param>
|
||||
/// <param name="cpu"></param>
|
||||
public ZX128Plus2a(ZXSpectrum spectrum, Z80A cpu, ZXSpectrum.BorderType borderType, List<byte[]> files, List<JoystickType> 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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -90,6 +90,46 @@ namespace BizHawk.Emulation.Cores.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Spectrum3_V4_0_ROM0_bin {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM0_bin", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Spectrum3_V4_0_ROM1_bin {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM1_bin", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Spectrum3_V4_0_ROM2_bin {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM2_bin", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Spectrum3_V4_0_ROM3_bin {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Spectrum3_V4_0_ROM3_bin", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
|
@ -123,9 +163,9 @@ namespace BizHawk.Emulation.Cores.Properties {
|
|||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,16 +127,28 @@
|
|||
<data name="SgbCartPresent_SPC" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\sgb-cart-present.spc.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Spectrum3_V4_0_ROM0_bin" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\spectrum3_v4-0_rom0.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Spectrum3_V4_0_ROM1_bin" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\spectrum3_v4-0_rom1.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Spectrum3_V4_0_ROM2_bin" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\spectrum3_v4-0_rom2.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Spectrum3_V4_0_ROM3_bin" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\spectrum3_v4-0_rom3.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ZX_128_ROM" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\128.ROM.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ZX_48_ROM" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\48.ROM.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ZX_plus2a_rom" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\plus2a.rom.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ZX_plus2_rom" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\plus2.rom.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ZX_plus3_rom" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\plus3.rom.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue