Added floating bus implementation to 128k/+2 and started looking at +3 emulation

This commit is contained in:
Asnivor 2018-03-08 16:50:56 +00:00
parent 74423041f3
commit f121aedd6a
8 changed files with 325 additions and 62 deletions

View File

@ -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>

View File

@ -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

View File

@ -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];
}
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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; }
}
}
}

View File

@ -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];
}
}
}

View File

@ -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;
}
}