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